5

I have a c function that I want to return a string.

If I print the string before it is returned then I see croc_data_0186.idx

If I try and print the string that is returned then I see croc_data_á☼

Can anyone see what I am doing wrong?

Problem function:

char* getSegmentFileName(FILE *file, int lineLength, int lineNumber)
{
    char* fileNameString;

    fseek(file, lineNumber * lineLength, SEEK_SET);

    char line[lineLength];
    fgets(line, lineLength, file);

    char *lineElements[3];
    lineElements[0] = strtok(line, ":");
    lineElements[1] = strtok(NULL, ":");
    lineElements[2] = strtok(NULL, ":");

    fileNameString = lineElements[2];

    printf ("getSegmentFileName fileNameString is: %s \r\n", fileNameString);

    return fileNameString;
}

Calling code:

int indexSearch(FILE *file, char* value, int low, int high, char* segmentFileName)
{
    ...

    segmentFileName = getSegmentFileName(file, lineLength, mid);
    printf ("indexSearch: segmentFilename3 is: %s \r\n", segmentFileName);

    ...
}
Dunc
  • 7,688
  • 10
  • 31
  • 38
  • possible duplicate of [functions returning char pointer](http://stackoverflow.com/questions/2341579/functions-returning-char-pointer) – Lundin Feb 21 '12 at 14:49
  • Possible duplicate of [Returning C string from a function](https://stackoverflow.com/questions/1496313/returning-c-string-from-a-function) – underscore_d Dec 12 '17 at 14:09

7 Answers7

8

You are returning a pointer to local data, which is not valid after the function returns. You have to allocate the string properly.

This can be done in either the calling function, by supplying a buffer to the called function, and it copies the string over to the supplied buffer. Like this:

char segmentFileName[SOME_SIZE];
getSegmentFileName(file, lineLength, mid, segmentFileName);

and the getSegmentFileName function:

void getSegmentFileName(FILE *file, int lineLength, int lineNumber, char *segmentFileName)
{
    /* ... */

    strcpy(segmentFileName, fileNameString);
}

The other solution is to allocate the memory for the string in getSegmentFileName:

return strdup(fileNameString);

but then you have to remember to free the string later.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
4

This is because you are returning a pointer to local. This is undefined behavior.

strtok returns a pointer into the line character array. You put that pointer into fileNameString, and return to the caller. At this time the memory inside line becomes invalid: any garbage can be written into it.

To avoid this problem, you should either pass a buffer/length pair for the return value, or use strdup() on the string that you are returning. In the later case you should remember to free the memory allocated for the returned string by strdup().

On a related subject, you should avoid using strtok, because it is not re-entrant, and will cause issues in multithreaded environments. Consider using strtok_r instead.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • You're quick, Johhny, so quick – Tio Pepe Feb 21 '12 at 14:17
  • "a buffer/length pair for the return value" - which is especially straightforward in this case, since a buffer of size `lineLength` is big enough. It's more fiddly when the caller doesn't know a good upper limit in advance. – Steve Jessop Feb 21 '12 at 14:24
3

You are returning a pointer to a local variable that doesn't exist anymore when the function returns. You have to malloc storage for it and return that. Alternatively, you can let the caller pass in a buffer to be filled. In any case the caller is responsible for freeing the memory later.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
2

It is because you return invalid pointers.

    char* fileNameString;

is just a pointer.

    char line[lineLength];

lives on the stack and is filled with a fgets() call.

    char *lineElements[3];
    lineElements[0] = strtok(line, ":");
    lineElements[1] = strtok(NULL, ":");
    lineElements[2] = strtok(NULL, ":");

Here you store pointers into that array. One of them is

    fileNameString = lineElements[2];

which you

    return fileNameString;

afterwards.

The solution would be to

  • either malloc enough space inside the function and copy your string to the new memory block or

  • have the caller provide a buffer you write the data into.

glglgl
  • 89,107
  • 13
  • 149
  • 217
2

The problem is that you are returning an stack variable, lost when function returns. One way to make this is to use a char * arg in function parameter, with enough reserved space, and use it to store all information and returns it.

Tio Pepe
  • 3,071
  • 1
  • 17
  • 22
0

Line is a local variable and is removed at the end of the function.

You should use malloc, or strcpy it to a string pointer passed as argument.

Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119
0

There are 3 ways you can solve this

1) Make 'fileNameString' static

static char fileNameString[100];

2) Caller of the function 'getSegmentFileName' should pass a character buffer 'segmentFileName' to the callee i.e.

getSegmentFileName(file, lineLength, mid, segmentFileName);

In this case you need to change the function arguments

   char* getSegmentFileName(FILE *file, int lineLength, int lineNumber, char *segmentFileName) {

    .....

    strcpy(segmentFileName, fileNameString); // copying the local variable 'fileNameString' to the function argument
                      // so that it wont be lost when the function is exited.

    return fileNameString; // there is no need to return anything and you can make this function void
                   // in order not to alter ur program I am putting the return also
    }

3) In this way you can dynamically allocate the memory for the fileNameString. Dynamic memory is allocated in the heap and it wont be lost when the function returns. So you can safely use it in the indexSearch function.

char* getSegmentFileName(FILE *file, int lineLength, int lineNumber)
{
    char *fileNameString = (char *)malloc(100 * sizeof(char));  // allocate memory for 100 character string

    .....
    return fileNameString;
}

In this case you will need to free the memory pointed by fileNameString using free

snibu
  • 581
  • 4
  • 16