0

I need to store a list of names in C. I decided a good way to do this would be to use double pointers (or pointers-to-pointers).

So I will have an array of names. Each array value is a pointer to another array: the name, stored as a character array.

The names might look like

unsigned char *name = "Joseph";

etc.

And then I would have a list of names (double pointer), to which I could (dynamically) assign each name (single pointer).

(type) **listOfNames;

My question is: what type should the double pointer be? Since it is a pointer to a pointer, I was thinking that it must be large enough to hold an arbitrary memory address: unsigned long, maybe? Or is there another type meant specifically for double pointers?

Alternatively — is there a better way of storing a variable-length array or variable-length strings?

5
  • 2
    Just char, or unsigned char if you really need that. The size of a pointer to T is not the same as the size of a T. Commented Sep 1, 2014 at 22:35
  • Oh, so just char **list;? Commented Sep 1, 2014 at 22:36
  • Yes. Otherwise you would have trouble making it point to string literals. Commented Sep 1, 2014 at 22:37
  • @user3121023 You don't have to, e.g. char const *listOfNames[20]; Commented Sep 1, 2014 at 22:47
  • Issue is that the names are not const. I am reading them from a file. Thus a variable length array of variable length strings. I don't know how long anything will be at compile time. Commented Sep 1, 2014 at 22:47

1 Answer 1

1

If you have a collection of unsigned char * values:

unsigned char *name_0 = "Joseph";
unsigned char *name_1 = "Helen";
unsigned char *name_2 = "Maximillian";

Then you can create:

unsigned char *data[] = { name_0, name_1, name_2 };
unsigned char **listOfNames = data;

Note that you need to allocate space for the list of pointers — in my code, that's the data array. You could use malloc() instead, but you'd need to remember to code the matching free() at some point.

Adding appropriate const qualifications is left as an exercise in frustration to the interested reader.

If you are reading a variable length list of names from a file a run time, with (presumably) one name per line, then you'd do best with POSIX getline() and strdup().

There must be a number of other questions that deal with this scenario, so I'll be terse with this code:

char **read_file(FILE *fp)
{
    char  *buffer = 0;
    size_t bufsiz = 0;
    char **lines = 0;
    size_t n_lines = 0;
    size_t n_alloc = 0;

    while (getline(&buffer, &bufsiz, fp) > 0)
    {
        if (n_lines + 1 >= n_alloc)
        {
            size_t new_num = (n_alloc + 1) * 2;
            size_t new_size = new_num * sizeof(*lines);
            char **new_lines = realloc(lines, new_size);
            if (new_lines == 0)
            {
                free(buffer);
                free(lines);
                return(0);
            }
            lines = new_lines;
            n_alloc = new_num;
        }
        lines[n_lines++] = strdup(buffer);  // Includes newline!
    }
    lines[n_lines] = 0;  // Null terminate list of strings
    free(buffer);        // Release input line's memory
    return lines;
}

Note that the code uses plain char and not unsigned char. You face some issues if you use unsigned char because neither getline() nor strdup() expects to work with unsigned char. While you can cast your way around the issue, it is messy to do so.

Sign up to request clarification or add additional context in comments.

4 Comments

I ended up using a slightly less-glorified version of that code. Some minor differences, including the fact that my list is CSV. I also didn't use strdup() but instead re-declared the buffer variable at the start of each loop.
Oh, yes — drat! I forgot to release buffer before returning, so my code leaks (well, leaked) memory. Using variations on the theme is fine — encouraged, even.
How about -1 as the return test for getline?
Yes, I needed to reread the manual page. I'd probably go with > 0 as the condition, but it will never return 0 anyway — either -1 or some number larger than zero.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.