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 Overflowc - Char ** usage and printing - Stack Overflow
How to make return char function in c programming? - Stack Overflow
array - Difference between char and char* in c - CS50 Stack Exchange
Char **
Videos
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.
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.
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".
C99 N1256 draft
There are two different uses of character string literals:
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,
ccan be modified.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[]tochar *, 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
sandtwhose 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
pwith 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 usepto 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
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