views:

64

answers:

4

Hi.

I'm attempting to create an array of strings that represent the directories stored in the PATH variable. I'm writing this code in C, but I'm having trouble getting the memory allocation parts working.

char* shell_path = getenv ("PATH");
char* tok = strtok (shell_path, SHELL_PATH_SEPARATOR);
int number_of_tokens = 0, i = 0;

while (tok != NULL)
{
    number_of_tokens++;
}

Shell_Path_Directories = malloc (/* This is where I need some help */);
shell_path = getenv ("PATH");
tok = strtok (shell_path, SHELL_PATH_SEPARATOR);
while (tok != NULL)
{
    Shell_Path_Directories[i++] = tok;
    tok = strtok (NULL, SHELL_PATH_SEPARATOR);
}

The issue I'm having is that I can't think of how I can know exactly how much memory to allocate.

I know I'm tokenizing the strings twice, and that it's probably stupid for me to be doing that, but I'm open to improvements if someone can figure out a better way to do this.

+1  A: 

You can do:

Shell_Path_Directories = malloc (sizeof(char*) * number_of_tokens);

Also the way you are counting the number_of_tokens is incorrect. You need to call the strtok again in the loop passing it NULL as the 1st argument:

while (tok != NULL) {
    number_of_tokens++;
    tok = strtok (NULL, SHELL_PATH_SEPARATOR);

}
codaddict
Yeah, that was just a mistake I made when editing the code to make it suitable to display here. Thanks though.
Varun Madiath
A: 

Since you've counted the number of tokens already, you can use that as the number of pointers to char to allocate:

char **Shell_Path_Directories = malloc(number_of_tokens * sizeof(char *));

Then you have one more minor issue: you're using strtok directly on the string returned by getenv, which leads to undefined behavior (strtok modifies the string you pass to it, and you're not allowed to modify the string returned by getenv, so you get undefined behavior). You probably want to duplicate the string first, then tokenize your copy instead.

Jerry Coffin
A: 

You should not change the getenv-return pointer, safer you make a copy. With strtok you can destroy the content of your environment table.

char* shell_path = getenv ("PATH");
char *p,*copyenv = strcpy( malloc(strlen(shell_path)+1), shell_path );
char **result = 0;
int i = 0;
for( p=strtok(copyenv,SHELL_PATH_SEPARATOR); p; p=strtok(0,SHELL_PATH_SEPARATOR) )
{
  result = realloc( result, ++i*sizeof*result );
  strcpy( result[i-1]=malloc(strlen(p)+1), p );
}
+1 for the observation that you may separate the problem of allocation of the `result` array and the copied strings. -1 for ugly programming with side effects on `i` where you simply could choose that as a loop variable.
Jens Gustedt
+1  A: 

Just to give you basically the same answer as user411313's in a different dialect:

char* shell_path = getenv ("PATH");

/* Copy the environment string */
size_t const len = strlen(shell_path)+1;
char *copyenv = memcpy(malloc(len), shell_path, len);

/* start the tokenization */
char *p=strtok(copyenv,SHELL_PATH_SEPARATOR);
/* the path should always contain at least one element */
assert(p);

char **result = malloc(sizeof result[0]);
int i = 0;

while (1)
{
  result[i] = strcpy(malloc(strlen(p)+1), p);
  p=strtok(0,SHELL_PATH_SEPARATOR);
  if (!p) break;
  ++i;
  result = realloc( result, (i+1)*sizeof*result );
}
Jens Gustedt
This code is for the most part correct.In the realloc it should be (i+1) instead of simply i.Other than that this answer I feel was the answer which answered my question in the best way possible.Thanks a lot.
Varun Madiath
@Varun: oops, corrected.
Jens Gustedt