The terminology is important here, I think. The char ** doesn't "hold" a series of strings at all (unlike container objects in higher-level languages than C). The variable c is just a pointer to a pointer to a character, and that character is going to be the first character in a nul-terminated string.

This line of thinking leads directly to the solution: If c is a pointer to a pointer to a character, that means we have to allocate some memory in which to actually hold the array of strings.

@DB_Monkey's solution posted as a comment seeks to do this but isn't quite right because it implies that code like c[0] = "cat" copies "cat" into c[0], which isn't so -- the assignment applies to the pointer, not to the string. A better way would be:

int rows = 3;
char **c = calloc (rows,sizeof(char*));
c[0] = "cat";
c[1] = "dog";
c[2] = "mouse";

This also shows that it isn't necessary to show the explicit nul termination of each string.

Answer from Simon on Stack Overflow
🌐
Learn C
learnc.net β€Ί home β€Ί learn c programming β€Ί c character type
C Character Type
April 13, 2025 - A character literal contains one character that is surrounded by a single quotation ( '). The following example declares key character variable and initializes it with a character literal β€˜Aβ€˜:
🌐
W3Schools
w3schools.com β€Ί c β€Ί c_data_types_characters.php
C Character Data Types
C Examples C Real-Life Examples C Exercises C Quiz C Code Challenges C Practice Problems C Compiler C Syllabus C Study Plan C Interview Q&A ... The char data type is used to store a single character.
Discussions

c - Char ** usage and printing - Stack Overflow
In C, I am using a char ** to hold a series of strings. Here is my code: char ** c; //now to fill c with data ???? //cannot change: printf ("%*s%s", 0, "", *c); while (*++w) printf (" %s", *... More on stackoverflow.com
🌐 stackoverflow.com
How to make return char function in c programming? - Stack Overflow
I'm Trying to do some simple c programming that will return the char value. The program is running with no error but, the output of the expected string does not appear. What I expected it will retu... More on stackoverflow.com
🌐 stackoverflow.com
array - Difference between char and char* in c - CS50 Stack Exchange
The difference between char* the pointer and char[] the array is how you interact with them after you create them. If you are just printing the two examples, it will perform exactly the same. More on cs50.stackexchange.com
🌐 cs50.stackexchange.com
February 21, 2015
Char **
Yes, this is a pointer to a pointer. As you might already know, pointers are also used to represent arrays. char** is therefore often times an array consisting of char arrays or in other terms: an array of c strings. Using a pointer to a pointer, you can use the normal [.] to access elements in the array and still get char* instances (aka c strings) to work with instead of just one single char. More on reddit.com
🌐 r/C_Programming
12
16
March 31, 2019
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί c language β€Ί unsigned-char-in-c-with-examples
unsigned char in C with Examples - GeeksforGeeks
July 12, 2025 - unsigned char: a Initializing an unsigned char with signed value: Here we try to insert a char in the unsigned char variable with the help of ASCII value. So the ASCII value -1 will be first converted to a range 0-255 by rounding.
🌐
OpenGenus
iq.opengenus.org β€Ί character-in-c
Working with character (char) in C
July 15, 2019 - Open-Source Internship opportunity by OpenGenus for programmers. Apply now. ... C uses char type to store characters and letters. However, the char type is integer type because underneath C stores integer numbers instead of characters.In C, char values are stored in 1 byte in memory,and value range from -128 to 127 or 0 to 255.
Top answer
1 of 3
8

The terminology is important here, I think. The char ** doesn't "hold" a series of strings at all (unlike container objects in higher-level languages than C). The variable c is just a pointer to a pointer to a character, and that character is going to be the first character in a nul-terminated string.

This line of thinking leads directly to the solution: If c is a pointer to a pointer to a character, that means we have to allocate some memory in which to actually hold the array of strings.

@DB_Monkey's solution posted as a comment seeks to do this but isn't quite right because it implies that code like c[0] = "cat" copies "cat" into c[0], which isn't so -- the assignment applies to the pointer, not to the string. A better way would be:

int rows = 3;
char **c = calloc (rows,sizeof(char*));
c[0] = "cat";
c[1] = "dog";
c[2] = "mouse";

This also shows that it isn't necessary to show the explicit nul termination of each string.

2 of 3
4

your char** is actually a number which thinks that number is an address of a number which is an address of a valid character...

to put it simply:

// I am a number that has undefined value, but I pretend to point to a character.
char *myCharPointer;
// | The statement below will access arbitrary memory
// |   (which will cause a crash if this memory is not allowed to be accessed).
char myChar = *myCharPointer; 

To make use of this pointer, you have to initialize it.

char *myCharPointer = (char *)malloc(10 * sizeof(char));

now, you can use this pointer in the same way you deal with arrays, or due pointer arithmetic if you want.

Note that malloc does not set all values in the "array" to 0, their values are undefined by default.

In order to do what you want to do, you have to do the following:

// I can store 10 "strings"
char **myArrayOfStrings = (char **)malloc(10 * sizeof(char *));
char *str0 = "Hello, world0";
char *str1 = "Hello, World1";
char *str2 = "Hello, World2";
char *str3 = "Hello, world3";
char *str4 = "Hello, world4";
char *str5 = "Hello, world5";
char *str6 = "Hello, world6";
char *str7 = "Hello, world7";
char *str8 = "Hello, world8";
char *str9 = "Hello, world9";
myArrayOfStrings[0] = str0;
myArrayOfStrings[1] = str1;
myArrayOfStrings[2] = str2;
myArrayOfStrings[3] = str3;
myArrayOfStrings[4] = str4;
myArrayOfStrings[5] = str5;
myArrayOfStrings[6] = str6;
myArrayOfStrings[7] = str7;
myArrayOfStrings[8] = str8;
myArrayOfStrings[9] = str9;
// the above is the same as
// *(myArrayOfStrings + 9) = str9

You don't have to have the strings of same length of anything, suppose str[0..9] are actually numbers that store the address of where the first character of these strings is located in memory, eg

str0 = (char *)&9993039;
str1 = (char *)&9993089;

myArrayOfStrings is actually also a number which stores the address of the first string location, in particularmyArrayOfStrings = (char **)&str0;

Obviously, you will not do this explicitly as I shown, but this can be done at runtime without much issue, just store a string from the user in the buffer, then append it to the list, hoping that it doesn't run out of space (there are techniques to avoid that).

Hopefully this helped.

🌐
PREP INSTA
prepinsta.com β€Ί home β€Ί all about c language β€Ί char data type in c
Char Data Type in C | PrepInsta
January 19, 2023 - On this page you will find about the char data type which is used in C, it's declaration and initialization, types, along with example code.
🌐
Medium
medium.com β€Ί @mazen.elheni β€Ί unsigned-char-in-c-with-examples-efa3db909c71
Unsigned char in C with Examples. char is the most basic data type in C… | by Mazen Elheni | Medium
February 5, 2025 - β€˜a’ and it will be inserted in unsigned char. // C program to show unsigned char #include <stdio.h> int main() { int chr = 97; unsigned char i = chr; printf("unsigned char: %c\n", i); return 0; }
Find elsewhere
🌐
W3Schools
w3schools.com β€Ί c β€Ί ref_keyword_char.php
C char Keyword
A char value must be surrounded by single quotes, like 'A' or 'c'. The signed and unsigned keywords treat the char as an integer type. A signed char can represent values between -128 and 127.
🌐
TutorialsPoint
tutorialspoint.com β€Ί cprogramming β€Ί c_character_pointers_and_functions.htm
Character Pointers and Functions in C
When the first not-matching character in str1 has a lesser ASCII value than the corresponding character in str2, the function returns a negative integer. It implies that str1 appears before str2 in alphabetical order, as in a dictionary. The following example demonstrates how you can use the strcmp() function in a C program βˆ’
🌐
Dremendo
dremendo.com β€Ί c-programming-tutorial β€Ί c-character-variable
How to Declare and Use Character Variables in C Programming | Dremendo
Declare a character variable x and assign the character '$' and change it value to @ in the next line. char x = '$'; x = '@'; //now the new value of x is @ Attempt the multiple choice quiz to check if the lesson is adequately clear to you.
🌐
GitHub
github.com β€Ί jeffotoni β€Ί c-char
GitHub - jeffotoni/c-char: Small examples to understand how char type works in C Β· GitHub
/** * * @author @jeffotoni * @copyright Copyright (c) 2017 * * Different ways to declare a string using char * */ #include <stdio.h> #include <stdlib.h> #include <string.h> /** * * Defining typedef of type char as vector * */ typedef char string[]; /** * * Defining typedef of char type as vector pointer * */ typedef char *string2[]; /** * * Defining typedef of type char as pointer * */ typedef char *string3; /** * * Main function * */ int main(){ /** * * Defining a pointer with char and assigning a value * */ char *stringx = "Avocado is delicious."; /** * * Defining a char pointer statically *
Author Β  jeffotoni
🌐
DEV Community
dev.to β€Ί wacimdev β€Ί understanding-char-in-cc-1852
Understanding char** in C/C++ - DEV Community
October 9, 2024 - Main Index (char**) β†’ String 1 (char*) β†’ "I love" β†’ String 2 (char*) β†’ "Embedded" β†’ String 3 (char*) β†’ "Systems" ... Each element of the array points to the first character of a string literal.
Top answer
1 of 2
50

The difference between char* the pointer and char[] the array is how you interact with them after you create them.

If you are just printing the two examples, it will perform exactly the same. They both generate data in memory, {h, e, l, l, o, /0}.

The fundamental difference is that in one char* you are assigning it to a pointer, which is a variable. In char[] you are assigning it to an array which is not a variable.

char[] is a structure, it is specific section of memory, it allows for things like indexing, but it always will start at the address that currently holds 'h'.

char* is a variable. It was initialized with a number, but we can change this number using mathematical operators such as ++, because it is essentially an integer.

So here's one example, where the pointer would be much more efficient than an array. Say, for whatever reason we wanted the string to say "ello" instead of "hello". With a pointer all we need to do is to shift the pointer one position to the "right".

char* p = "hello";
p++;

This is a very fast operation and runs in Big O of 1 (literally, in this case it is a single very fast operation)

But with char[], we can't change where the array starts, therefore we actually need to do something much less efficient. We need to loop through the entire word and for every index change the char in memory. It would look something like this. (manually done instead of looping for clarity)

char s[] = "hello";
s[0] = 'e';
s[1] = 'l';
s[2] = 'l';
s[3] = 'o';
s[4] = '/0';

This is a far slower operation running in "big O of n".

2 of 2
8

C99 N1256 draft

There are two different uses of character string literals:

  1. Initialize char[]:

    char c[] = "abc";      
    

    This is "more magic", and described at 6.7.8/14 "Initialization":

    An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

    So this is just a shortcut for:

    char c[] = {'a', 'b', 'c', '\0'};
    

    Like any other regular array, c can be modified.

  2. Everywhere else: it generates an:

    • unnamed
    • array of char https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-c
    • with static storage
    • that gives UB if modified

    So when you write:

    char *c = "abc";
    

    This is similar to:

    /* __unnamed is magic because modifying it gives UB. */
    static char __unnamed[] = "abc";
    char *c = __unnamed;
    

    Note the implicit cast from char[] to char *, which is always legal.

    Then if you modify c[0], you also modify __unnamed, which is UB.

    This is documented at 6.4.5 "String literals":

    5 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence [...]

    6 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

6.7.8/32 "Initialization" gives a direct example:

EXAMPLE 8: The declaration

char s[] = "abc", t[3] = "abc";

defines "plain" char array objects s and t whose elements are initialized with character string literals.

This declaration is identical to

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

The contents of the arrays are modifiable. On the other hand, the declaration

char *p = "abc";

defines p with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

GCC 4.8 x86-64 ELF implementation

Program:

#include <stdio.h>

int main(void) {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

Compile and decompile:

gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

Output contains:

 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

Conclusion: GCC stores char* it in .rodata section, not in .text.

If we do the same for char[]:

 char s[] = "abc";

we obtain:

17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

so it gets stored in the stack (relative to %rbp).

Note however that the default linker script puts .rodata and .text in the same segment, which has execute but no write permission. This can be observed with:

readelf -l a.out

which contains:

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata
🌐
Programiz
programiz.com β€Ί c-programming β€Ί c-strings
Strings in C (With Examples)
Here, we are trying to assign 6 characters (the last character is '\0') to a char array having 5 characters. This is bad and you should never do this. Arrays and strings are second-class citizens in C; they do not support the assignment operator once it is declared. For example,
🌐
Swarthmore College
cs.swarthmore.edu β€Ί ~newhall β€Ί unixhelp β€Ί C_chars.html
char in C
#include <ctype.h> int islower(ch); int isupper(ch); // these functions return a non-zero value if the int isalpha(ch); // test is TRUE, otherwise they return 0 (FALSE) int isdigit(ch); int isalnum(ch); int ispunct(ch); int isspace(ch); char tolower(ch); char toupper(ch); Here are some examples of what they do/return:
🌐
Unstop
unstop.com β€Ί home β€Ί blog β€Ί character set in c | types, uses, evolution & more (+examples)
Character Set In C | Types, Uses, Evolution & More (+Examples)
July 16, 2024 - Each type from the <ctype.h> standard library offering functions that allow us to perform operations like checking character properties and converting characters. For example, functions such as isalpha(), isdigit(), isspace(), and ispunct() help ...
🌐
Newtum
blog.newtum.com β€Ί char-data-type-in-c-2
Char Data Type in C – Memory Size, ASCII Values & Usage Explained - Newtum
June 28, 2025 - It’s commonly used in string manipulation, input/output operations, and when memory optimization is needed. ... In this example, the character 'A' is stored as its ASCII value, which is 65.
🌐
Reddit
reddit.com β€Ί r/c_programming β€Ί char **
r/C_Programming on Reddit: Char **
March 31, 2019 -

Often see this symbol but unclear what it is. Is it a pointer to a pointer?? Already having a hard time with pointers and so this is just too confusing. Why the hell would want to have a pointer to pointer? Could you please explain this? Thanks

Top answer
1 of 5
18
Yes, this is a pointer to a pointer. As you might already know, pointers are also used to represent arrays. char** is therefore often times an array consisting of char arrays or in other terms: an array of c strings. Using a pointer to a pointer, you can use the normal [.] to access elements in the array and still get char* instances (aka c strings) to work with instead of just one single char.
2 of 5
6
Consider this: A pointer is really just an integer value. It's an integer value that references a memory address. A single memory address (known as the first-available byte). We interpret how much memory to read from that first-available byte by using the data type of the pointer. So if I have an int pointer to some memory address 0x00001000 , I would say that some int variable "x" belongs to memory addresses 0x00001000 to 0x00001003 (that's four bytes). That's all there is to it for a pointer. Now as another commenter pointed out, char** is often another way of writing char[] argv in a C main function. They are synonymous with each other. The array syntax "[ ]" is really a syntactic sugar for " ** ". int main(int argc, char argv[]) { //int argc represents the number of strings in an input buffer called "stdin". //char[] or char** argv represents the strings themselves, often used for command line arguments. return 0; } You might be a bit confused as to how an "integer-like value" can reference a memory address. To help aid your confusion let me introduce you to a hardware component known as the Memory Management Unit or MMU for short . When your C code (or any programming language) gets compiled, references to pointers get translated into instructions to the CPU to read or write to some memory address/addresses in RAM (also can be CPU cache memory but ignore this for now if you're not familiar with cache memory yet). So basically the way that it works is that when your C code needs to reference some location in memory, it's handled for you. There's a hardware component called the MMU whose sole purpose is to handle these instructions for you, otherwise the CPU-to-RAM communication model (called the "Von Neumann Architecture") would not be possible. All you need to worry about with pointers is a few things: Since pointers are integer-like we can treat them the same way we would treat integers. This is called pointer-arithmetic. If int* x_ptr, some integer pointer I just made up, points to fictional memory address "1000" (simplified down without 0x notation to make it easier), then doing x_ptr = x_ptr + 1; is the same as doing "1000 + 4*1". We're multiplying by 4 because that's the size of an int value. So to be consistent with memory sizes, when we add 1 we would really be adding four. We multiply the number we're adding by the size of the data type before we add it to the pointer. Normally it's bad practice to work with pointers this way but this is to explain how they work underneath the hood and more importantly why arrays are able to work. Since x_ptr = x_ptr + 1; is the same as doing something like "1000 + 4*1", then x_ptr = x_ptr + 2; is the same as doing something like "1000 + 4*2", because the same logic applies. We do the location of x_ptr + the size of x_ptr * the number we are adding. It may not be immediately obvious but that's the same as saying "int fictional_array[2]". Notice that the number we are adding is the same as the array index. This is how arrays work underneath the hood and if you understand how arrays work, now you understand how pointers to pointers work. So char** argv is really the same thing as char argv[]. 2) You need to check that your pointer does not point to null. A null pointer means a reference to a particular memory address that is basically used to mean "dead-end". Most compilers operate by a principle that if you tried to read a null pointer, your program will crash. This is because the operating system needs to stop programs from trying to read memory that does not belong to the program as this is a general tactic that malicious programs use to damage systems. 3) You need to clean up any dynamic memory you make. Pointers help us keep track of things in memory, they let us know exactly where something is. If we call malloc() or a similar function to find and give us new memory (from what is called the "heap"), we need to free() the memory later to give it back to the system. Failing to do this will leave some memory reserved and unused for as long as your program runs. This is an issue called a "memory leak". Good code practice involves ensuring no memory leaks occur. Hope this helps.
🌐
TutorialsPoint
tutorialspoint.com β€Ί cprogramming β€Ί c_strings.htm
Strings in C
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; C lets you initialize an array without declaring the size, in which case the compiler automatically determines the array size.