0
void test(){
   char *c = malloc(strlen("I like coffe") + 1);
   strcpy(c, "I like coffe");
   char **s = &c;
   while(strlen(*s) < 25)
      my_function(s);
}

void my_function(char **s){
  char *w  = *s;   

  char *tmp = realloc(w, len + 2);//Error HERE. *s gets = ""
  if(tmp != NULL)
  w = tmp;
  for(i= len; i>=p; i--){
      w[i+1] = w[i];
  }
  w[p] = c;    
}  

This function is used to insert a new character inside a char *.
Also, this function is inside a while loop. It works fine but by the 3rd time the loop runs, it just sets *s = "".
I thought that by using the char *tmp I could keep the data if any wrong thing happen. I can't understand why P *s is been setted to empty string.

7
  • 1
    Betcha you're running into trouble by fiddling with "pointers-to-pointers." Grab a piece of paper and a number-two pencil and work out ... offline(!) ... "I said, 'a piece of paper and a number-two pencil!'" ... what this snippet of code is actually telling the computer to do. "The error of your ways" should become obvious. (And, no, I'm not trying to be snarky here.) Commented May 14, 2015 at 2:33
  • You are never reassigning the parent s back with the new address. There is no guarantee that realloc(addr) returns addr. In fact, with most custom allocators, it usually won't. Try doing a *s = tmp rather than a w = tmp in your code. Also, if realloc fails (returns NULL), you would need to set *s to NULL. Commented May 14, 2015 at 2:38
  • 1
    @digger: No; if realloc() returns NULL, the original allocation is unchanged. Commented May 14, 2015 at 2:38
  • I thought that as I did not allocated memory for w it would NOT be just a COPY of *s. When I add a character to w[p] it changes in *s aswell. Commented May 14, 2015 at 2:41
  • 1
    The first time you call my_function the realloc will free the memory pointed to by *s. So you need to have an *s = w at the end of that function to update the original pointer to the new memory. Better still, IMHO, forget the double pointer. Just return the relloced value from the function. Also, don't need to call malloc in the parent function. realloc will handle a NULL first paramter by doing a malloc. Commented May 14, 2015 at 2:45

1 Answer 1

3

You've forgotten to assign the new value to *s in the function that contains realloc().

void test(void)  // Unaltered; still broken!
{
    char *c = malloc(strlen("I like coffe") + 1);
    strcpy(c, "I like coffe");
    char **s = &c;
    while (strlen(*s) < 25)
        my_function(s);
}

void my_function(char **s)  // Fixed one way
{
    char *w  = *s;   
    size_t len = strlen(w) + 1;  // Define and initialize len

    char *tmp = realloc(w, len + 2);
    if (tmp != NULL)
        w = tmp;
    *s = w;  // Reassign to `*s`
}

Or, more simply:

void my_function(char **s)  // Fixed another way
{
    char *w  = *s;   
    size_t len = strlen(w);  // Define and initialize len

    char *tmp = realloc(w, len + 2);
    if (tmp != NULL)
        *s = tmp;  // Reassign to `*s`
}

Assigning to w only sets the local variable which is a copy of *s; it does not reset the pointer in the calling code.

Note that even with this fix, the loop in test() is going to run a long time because nothing changes the length of the string in c. There's also another problem: you don't pass the address of s to my_function(), so my_function() can't modify s.

void test(void)
{
    char *c = malloc(strlen("I like coffe") + 1);
    strcpy(c, "I like coffe");
    while (strlen(c) < 25)
    {
        my_function(&c);
        strcat(c, "AZ");  // Grow string — not good in real code
        printf("%2zu: <<%s>>\n", strlen(c), c);
    }
}

void my_function(char **s)
{
    char *w = *s;   
    size_t len = strlen(w) + 1;  // Define and initialize len

    char *tmp = realloc(w, len + 2);
    if (tmp != NULL)
        *s = tmp;  // Reassign to `*s`
}

This does away with the pointer to pointer to char in test(). If that's crucial, there's more thinking to be done.

Code not formally tested yet!

Code now tested — can you say "pig's ear"? Copy'n'paste of the wrong material made my test code fail. Here's the instrumented working version — valgrind gives it a clean bill of health.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void my_function(char **s)
{
    char *w = *s;
    size_t len = strlen(w) + 1;  // Define and initialize len
    printf("M1: %p: %2zu: <<%s>>\n", (void *)w, len, w);

    char *tmp = realloc(w, len + 2);
    if (tmp != NULL)
        *s = tmp;  // Reassign to `*s`
    printf("M2: %p: %2zu: <<%s>>\n", (void *)*s, strlen(*s), *s);
}

static void test(void)
{
    char *c = malloc(strlen("I like coffe") + 1);
    if (c == 0)
    {
        fprintf(stderr, "Out of memory\n");
        exit(EXIT_FAILURE);
    }
    strcpy(c, "I like coffe");
    printf("T1: %p: %2zu: <<%s>>\n", (void *)c, strlen(c), c);
    while (strlen(c) < 25)
    {
        my_function(&c);
        printf("T2: %p: %2zu: <<%s>>\n", (void *)c, strlen(c), c);
        if (c == NULL)
        {
            fprintf(stderr, "Out of memory\n");
            exit(EXIT_FAILURE);
        }
        strcat(c, "AZ");  // Grow string — not good in real code
        printf("T3: %p: %2zu: <<%s>>\n", (void *)c, strlen(c), c);
    }
    free(c);
}

int main(void)
{
    test();
    return 0;
}
Sign up to request clarification or add additional context in comments.

7 Comments

I thought that as I did not allocated memory for w, just made w points to the same local as *s points, it would change both. I didnt think it was just a copy. And why it only happens by the 3rd time and not since the first time I run.
It is easy to be confused, but w contains a copy of *s. Modifying w modifies the local copy, not the original.
I just made another test. Those functions are in separeted files.c. When my_function()is over and returns for the caller function. I can see the modified value of *s. How if its just a copy ? So confused haha
There are some more problems; working on the fix and write-up — and trying to avoid being a Three Star Programmer.
@BLUEPIXY: the problem is more that the strlen(w) doesn't account for the null byte; the +2 is correct if the base length is correct, which it wasn't when you commented but is now (unless I've screwed up again, somewhere).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.