Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C string declaration

Tags:

c

string

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!

like image 845
turtlesoup Avatar asked Dec 07 '22 09:12

turtlesoup


2 Answers

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.

like image 166
Keith Thompson Avatar answered Dec 27 '22 05:12

Keith Thompson


char* str1="string";

This creates a pointer to a literal string that will be located on either .data or .text segments and is accessible at all times. Whenever you do something like that, be sure to declare it const, because if you try to modify it, nasty things might happen.

char str2[7]="string";

This creates a local buffer on the stack with a copy of the literal string. It becomes unavailable once the function returns. That explains the weird result you're getting.

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

This creates a buffer on the heap (uninitialized) that will be available until you free it. And free it you must, or you will get a memory leak.

like image 44
imreal Avatar answered Dec 27 '22 06:12

imreal