tags:

views:

166

answers:

3

How do I do the following declaration?

int main(int argc, char *argv[]) {
char *users[] = {};
char *names[] = {};

openPasswd(users, names);

return 0;
}

void openPasswd(char &users[] = {}, char &names[] = {}){
}

I want to populate the 2 char arrays from the function back to the main program.

How do I do this?

+4  A: 

You need to use pointers-to-pointers-to-pointers:

void openPasswd(char ***users, char ***names)
{
  *users = malloc(3 * sizeof **users);
  (*users)[0] = "3";
  (*users)[1] = "4";
  (*users)[2] = "7";
  *names = malloc(3 * sizeof **names);
  (*names)[0] = "foo";
  (*names)[1] = "bar";
  (*names)[2] = "baz";
}

int main(void)
{
  char **users, **names;

  openPasswd(&users, &names);
  print("user %s is named %s\n", users[0], names[0]);
  return 0;
}

Note that the above omits error-checking, and assumes data is known at compile-time of course.

unwind
Auuuuuugh ! http://c2.com/cgi/wiki?ThreeStarProgrammer !But it seems the most obvious way to do it in plain old C
Johan Buret
@Johan: Well ... If you consider pointers difficult, or agree with that idea that it's not "a compliment", then maybe C isn't your language. Or, heh, perhaps you prefer to hide them using typedefs. :)
unwind
thank you!!! It looks great but it doesn work... :(I get "assignment from incompatible pointer type"....
John Assael
`users[n]` and `names[n]` in the `openPasswd()` function should be `(*users)[n]` and `(*names)[n]`. You want to subscript what users and names *point to*.
John Bode
@John: Of course! D'oh! Thanks, and fixed.
unwind
@Johan: Re: that link - I honestly don't understand why people get so hung up on multiple levels of indirection. Two star, three star, ten star, all follow the same rules. It may be hard to read, but it's not that hard to understand.
John Bode
+1  A: 

If you don't know how big the arrays are going to be ahead of time:

int main(int argc, char **argv) 
{
  char **users = NULL; // users and names will be dynamically allocated arrays
  char **names = NULL; // of pointer to char
  size_t entries = 0;
  /**
   * Somewhere between here and openPassword figure out how big the arrays
   * need to be
   */
  openPasswd(&users, &names, entries);
  return 0;
}
/**
 * Since we need to modify the values of the pointers for users and names,
 * we must pass pointers to those pointers.
 */
void openPasswd(char ***users, char ***names, size_t entries)
{
  size_t i;

  /**
   * allocate the arrays
   *
   * type of  *users == char **
   * type of **users == char *
   */
  *users = malloc(sizeof **users * entries);
  *names = malloc(sizeof **names * entries);
  /**
   * Allocate each entry and get the username/password data from somewhere
   * get_user_length, get_name_length, get_user, get_name are all
   * placeholders.  
   */
  for (i = 0; i < entries; i++)
  {
    /**
     * The subscript operator should not applied to the values of users and 
     * names, but to the values of what users and names *point to*.  Since 
     * [] binds before *, we must use parens to force the correct grouping.  
     *
     * type of  (*users)[i] == char *
     * type of *(*users)[i] == char
     */
    (*users)[i] = malloc(sizeof *(*users)[i] * get_user_length(i));
    if ((*users)[i] != NULL)
    {
      strcpy((*users)[i], get_user(i));
    }
    (*names)[i] = malloc(sizeof *(*names)[i] * get_name_length(i));
    if ((*names)[i] != NULL)
    {
      strcpy((*names)[i], get_name(i));
    }
  }
}
John Bode