tags:

views:

743

answers:

8

I have written a program in which in the main function I declare an array of pointers and then I call a function which splits a given sentence and then want to assign it to the array of pointers in main(). I am unable to do. Can you please check the code pasted below:

   int  main(void)
   {
      char *data[3];

      allocate(data);
      /* Unable to print the strings here */
      printf("Main is %s\n", data[0] );
      printf(""   

   }

   void allocate(char **dt)
   { 
       int i;
       char buf[] = "The great Scorpion";
       char delims[] = " ";

       size_t len;
       char *p;
       char *result = NULL;
       result = strtok(buf," ");
       *dt = result;
       int j = 1;
       while(result!=NULL)
       {   

            result = strtok( NULL, delims );
            dt[j]=result;
            j++;

       }
      /* able to print values here */
      printf( "result is %s\n", dt[0]); 
      printf( "result is %s\n", dt[1] );
      printf( "result is %s\n", dt[2] );
    }

Can anyone please help me out?

A: 

Yo havent allocated the memory to be used inside data[X] just allocated data. data[0] == null pointer

Chocolim
Makes sense to me. j starts at 1, not 0.
Robert Harvey
Robert:I am using strtok function.So just wann get into the loop.
You missed `*dt = result;` - it sets `dt[0]`
Pavel Minaev
+14  A: 

strtok does not allocate new strings, it returns a pointer to an existing string (and substitutes delimiters with null characters in place). So in allocate, you fill dt with pointers into buf. Since buf is an automatic variable, its lifetime ends when allocate returns, and all pointers in dt are invalidated.

Pavel Minaev
You could fix the automatic variable problem by doing `char const * const buf = "The great scorpion"` b/c then `buf` would be a pointer to a static const string, **BUT** then you wouldn't be able to use `strtok()` since that will want to modify the string `buf` points to, which isn't allowed.
rampion
So he could actually fix the problem by giving buf static storage duration: static char buf[] = "The great Scorpion";
caf
+2  A: 

If I remember correctly, strtok() doesn't do dynamic allocation, it actually modifies the string that you pass to in the first time you call it. So, in this case, it modifies buf. So dt is an array of pointers into buf. And when you exit the function, buf is destroyed.

tetromino
A: 

Ok,

  1. You have an allocate function to which you pass the return pointer array.
  2. Inside the function you allocate a string on the stack, and,
  3. Make the strtok return pointers to this stack area outside the function
  4. At that point you have 'dangling' pointers to the string -- effectively
  5. Then you call printf which kill the data in unallocated stack
  6. you miss the strings in printf.

If you want to do this, the correct way would be to
really allocate strings in your allocate function and
then free them from main after you are done with them.

The older way to work with strtok was to use strdup in the allocate and free later.


OldStuff... I think you need to pass the &data to your allocate function.
Either that, or i am not all awake yet.

nik
He doesn't need that. `data` is of type `(char*)[]`, and will decay to `char**`, which is the function argument type. If he does what you suggest, he'll get (char[])*, which won't be a compatible argument type.
Pavel Minaev
A: 

Actually you might just add static to your buf declaration.

EFraim
A: 

As a small aside (that won't actually have an effect on your program), you loop is structured wrong.

   int j = 1;
   while(result!=NULL)
   {   

        result = strtok( NULL, delims );
        dt[j]=result;
        j++;
   }

You set dt[0], dt[1], and dt[2], correctly. However due the the nature of your loop (you check, call strtok, then insert into dt,) you're also assigning NULL into dt[3]. This would probably run fine in this trivial example, but you're probably trashing your stack. You should really structure your loop like

   result = strtok(buf," ");
   int j=0
   while(result != NULL)
   {   
        dt[j]=result;
        j++;
        result = strtok(NULL, delims);
   }
Falaina
A: 

You're trying to return the address of a local, non-static variable; once the allocate() function exits, the buf array no longer exists, so the pointers in your data array are no longer pointing to anything meaningful.

What you need to do is save a copy of the token, rather than just a pointer to it:

void allocate(char **dt)
{
  char buf[] = "The Great Scorpion";
  char delim[] = " ";
  size_t i = 0;
  char *result = strtok(buf, delim);
  while (result)
  {
    dt[i] = malloc(strlen(result) + 1);
    if (dt[i])
    {
      strcpy(dt[i++], result);
    }
    result = strtok(NULL, delim);
  }
}

int main(void)
{
  char *data[3];
  allocate(data);
  ...
}

Alternately, you can define data to be a 2D array of char, rather than just an array of pointers, but you need to make sure it's sized to handle the maximum string length; also, the type passed to allocate changes:

#define STRING_SIZE ... /* large enough for longest string */
void allocate(char (*dt)[STRING_SIZE+1])
{
  char buf[] = "The Great Scorpion";
  char delim[] = " ";
  size_t i = 0;
  char *result = strtok(buf, delim);
  while (result)
  {
    strcpy(dt[i++], result);
    result = strtok(NULL, delim);
  }
}

int main(void)
{
  char data[3][STRING_SIZE];
  allocate(data);
  ...
}

Dynamically allocating memory is more flexible, but requires some bookkeeping and you have to remember to free it when you're done with it.

John Bode
A: 

To not trash the stack, the while loop should be guarded with the size of the passed parameter "char *data[3]" which is 3 in this case, i.e extra parameter.

But i agree adding static to "static char buf[] = ...." is the quickest answer to get out of pointing to the de-allocated stack of a terminated function.

Koos