Creating arrays in C

arrays, c, pointers

Solution

You're really on the right track.

In your second example, where you use `malloc()`, the `fgets()` command would be called like so:

`fgets( line, sizeof(line), stdin ); /* vs. fgets( *line ... ) as you have */`

The reason for this is that in C a named array variable is always just a pointer. So:

`char line[256];`

declares (and defines) a pointer called `line` that points to 256 bytes of memory allocated at compile time (probably on the stack).

`char *line;` also declares a pointer, but the memory it points to is not assigned by the compiler. When you call `malloc` you typecast the return value to `char *` and assign it to `line` so the memory is allocated dynamically on the heap.

Functionally though, the variable `line` is just a `char *` (pointer to char) and if you look at the declaration of `fgets` in the `<stdio.h>` file, you'll see what it expects as its first argument:

`char *fgets(char * restrict str, int size, FILE * restrict stream);`

... namely a `char *`. So you could pass `line` either way you declared it (as a pointer or as an array).

With respect to your other questions:

`char *arr[20];` declares 20 uninitialized pointers to `char *`. To use this array, you would iterate 20 times over the elements of `arr` and assign each one with some result of `malloc()`:

arr[0] = (char *) malloc( sizeof(char*) * 256 );
arr[1] = (char *) malloc( sizeof(char*) * 256 );
...
arr[19] = (char *) malloc( sizeof(char*) * 256 );

Then you could use each of the 20 strings. To pass the second one to `fgets`, which expects a `char *` as its first argument, you would do this:

`fgets( arr[1], ... );`

Then `fgets` gets the `char *` it expects.

Be aware of course that you have to call `malloc()` before you attempt this or `arr[1]` would be uninitialized.

Your example using execvp() is correct (assuming you allocated all these strings with `malloc()` first. `vector_arr[0]` is a char **, which `execvp()` expects. [Remember also execvp() expects the last pointer of your vector array to have the value NULL, see the man page for clarification].

Note that `execvp()` is declared like so (see `<unistd.h>`)

`int execvp(const char *file, char *const argv[]);`

removing the `const` attribute for clarity, it could also have been declared like so:

`int execvp( const char *file, char **argv );`

The declaration of `char **array` being functionally equivalent to `char *array[]`.

Remember also that in every example where we use `malloc()`, you'll have to at some point use a corresponding `free()` or you'll leak memory.

I'll also point out that, generally speaking, although you can do an array of vectors (and arrays of arrays of vectors and so on), as you extend your arrays more and more dimensionally you'll find the code gets harder and harder to understand and maintain. Of course you should learn how this all works and practice until you understand it fully, but if in the course of designing your code you find yourself thinking you need arrays of arrays of arrays you are probably overcomplicating things.

Problem

I am attempting to create a UNIX shell in C. If it were in Java, it would be a piece of cake, but I am not so experienced in C. Arrays in C confuse me a bit. I am not sure how to declare or access certain data structures. I would like to create a string to read in each line. Easy enough: simply an array of characters. I would initialize it as follows: ``` char line[256]; //Maximum size of each line is 255 characters ``` And to access an element of this array, I would do as follows: ``` line[0] = 'a'; //Sets element 0 to 'a' fgets( line, sizeof line, stdin ); //Gets a line from stdin and places it in line ``` How does declaring and using a string in this manner differ from declaring it as a pointer? From my understanding, an array in C decays to a pointer. So, would the following be equivalent? ``` char *line = (char*) malloc( sizeof(char) * 256 ); line[0] = 'a'; fgets( *line, sizeof(line), stdin ); ``` When do you use the pointer character '*', and when don't you? In the example above, is including the '*' in fgets necessary, or correct? Now, I would like to create an array of strings, or rather, an array of pointers which point to strings. Would I do so as follows? ``` char *arr[20]; // Declares an array of strings with 20 elements ``` And how would I access it? ``` arr[0] = "hello" // Sets element zero of arr to "hello" ``` Is this correct? How would I pass this array to a function? ``` execvp("ls", arr); // Executes ls with argument vector arr ``` Is that correct, or would I use the pointer *arr? If so, why? Now even worse, I would like an array of arrays of strings (for example, if I wanted to hold multiple argument vectors, in order to execute multiple commands in pipe sequence). Would it be declared as follows? ``` char **vector_arr[20]; // An array of arrays of strings ``` And how would I access an element of this array? ``` execvp("ls", vector_arr[0]); // Executes ls with first element of vector_arr as argument vector ``` I thought that I grasped a decent understanding of what a pointer is, and even how arrays relate to pointers, however I seem to be having trouble relating this to the actual code. I guess that when dealing with pointers, I don't know when to reference *var, var, or &var.

Original source

Related problems