4

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!

3 Answers 3

9
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.

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

2 Comments

Thanks for the clarification. In this case, if my function has to return a string of arbitrary length, I use a char[someLength] buffer in the function, how can I return this buffer as the output?
@user1926344: First, note that your string of "arbitrary length" couldn't be longer than someLength bytes. Second, you'll just have to copy it to some memory region that the caller will be able to access -- which means you might as well skip the char[someLength] variable and copy it there directly. The region can be static (which has some disadvantages), or it can be malloc()ed, or it can be up to the caller to allocate it and pass your function a pointer.
6
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.

Comments

0

The string literal "string" is stored as a 7-element array of char with static extent, meaning that the memory for it is allocated at program startup and held until the program terminates.

The declaration

char *str1 = "string";

assigns the address of the string literal to str1. Even though the variable str1 ceases to exist when the function exits, its value (the address of the literal "string") is still valid outside of the function.

The declaration

char str2[7] = "string";

declares str2 as an array of char, and copies the contents of the string literal to it. When the function exits, str2 ceases to exist, and its contents are no longer meaningful.

The declaration

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

which can be simplified to

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

allocates an uninitialized 7-byte block of memory and copies its address to str3. When the function exits, the variable str3 ceases to exist, but the memory it points to is still allocated. As written, this is a memory leak, because you don't preserve the value of the pointer in the calling code. Note that, since you don't copy anything to this block, the output in main will be random.

Also, unless your compiler documentation explicitly lists void main() as a legal signature for the main function, use int main(void) instead.

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.