2

It's kind of hard to word my question so I'll just give a code example:

#include <stdio.h>

typedef struct {
    char *str;
} strHold;

void f2(char *s)
{
    *s = "Char 2";
}

void f3(strHold *str)
{
    (*str).str = "Struct 2";
}

int main()
{
    char *s1 = "Char 1";
    strHold str1;
    str1.str = "Struct 1";

    //f2(s1);
    f3(&str1);

    printf("%s, ", s1);
    printf("%s", str1.str);

    return 0;
}

this C program runs, and even displays "Struct 2" on the second print. However function f2 doesn't work, as in, if I remove the comment, the program crashes. I'm actually not surprised that f2 doesn't work, I'm more wondering why does f3 work?

When I define a string constant inside a function's scope, that data should be freed once I exit the scope of the function, right? Which means that data would turn into garbage once I return into the calling function scope.

So... how comes the structure version works? Can somebody explain how memory works in both of those situations, and what's the "correct" way to initialize strings of an unknown length in a calling function from a function that it calls?

2
  • You should be getting lots of warnings from this program when building, read them, try to understand what they mean, and fix the root cause of the warnings (and by "fix" I don't just cast the warnings away). Commented Mar 19, 2016 at 13:47
  • Also learn about how to emulate pass by reference in c. Commented Mar 19, 2016 at 13:48

4 Answers 4

2

You compiler should've given a warning for this line:

*s = "Char 2";

Here, *s is a char and you try to assign a string(char*) to it. Fix it by passing the address of s1 to the function:

f2(&s1);

and change the function header to:

void f2(char **s)

When I define a string constant inside a function's scope, that data should be freed once I exit the scope of the function, right? Which means that data would turn into garbage once I return into the calling function scope.

No. String literals have static lifetime which means that they exist as long as the program does. Only local variables inside the function are destroyed once the function ends.

Sign up to request clarification or add additional context in comments.

1 Comment

This was the most useful answer. I noticed my mistake just earlier with f2 and fixed to &s1 in call and **s in header, but the way string literals are stored was my real question here, and you answered this so now I know what I'm doing. thanks.
2

You must not try to modify string literals, or you will invoke undefined behavior.

"Char 1" is assigned, so the argument s of f2 contains a pointer to a string literal. Therefore, assigning something to *s means that you are trying to modify a string literal.

To modify caller's local variable, use pointers to the variable to modify.

You don't have to free the string literals, and you mustn't try to free them because they are allocated with static storage duration, according to N1256 6.4.5 String literals-5 and N1570 6.4.5 String literals-6.

The structure version works because you passed the pointer to the struct and used it to modify a member of the struct without trying to modify any string literals.

This code will work:

#include <stdio.h>

typedef struct {
    char *str;
} strHold;

void f2(char **s) /* add * to receive a pointer to char* */
{
    *s = "Char 2";
}

void f3(strHold *str)
{
    (*str).str = "Struct 2";
}

int main(void)
{
    char *s1 = "Char 1";
    strHold str1;
    str1.str = "Struct 1";

    f2(&s1); /* add & to get the pointer to s1 */
    f3(&str1);

    printf("%s, ", s1);
    printf("%s", str1.str);

    return 0;
}

Comments

1

In:

void f2(char *s)
{
    *s = "Char 2";
}

you will get a compiler error: you are dereference the pointer, which yields a character (type) and now want to assign a string to the character.

More general, a string literal must be stored somewhere in memory, otherwise the program can't assign its value. So after leaving the function the literal is still stored somewhere in memory.

Comments

0

The pointer you have used, *s1 should point to a large enough block of memory, for a beginner use a string long enough to contain your longest output. More experienced programmers should use malloc and free appropiately.

For a beginner:

static char buffer[80]; /* 80 chars of null bytes */
char        *s1;        /* pointer to string */
s1 = buffer;          /* pointer now pointing to beginning of buffer */
strcpy(s1,"Char 1")   /* buffer now contains initial text,
  rest is null bytes, so string is terminated correctly */

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.