turtlesoup turtlesoup - 3 months ago 21
C Question

C string declaration

I am confused about some basics in C string declaration. I tried out the following code and I noticed some difference:

char* foo(){
char* str1="string";
char str2[7]="string";
char* str3=(char)malloc(sizeof(char)*7);
return str1;
/* OR: return str2; */
/* OR: return str3; */
}
void main() {
printf("%s",foo());
return 0;
}


I made foo() return str1/2/3 one at a time, and tried to print the result in the main. str2 returned something weird, but str1 and str3 returned the actual "string".

1.Now, what's the difference between the three declarations? I think the reason why str2 didn't work is because it is declared as a local variable, is that correct?

2.Then what about str1? If the result remains after the foo() ended, wouldn't that cause memory leak?

3.I'm simply trying to write a function that returns a string in C, and use the value returned by that function for other stuff, which str declaration above should I use?

Thanks in advance!

Answer
char* str1="string";

This makes str1 a pointer; it points to the first character of the string literal. You should define it as const, because you're not allowed to modify a string literal:

const char *str1 = "string";

...

char str2[7]="string";

This makes str2 an array of char (not a pointer), and copies the contents of the string literal into it. There's no need to define it as const; the array itself is writable. You can also omit the size and let it be determined by the initializer:

char str2[] = "string";

Then sizeof str2 == 7 (6 bytes for "string" plus 1 for the terminating '\0').

This:

char* str3=(char)malloc(sizeof(char)*7);

is written incorrectly, and it shouldn't even compile; at the very least, you should have gotten a warning from your compiler. You're casting the result of malloc() to type char. You should be converting it to char*:

char *str3 = (char*)malloc(sizeof(char) * 7);

But the cast is unnecessary, and can mask errors in some cases; see question 7.7 and following in the comp.lang.c FAQ:

char *str3 = malloc(sizeof(char) * 7);

But sizeof(char) is 1 by definition, so you can just write:

char *str3 = malloc(7);

malloc() allocates memory, but it doesn't initialize it, so if you try to print the string that str3 points to, you'll get garbage -- or even a run-time crash if the allocated space doesn't happen to contain a terminating null character '\0'. You can initialize it with strcpy(), for example:

char *str3 = malloc(7);
if (str3 == NULL) {
    fprintf(stderr, "malloc failed\n");
    exit(EXIT_FAILURE);
}
strcpy(str3, "string");

You have to be very careful that the data you're copying is no bigger than the allocated space. (No, `strncpy() is not the answer to this problem.)

void main() is incorrect; it should be int main(void). If your textbook told you to use void main() find a better textbook; its author doesn't know C very well.

And you need appropriate #include directives for any library functions you're using: <stdio.h> for printf(), <stdlib.h> for exit() and malloc(), and <string.h> for strcpy(). The documentation for each function should tell you which header to include.

I know this is a lot to absorb; don't expect to understand it all right away.

I mentioned the comp.lang.c FAQ; it's an excellent resource, particularly section 6, which discusses arrays and pointers and the often confusing relationship between them.

As for your question 3, how to return a string from a C function, that turns out to be surprisingly complicated because of the way C does memory allocation (basically it leaves to to manage it yourself). You can't safely return a pointer to a local variable, because the variable ceases to exist when the function returns, leaving the caller with a dangling pointer, so returning your str2 is dangerous. Returning a string literal is ok, since that corresponds to an anonymous array that exists for the entire execution of your program. You can declare an array with static and return a pointer to it, or you can use malloc() (which is the most flexible approach, but it means the caller needs to free() the memory), or you can require the caller to pass in a pointer to a buffer into which your function will copy the result.

Some languages let you build a string value and simply return it from a function. C, as you're now discovering, is not one of those languages.