There are two way of working with array of characters (strings) in C. They are as follows:

char a[ROW][COL];
char *b[ROW];

Pictorial representation is available as an inline comment in the code.

Based on how you want to represent the array of characters (strings), you can define pointer to that as follows

    char (*ptr1)[COL] = a;
    char **ptr2 = b;

They are fundamentally different types (in a subtle way) and so the pointers to them is also slightly different.

The following example demonstrates the different ways of working with strings in C and I hope it helps you in better understanding of array of characters (strings) in C.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ROW 5
#define COL 10

int main(void) 
{
    int i, j;
    char a[ROW][COL] = {"string1", "string2", "string3", "string4", "string5"};
    char *b[ROW];

    /*

    a[][]

      0   1   2   3   4   5   6     7    8   9
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 1 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 2 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 3 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 4 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 5 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+

    */  

    /* Now, lets work on b */    
    for (i=0 ; i<5; i++) {
        if ((b[i] = malloc(sizeof(char) * COL)) == NULL) {
            printf("unable to allocate memory \n");
            return -1;
        }
    }

    strcpy(b[0], "string1");
    strcpy(b[1], "string2");
    strcpy(b[2], "string3");
    strcpy(b[3], "string4");
    strcpy(b[4], "string5");

    /*

       b[]              0   1   2   3   4   5   6    7     8   9
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 1 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 2 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 3 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 4 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 5 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+

    */

    char (*ptr1)[COL] = a;
    printf("Contents of first array \n");
    for (i=0; i<ROW; i++)
        printf("%s \n", *ptr1++);


    char **ptr2 = b;
    printf("Contents of second array \n");
    for (i=0; i<ROW; i++)
        printf("%s \n", ptr2[i]);

    /* b should be free'd */
    for (i=0 ; i<5; i++)
        free(b[i]);

    return 0;
}
Answer from Sangeeth Saravanaraj on Stack Overflow
Top answer
1 of 2
28

There are two way of working with array of characters (strings) in C. They are as follows:

char a[ROW][COL];
char *b[ROW];

Pictorial representation is available as an inline comment in the code.

Based on how you want to represent the array of characters (strings), you can define pointer to that as follows

    char (*ptr1)[COL] = a;
    char **ptr2 = b;

They are fundamentally different types (in a subtle way) and so the pointers to them is also slightly different.

The following example demonstrates the different ways of working with strings in C and I hope it helps you in better understanding of array of characters (strings) in C.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ROW 5
#define COL 10

int main(void) 
{
    int i, j;
    char a[ROW][COL] = {"string1", "string2", "string3", "string4", "string5"};
    char *b[ROW];

    /*

    a[][]

      0   1   2   3   4   5   6     7    8   9
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 1 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 2 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 3 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 4 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+
    | s | t | r | i | n | g | 5 | '\0' |   |   |
    +---+---+---+---+---+---+---+------+---+---+

    */  

    /* Now, lets work on b */    
    for (i=0 ; i<5; i++) {
        if ((b[i] = malloc(sizeof(char) * COL)) == NULL) {
            printf("unable to allocate memory \n");
            return -1;
        }
    }

    strcpy(b[0], "string1");
    strcpy(b[1], "string2");
    strcpy(b[2], "string3");
    strcpy(b[3], "string4");
    strcpy(b[4], "string5");

    /*

       b[]              0   1   2   3   4   5   6    7     8   9
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 1 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 2 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 3 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 4 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+
    |      --|------->| s | t | r | i | n | g | 5 | '\0' |   |   |
    +--------+        +---+---+---+---+---+---+---+------+---+---+

    */

    char (*ptr1)[COL] = a;
    printf("Contents of first array \n");
    for (i=0; i<ROW; i++)
        printf("%s \n", *ptr1++);


    char **ptr2 = b;
    printf("Contents of second array \n");
    for (i=0; i<ROW; i++)
        printf("%s \n", ptr2[i]);

    /* b should be free'd */
    for (i=0 ; i<5; i++)
        free(b[i]);

    return 0;
}
2 of 2
1

What would be the correct way to solve this problem?

Well, the correct way would be to use a library specifically designed for dealing with multilanguage interfaces - for instance gettext.

Another way, though patchier, would be to use a hash table (also known as "dictionary" or "hash map" or "associative map" in other languages/technologies): Looking for a good hash table implementation in C

It's probably not the answer you were looking for, but you've asked the wrong question to the right problem.

🌐
RIT
se.rit.edu β€Ί ~swen-250 β€Ί activities β€Ί MicroActivities β€Ί C β€Ί mu_string_ptr_update β€Ί distrib β€Ί index.html
C Strings with Arrays and Pointers
Arrays can be declared with an ... in Hello! + terminating NUL Β· An array name is a constant pointer to the first (0th) array element; thus: mesg == &mesg[0] ; // address of the first character in the message....
🌐
DEV Community
dev.to β€Ί missmati β€Ί pointers-arrays-strings-in-c-52h3
Pointers , Arrays & Strings in C - DEV Community
October 11, 2022 - Pointers contain addresses of the particular variable that we need. An array of pointers stores the addresses of all the elements of the array and an array of string pointers stores the addresses of the strings present in the array.
🌐
TutorialsPoint
tutorialspoint.com β€Ί c-program-to-print-array-of-pointers-to-strings-and-their-address
C program to print array of pointers to strings and their address
The C program demonstrating the concept of printing array of pointers to string and the addresses too is given below βˆ’ Β· #include<stdio.h> #include<string.h> void main(){ //Declaring string and pointers, for loop variable// int i; char *a[5]={"One","Two","Three","Four","Five"}; //Printing values within each string location using for loop// printf("The values in every string location are : "); for(i=0;i<5;i++){ printf("%s ",a[i]); } //Printing addresses within each string location using for loop// printf("The address locations of every string values are : "); for(i=0;i<5;i++){ printf("%d ",a[i]); } }
🌐
Aticleworld
aticleworld.com β€Ί home β€Ί pointer to string array in c, you should know
Pointer to string array in C, you should know - Aticleworld
February 25, 2023 - Similar to the 2D array we can create the string array using the array of pointers to strings. Basically, this array is an array of character pointers where each pointer points to the string’s first character.
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί c language β€Ί array-of-pointers-to-strings-in-c
Array of Pointers to Strings in C - GeeksforGeeks
November 14, 2025 - Each array element will act as a pointer to the first character of an individual string.
🌐
CodinGeek
codingeek.com β€Ί home β€Ί array of pointers to string - c programming language
Array of pointers to string in C Language | Codingeek
February 24, 2021 - As we take the first input the length of the string is calculated using the function strlen() and stored in the variable l. This is done so that we can dynamically allocate memory to the pointer array for storing the strings.
🌐
Scaler
scaler.com β€Ί home β€Ί topics β€Ί string pointer in c
String Pointer in C - Scaler Topics
January 16, 2024 - Arrays are essentially continuous ... string in a pointer variable, we need to create a char type variable and use the asterisk * operator to tell the compiler the variable is a pointer....
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί c language β€Ί array-of-strings-in-c
Array of Strings in C - GeeksforGeeks
July 23, 2025 - It leads to so much wastage of space. But we can avoid this wastage in our program by using array of pointers to strings. In C we can use an Array of pointers instead of having a 2-Dimensional character array.
🌐
Dyclassroom
dyclassroom.com β€Ί c β€Ί c-pointers-and-strings
C - Pointers and Strings - C Programming - dyclassroom | Have fun learning :-)
The pointer variable strPtr is at memory location 8000 and is pointing at the string address 5000. The temporary variable is also assigned the address of the string so, it too holds the value 5000 and points at the starting memory location of ...
Top answer
1 of 2
11

The issue is that you are not allocating any space for those names. You need to initialize each element in the array if you intend to use it with scanf.

char* names[6];
for( int i = 0; i < 6; ++i )
    names[i] = malloc( 256 * sizeof *names[i] ); // or some other max value

scanf( "%s", names[1] );

Otherwise those pointers will be pointing anywhere in your memory, and attempting to read/write those locations will eventually result in a segmentation fault.

2 of 2
5

In your code names is an array of 6 pointers to char. Now each of these pointers can store the starting point (the address of the first character) of a new string. This means you can store the starting addresses of 6 different strings in your names variable.

But when you use a loop to initialize each of these strings, you need to inform the machine HOW long each string might be, so that it can allocate a continuous block of addresses whose first address can then be stored in your pointer to refer to your string. Thus, you must allocate a certain size you think should be sufficient to store your string (eg: 256 bytes, 1 byte being 1 character). In the absence of this, the machine doesn't know where to store all the bytes of your string and throws a segmentation fault due to illegal memory access.

Thus to do this, each of your 6 pointers must be allocated some space to store a string. This will be done in your loop using malloc(). Based on @K-ballo's code:

char* names[6];
int max_length = 256; // The maximum length you expect
for( int i = 0; i < 6; ++i )
    names[i] = malloc( max_length * sizeof(char) ); // allocates max_length number of bytes

scanf( "%s", names[1] );

So now you basically have a 6 different blocks of max_length continuous char addresses that are each referred to by names[i]. When you do the scanf() it reads the bytes from standard input and puts then into these allocated bytes in memory referred to by names[1].

I had a difficult time at the start understanding all this, so just thought an elaborate explanation would help. :)

🌐
Cprogramming
cboard.cprogramming.com β€Ί c-programming β€Ί 129552-pointer-array-strings.html
pointer to array of strings
what do you think of this memory allocation and free, using function: I have problem with sizeof function, it always return 4 byte, i guess because pc is 32 bit, how to get the size dinamically of these array and pointer?? ... #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> char **arr( char *s[], char *p[] ); int main () { char **pointer; int size = sizeof(pointer); pointer = malloc(size * sizeof(char *)); char *p[] = { "cane", "dog", "gatto", "cat" }; int size1 = sizeof(p)/sizeof(size1); char **c; c = arr( p, pointer); int size2 = sizeof(c); printf("size=%d\nsize
🌐
Stack Overflow
stackoverflow.com β€Ί questions β€Ί 73292290 β€Ί creating-a-pointer-to-an-array-of-strings-in-c
Creating a pointer to an array of strings in C - Stack Overflow
The correct pointer declaration is char (*suits)[9] = a; which says that suits is a pointer to an array of characters of length 9. ... void printString(size_t cols, char (*strings)[cols], size_t pos) { printf("Printing in function: String at ...
🌐
Reddit
reddit.com β€Ί r/c_programming β€Ί pass pointer to array of strings? (stumped)
r/C_Programming on Reddit: Pass pointer to array of strings? (Stumped)
February 9, 2024 -

I've tried everything! I've never been this stuck!

static char file[ROWS][LENGTH];
void loadFile(FILE* file, char** buffer){
      // load the file
}
void saveFile(FILEI* file, char** buffer){
      // save the file
}

int main(){
      FILE* theFile = fopen("the path.txt", "r");
      loadFile(theFile, file);
      fclose(theFile);
      return 0;
}

I've tried using char** buffer, char* buffer[], char* buffer[][] in the function prototype

and I've tried passing file, &file[0], file[], &file into the function call.

but I get "warning: passing argument 2 of 'loadFile' from incompatible pointer type"

I need a way to make file[ROWS][LENGTH]; work. How do I do this?

🌐
Villanova
csc.villanova.edu β€Ί ~mdamian β€Ί Past β€Ί csc8400fa15 β€Ί notes β€Ί 05_Pointers.pdf pdf
1 CSC 8400: Computer Systems Pointers, Arrays and Strings in C Overview
ADDRESS-OF operator. ... Logically, there is no a[6]! ... Arrays: C vs. Java ... C Does Not Do Bounds Checking! ... Stack vs. Data ... Arrays vs. Pointers ... All these declarations are equivalent! Try them out. ... C vs. Java Strings ... Do not use strlen in your code.
Top answer
1 of 15
305

If you don't want to change the strings, then you could simply do

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

When you do it like this you will allocate an array of two pointers to const char. These pointers will then be set to the addresses of the static strings "blah" and "hmm".

If you do want to be able to change the actual string content, the you have to do something like

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

This will allocate two consecutive arrays of 14 chars each, after which the content of the static strings will be copied into them.

2 of 15
251

There are several ways to create an array of strings in C. If all the strings are going to be the same length (or at least have the same maximum length), you simply declare a 2-d array of char and assign as necessary:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

You can add a list of initializers as well:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

This assumes the size and number of strings in the initializer match up with your array dimensions. In this case, the contents of each string literal (which is itself a zero-terminated array of char) are copied to the memory allocated to strs. The problem with this approach is the possibility of internal fragmentation; if you have 99 strings that are 5 characters or less, but 1 string that's 20 characters long, 99 strings are going to have at least 15 unused characters; that's a waste of space.

Instead of using a 2-d array of char, you can store a 1-d array of pointers to char:

char *strs[NUMBER_OF_STRINGS];

Note that in this case, you've only allocated memory to hold the pointers to the strings; the memory for the strings themselves must be allocated elsewhere (either as static arrays or by using malloc() or calloc()). You can use the initializer list like the earlier example:

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

Instead of copying the contents of the string constants, you're simply storing the pointers to them. Note that string constants may not be writable; you can reassign the pointer, like so:

strs[i] = "bar";
strs[i] = "foo"; 

But you may not be able to change the string's contents; i.e.,

strs[i] = "bar";
strcpy(strs[i], "foo");

may not be allowed.

You can use malloc() to dynamically allocate the buffer for each string and copy to that buffer:

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

BTW,

char (*a[2])[14];

Declares a as a 2-element array of pointers to 14-element arrays of char.

Top answer
1 of 4
12

Given that the code is really simple, I see mostly coding style issues with it.

Instead of this:

char *names[] = {
    "John", "Mona",
    "Lisa", "Frank"
};

I would prefer either of these writing styles:

char *names[] = { "John", "Mona", "Lisa", "Frank" };

// or

char *names[] = {
    "John",
    "Mona",
    "Lisa",
    "Frank"
};

The pNames variable is pointless. You could just use names.

Instead of the while loop, a for loop would be more natural.

This maybe a matter of taste, but I don't think the Hungarian notation like *pArr is great. And in any case you are using this pointer to step over character by character, so "Arr" is hardly a good name. I'd for go for pos instead. Or even just p.

You should declare variables in the smallest scope where they are used. For example *pos would be best declared inside the for loop. In C99 and above, the loop variable can be declared directly in the for statement.

The last return statement is unnecessary. The compiler will insert it automatically and make the main method return with 0 (= success).

Putting it together:

int main(int argc, char *argv[])
{
    char *names[] = { "John", "Mona", "Lisa", "Frank" };
    for (int i = 0; i < 4; ++i) {
        char *pos = names[i];
        while (*pos != '\0') {
            printf("%c\n", *(pos++));
        }
        printf("\n");
    }
} 

Actually it would be more interesting to use argc and argv for something:

int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; ++i) {
        char *pos = argv[i];
        while (*pos != '\0') {
            printf("%c\n", *(pos++));
        }
        printf("\n");
    }
} 
2 of 4
9

Other points not already mentioned:

Use const where possible

It's better to use const where possible so that it's clear when you are intending to modify things and clear when you're not. This helps the compiler help you find bugs early.

Avoid magic numbers

It's better to avoid having numbers like 4 in the program. If you want to change things later, you may well be left wondering "why 4? what does that mean?" Better would be to assign a constant with a meaningful name.

Use putchar rather than printf for single characters

The printf function is very useful, but putchar is often better suited for single-character output. The reason is that printf has to, at runtime, parse the format string, apply the arguments and then emit the results, while putchar only has to pass a character directly to the output. This particular code isn't exactly performance-critical but it's useful to acquire good coding habits from the beginning.

Use C idioms

It's more idiomatic C to have a loop like this for the characters:

while(*pArr) { /* ... */ }

rather than this:

while(*pArr != '\0') { /* ... */ }

Consider using a "sentinel" value for the end of a list

There are two common ways to iterate through a list in C. One is as you already have it, when you know how many values are in the list. The other way is to use a "sentinel" value -- some unique value that tells the program "this is the end of the list." For a list of names such as this program has, a rational choice for a sentinel value would be NULL.

Omit the return 0 from the end of main

Uniquely for main, if the program gets to the end of the function, it automatically does the equivalent of return 0 at the end, so you can (and should) omit it.

Result

Using all of these suggestions, one possible rewrite might look like this:

#include <stdio.h>

int main() 
{
    const char *names[] = { "John", "Mona", "Lisa", "Frank", NULL };

    for (int i=0; names[i]; ++i) {
        const char *ch = names[i]; 
        while(*ch) {
            putchar(*ch++);
            putchar('\n');
        }
        putchar('\n');
    }
} 
🌐
OverIQ
overiq.com β€Ί c-programming-101 β€Ί array-of-strings-in-c
Array of Strings in C - C Programming Tutorial - OverIQ.com
The ch_arr is a pointer to an array of 10 characters or int(*)[10]. Therefore, if ch_arr points to address 1000 then ch_arr + 1 will point to address 1010. ... ch_arr + 0 points to the 0th string or 0th 1-D array. ch_arr + 1 points to the 1st string or 1st 1-D array.
🌐
DataFlair
data-flair.training β€Ί blogs β€Ί string-using-pointers-in-c
String using Pointers in C - DataFlair
March 9, 2024 - Here, the size of the array is automatically set based on the size of the string literal. If we declare the array size equal to the string length, the null terminator will be missing. This can cause undefined behavior when trying to print or traverse the string. char str[5] = "String"; // Missing null terminator Β· The first element in an array’s name corresponds to its memory location so that we can establish a pointer to the string’s initial character.
🌐
Reddit
reddit.com β€Ί r/c_programming β€Ί what are array of pointers?
r/C_Programming on Reddit: What are Array of Pointers?
December 17, 2024 -

So i am learning command lines arguments and just came cross char *argv[]. What does this actually do, I understand that this makes every element in the array a pointer to char, but i can't get around as to how all of this is happening. How does it treat every other element as another string? How come because essentialy as of my understanding rn, a simple char would treat as a single contiguous block of memory, how come turning this pointer to another pointer of char point to individual elements of string?

Top answer
1 of 16
79
If you have something like const char *argv[] = {"./a.out", "hello", NULL}; You get this in memory: argv β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ptr β”œβ”€β”€β”€β–Ίβ”‚ ./a.out β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ ptr β”œβ”€β” β”œβ”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ NULL β”‚ └─►│ hello β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ You can see that the "./a.out" and "hello" are stored in other places in memory, not inside the array. That’s what a pointer isβ€”a value that can point to another location in memory. Or it can be NULL, which does not point to anything.
2 of 16
13
The only thing that’s guaranteeing is contiguous are the double pointers. If you dereference the first element, that is a pointer to a char, and there might be more chars further along if you move down that row with pointer arithmetic. Dereferencing your second element would be a pointer to another char which might make up a string along that row too (if you defined it as such). Those derefenced pointers have no reason to be contiguous in memory. It’s just that the pointers for themselves are. The only contiguity guarantee here from that statement alone is the array of pointers to char *.