views:

622

answers:

7

Hi, I was wondering if you could help me out with a C string problem I don't quite understand. I have a function to which I send 3 char pointers. Within this function, the char pointers are shifted and modified correctly. However, when I return to the main function from which they are called, said functions are not changed. Am I passing by value be mistake? Here is an example of my code:

int main(void) 
{ 
    LPSTR path = (char*)malloc(strlen(START_PATH));

    strcpy( path, START_PATH );

    char* newstr = (char*)malloc(PATH_SIZE);

    TrimVal(path, "*.*", newstr);

    //Do Stuff

    return 0;
}

void TrimVal(char* modify, char* string, char* newstr)
{ 
      newstr[0] = '\0';

      modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));

      return;
}

NOTE: Assume PATH_SIZE is a size value, and START_PATH is a char array

+6  A: 

In doing this

 modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));

You are modifying the pointer, not what the pointer points to.

When you pass in path to TrimVal. It will pass in the memory location of path e.g. 0x12345

When you do the modify = you are saying, change the local variable modify to be a new memory location, e.g. 0x54321

When you return to main, it only has a pointer to 0x12345, and when it looks there, nothing has changed.

You can easily fix your problem by doing

{ 
...
TrimVal(&path, "*.*", newstr);
... 
}

void TrimVal(char** modify, char* string, char* newstr)
{ 

      newstr[0] = '\0';

      *modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));

      return;

}
Salgar
You beat me to the answer. No fair :P
wheaties
should be*modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
ammoQ
It should be noted that if you do these changes without some other changes to the code that calls `TrimVal()` the pointer that was in `path` will be lost and now there's a memory leak since it was allocated from the heap.
Michael Burr
A: 

If you expect your char* variable to be modified in the function and you want to pass by reference, you need to pass it as char* . Remember, you are passing the pointer by reference, so there needs to be an extra layer of indirection (passing char does pass something by reference - a single character!)

tbocek
A: 

C doesn't really have a pass-by-reference. What you are doing here is passing pointers by value. A string in C is represented by a pointer to char. So in the function TrimVal you can modify the contents of the string (that is, the pointed-to data), but not the pointer itself.

strncat modifies the contents of the first parameter and returns the same value.

If you want to change the value of path within TrimVal, you should pass a pointer to a pointer, like so:

...

TrimVal(path, "*.*", newstr);

...

void TrimVal(char** modify, char* string, char* newstr)

{ 
  newstr[0] = '\0';
  *modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
  return;
}
Eddie Sullivan
should be *modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
ammoQ
Good catch. Fixed in the code.
Eddie Sullivan
+1  A: 
void TrimVal(char* modify, char* string, char* newstr)

Changing the values of modify, string, or newstr inside the TrimVal() function has no effect on the variables at the calling function.

Changing the contents of modify, string, or newstr inside the TrimVal() function will be reflected on the variables at the calling function.

So

void TrimVal(char* modify, char* string, char* newstr)
{
    newstr[0] = '\0'; /* will be reflected in the calling function */
    modify = "a new string"; /* won't be reflected */
}

I think your function, with a little clearing of code, could do what you want.

Oh ... and you have a memory leak with the path variable: you malloc some space for it and immediately afterwards lose the address of that space by assigning a different value to the path variable.

pmg
A: 

I see a problem with the first two statements. You are declaring path as a pointer char and allocating memory for it that is stored in this address holder. In your next statement, you are changing the value in path, pointing it to the start of your char array, START_PATH. The memory you allocated is now lost.

Also, strncat does not call malloc to concatenate. It is expected that you are passing in a buffer large enough to hold the concat, and this is a potential security risk (buffer overrun).

+1  A: 

A couple of points in addition to the many other good ones raised in this thread:

    LPSTR path = (char*)malloc(strlen(START_PATH));

If this is C, you should not cast the return value of malloc. (See C FAQ 7.7b.

More importantly, strlen does not include the terminating \0 in its calculation. So, the memory path points to is one character short of the required amount of memory to hold START_PATH plus the \0. Therefore:

    strcpy(path, START_PATH);

invokes undefined behavior by writing one past the memory pointed to by path.

Sinan Ünür
A: 

Hello,

Just one comment about your style of casting the return type of the malloc call. When casting this can hide errors.

This would be a much better style.

Include the stdlib.h and try and make the call to malloc as type independent.

char *ptr_char = NULL;

ptr_char = malloc(sizeof(*ptr_char));

Hope this helps,

robUK