1

I am trying to return and print a function in C. Printing it out works in the function just fine, but when I try to print it after returning it from the function, I get nonsense.

I have already tried a lot and I think I have seen at least 6 stack overflow posts similar to this and this is the closest thing I can get to working that is not a segmentation fault or an error.

Code:

char* getBitstring(unsigned short int instr) {
    //this is what the code below is going to convert into. It is set to default
    //as a 16 bit string full of zeros to act as a safety default.
    char binaryNumber[] = "0000000000000000";

    //....
    //doing things to binaryNumber
    //.....

    printf("don't get excited yet %s\n", binaryNumber); //note, this works

    return binaryNumber;
}
int main(int argc, char *argv[]) {
    char *a = getBitstring(0x1234);
    printf("%s", a); //this fails
    return 0;
}

Here is the output:

don't get excited yet 0001001000110100
������e��r�S�����$�r�@�t�$�r�����ͅS�������t����
6
  • Can you tell us what printf("%d\n", binaryNumber[16]); shows? Commented Dec 8, 2014 at 21:04
  • 1
    Did any of those other posts mention anything about not to return local data? Commented Dec 8, 2014 at 21:04
  • @Qix it returns "don't get excited yet 0001001000110100". If I took that line out, the only output would be the nonsense. Commented Dec 8, 2014 at 21:05
  • @Jongware yes, did and earned a downvote, too. what a day !!! Commented Dec 8, 2014 at 21:08
  • 1
    @JS1 This is true, but the string literal is initialized into read-only memory segment by the compiler, so trying to modify binaryNumber will result in an invalid memory reference (segmentation fault). Commented Dec 8, 2014 at 21:44

6 Answers 6

3

This is because you are returning a pointer to an object allocated in automatic memory - an undefined behavior.

If you want to return a string from a function, you need to return either a dynamically-allocated block, or a statically allocated block.

Another choice is to pass the buffer into the function, and provide the length as the return value of the function, in the way the file reading functions do it:

size_t getBitstring(unsigned short int instr, char* buf, size_t buf_size) {
    ... // Fill in the buffer without going over buf_size
    printf("don't get excited yet %s\n", binaryNumber);
    return strlen(buf); 
}

Here is how you call this function:

char binaryNumber[] = "0000000000000000";
size_t len = getBitstring(instr, binaryNumber, sizeof(binaryNumber));

Now binaryNumber is an automatic variable in the context of the caller, so the memory would be around while the caller needs it.

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

4 Comments

I am confused, how would I call this?
Before calling the function, allocate a buffer for your string. Your function will then fill the buffer. After the function is over, the caller can then print the buffer.
I am knew to C, can you point me to a good reference on how learn to use buffers in this specific example
This is TOO complex for student work and far away from simple demo of char * result. Also, are you sure that char * return value is not strictly required by the examination?
1

This is a good example of a problem people hit when they're learning C that they probably wouldn't hit if they were operating in Java or another more modern language that doesn't expose the details of memory layout to the user.

While everyone's answer here is probably technically correct, I'm going to try a different tack to see if I can answer your question without just giving you a line of code that will fix it.

  1. First you need to understand what's going on when returning a variable defined inside a function, like this:

    void f(void) {
        int x = 0;
    
        /* do some crazy stuff with x */
    
        return x;
    }
    

    What happens when you call return x;? I'm probably omitting some details here, but what is essentially going on is that the calling context gets the value stored inside the variable named x at that time. The storage that is allocated to store that value is no longer guaranteed to contain that value after the function is over.

  2. Second, we need to understand what happens when we refer to an array by its name. Say we have a 'string':

    char A[] = "12345";
    

    In C, this is actually equivalent to declaring an array of characters that ends in a \0:

    char A[6] = { '1' , '2' , '3' , '4' , '5' , '\0' };
    

    Then this is sort of like declaring six chars A[0], A[1], ... , A[5]. The variable A is actually of type char * i.e. it is a pointer containing the memory address storing A[0] (the beginning of the array).

  3. Finally, we need to understand what happens when you call printf to print a string like this:

    printf("%s", A);
    

    What you're saying here is "print all the bytes starting at memory address A until you hit a byte that contains \0".

So, let's put it all together. When you run your code, the variable binaryNumber is a pointer containing the memory address of the first character of the array: binaryNumber[0], and this address is what's returned by the function. BUT, you've declared the array inside of getBitString, so as we know that the memory allocated for the array is no longer guaranteed to store the same values after getBitString is over.

When you run printf("%s", a) you're telling C to "print all the bytes starting at memory address a until you get to a byte containing \0 -- but since that memory address is only guaranteed to contain valid values inside getBitString, what you get is whatever garbage it happens to contain at the time when you call it outside of getBitString.

So what can you do to resolve the problem? Well you have several options, here are is a (non-exhaustive) list:

  1. You declare binaryString outside of getBitString so that it's still valid when you try to access it in main
  2. You declare binaryString as static as some others have suggested, which is effectively the same thing as above, except that the actual variable name binaryString is only valid inside the function, but the memory allocated to store the array is still valid outside the function.
  3. You make a copy of the string using the strdup() function before you return it in your function. Remember that if you do this, you have to free() the pointer returned by strdup() after you're done with it, otherwise what you've got is a memory leak.

Comments

1

Your binaryNumber character array only exists inside of your getBitstring function. Once that function returns, that memory is no longer allocated to your binaryNumber. To keep that memory allocated for use outside of that function you can do one of two things:

Return a dynamically allocated array

char* getBitstring(unsigned short int instr) {
    // dynamically allocate array to hold 16 characters (+1 null terminator)
    char* binaryNumber = malloc(17 * sizeof(char));
    memset(binaryNumber, '0', 16); // Set the first 16 array elements to '0'
    binaryNumber[16] = '\0'; // null terminate the string

    //....
    //doing things to binaryNumber
    //.....

    return binaryNumber;
}

int main(int argc, char *argv[]) {
    char *a = getBitstring(0x1234);
    printf("%s", a);
    free(a); // Need to free memory, because you dynamically allocated it
    return 0;
}

or pass the array into the function as an argument

void* getBitstring(unsigned short int instr, char* binaryNumber, unsigned int arraySize ) {
    //....
    //doing things to binaryNumber (use arraySize)
    //.....
}

int main(int argc, char *argv[]) {
    char binaryNumber[] = "0000000000000000";
    getBitstring(0x1234, binaryNumber, 16); // You must pass the size of the array
    printf("%s", binaryNumber);
    return 0;
}

Others have suggested making your binaryNumber array static for a quick fix. This would work, but I would avoid this solution, as it is unnecessary and has other side effects.

Comments

0

Create your return type in dynamic way with malloc() function. create 16+1 blocks for end of string. this is not safe but easy to understand.

char * binaryNumber = (char*) malloc(17*sizeof(char));//create dynamic char sequence
strcpy(binaryNumber,"0000000000000000");//assign the default value with String copy

The final result will be;

char* getBitstring(unsigned short int instr) {
//this is what the code below is going to convert into. It is set to default
//as a 16 bit string full of zeros to act as a safety default.
char * binaryNumber = (char*) malloc(17*sizeof(char));//create dynamic char sequence
strcpy(binaryNumber,"0000000000000000");//assign the default value with String copy function
//....
//doing things to binaryNumber
//.....
printf("don't get excited yet %s\n", binaryNumber); //note, this works
return binaryNumber;
}
 int main(int argc, char *argv[]) {
 char *a = getBitstring(0x1234);
 printf("%s", a); //this fails
 return 0;
}

of course include the <string.h> library.

Comments

0

your char binaryNumber[] is local to the function getBitstring(). you cannot return a local variable to other function.

The scope of binaryNumber is over when getBitstring() finishes execution. So, in your main(), char *a is not initialized.

The workaround:

  1. define the array as static so that it does not go out-of-scope. [Not a good approach, but works]

or

  1. use dynamic memory allocation and return the pointer. [don't forget to free later, to avoid memory leak.]

IMO, the second approach is way better.

2 Comments

@i486 but OP did not make it static. and is that the reason for downvote?
Sorry for the downvote. I clicked it first, then realized that have to add comment.
-1

You need static:

static char binaryNumber[] = "0000000000000000";

Without static keyword, the value of automatic variable is lost after function returns. Probably you know this.

13 Comments

this worked thanks. Ill give you the answer when it lets me. Can you explain how this works please? because I have an exam on this soon and I would like to know whats going on.
With static keyword the local variable is like global - i.e. it exists all time of program life. Without static it exists in the stack only for the time of function call - then it is freed and you get garbage at printf time.
it works. though, honestly, declare a static data field for return should be discouraged.
so Im assuming that it isnt great practice then? this is a helper function.
Agree with @HuStmpHrrr. In my book it's slightly more evil that just going all the way and declaring the string globally. With global variables you know at least where to look.
|

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.