But I am wondering how to initialize char *** in c.
initialize char* :
char *test = "hello";
printf("tets[0]=%s\n",test);
The following is initialize char **.
char **test = (char *[]) {"hello", "world"};
printf("tets[1]=%s\n",test[1]);
So far I tried to initialize char ***:
// char ***test = (*(char *[])) {{"hello"}, {"world"}};
//char ***test = ((char **)[]) {{"hello"}, {"world"}};
Intended to achieve, initialize a char*** using text string literal.
Then i can use printf("tets[1]=%s\n",(*test)[1]) to print out world.
It is possible to additionally create a compound literal which is simply an object of type char** which points to the first element of the array you defined in the question, and make the char *** point to this char ** object:
#include <stdio.h>
int main( void )
{
char ***test = &(char**){ (char *[]){"hello", "world" } };
printf( "test[1]=%s\n", (*test)[1] );
}
This program has the desired output world.
However, adding this additional layer of indirection does not make much sense. It would make more sense to simply use a char** instead of a char***, as you did in the code in your question.
I can't come up with any scenario when such code would make any sense. Literally the only place in C where char*** can perhaps be justified, is when returning a pointer-to-pointer through a function parameter. Every other use of char*** is very likely caused by muddy or incorrect program design.
If you wish to implement a 2D array of pointers (without using structs, as would perhaps be a good idea), then the correct way would be to use a 2D array: char* array[X][Y]. And in case pointing at string literals, also make it const. Then you can point at that 2D array row by row:
Example of code that might actually make sense:
#include <stdio.h>
#define X 2
#define Y 2
int main()
{
const char* (*strtable) [Y] =
(const char* [X][Y])
{
{ "hello", "world" },
{ "testing", "testing" },
};
for(size_t i=0; i<X; i++)
{
for(size_t j=0; j<Y; j++)
{
printf("%-10s ", strtable[i][j]);
}
printf("\n");
}
}
You can have compound literal containing compound literals.
char *test = "hello";
printf("tets[0]=%s\n",test);
char **test1 = (char *[]) {"hello", "world"};
printf("tets[1]=%s\n",test1[1]);
char ***test2 = (char **[]){(char *[]) {"hello", "world"}, (char *[]) {"something", "else"}};
printf("tets[1]=%s\n",test2[1][1]);
char **elem1 = (char *[]) {"hello", "world"};
char **elem2 = (char *[]) {"something", "else"};
char ***test3 = (char **[]){elem1, elem2};
printf("tets[1]=%s\n",test2[1][0]);
/* --- or **** */
char ****test4 = (char ***[]){ (char **[]){(char *[]) {"hello", "world"}, (char *[]) {"something", "else"}},
(char **[]){(char *[]) {"four", "pointer"}, (char *[]) {"programmer", "king"}}};
printf("tets[1]=%s\n",test4[1][1][0]);
Related
I am new to programming and C in general and the last few weeks I try to get the concept of pointers, arrays and how they are connected.
At the moment I experiment with command line arguments in C and I read here on this platform that argv can be syntactically defined differently, however the semantic stays the same.
int main(int argc, char *argv[])
is equal to
int main(int argc, char **argv)
Okay, but why is my code behaving differently when I try to initialize an array in these ways:
char *s[] = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get as output as expected: o and 3.
But when I initialize the array like
char **s = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get a segmentation fault or other errors which I cannot understand like (near initialization for āsā)
I guess you cannot initialize an pointer to a pointer array with 2 asterisks.
Maybe someone can provide me with more information about these relation and how these 2 definitions differ from each other.
They are completely different:
char *s[]
is an array of pointers. Arrays cannot be assigned or used as values
This code will not compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
a++;
}
void bar(void)
{
a1 = a;
}
char **s
is a pointer to a pointer and can be assigned or used as an lvalue.
This code will compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
s++;
}
void bar(void)
{
s1 = s;
}
https://godbolt.org/z/vqxv913WY
I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I've been going through Kernighan and Ritchie book in C and got lost in pointers to pointers that point to char arrays.
Let's take this sample code:
char str1[] = "This ";
char str2[] = "is ";
char str3[] = "a cat.";
char *ptr1 = str1;
char *ptr2 = str2;
char *ptr3 = str3;
char *ptrall[] = { ptr1, ptr2, ptr3 };
Question:
How do I print all of the arrays using, say, while?
The book tells me (quote):
while (...){
printf("%s\", *ptr++);}
So, this *ptr++ is supposed to increment pointers within **ptr. But When I try to build it in VS it says there's the "lvalue" mistake.
What do I misunderstand here? How should I increment pointers stored in **?
Am I limited to printf("%s", ptr[i++]) only?
Question: How do I print all of the arrays using, say, while?
It depends on how the array ptrall is defined.
If the array ptrall is defined like
char *ptrall[] = { ptr1, ptr2, ptr3, NULL };
then it can be outputted the following way using a while loop
#include <stdio.h>
int main( void )
{
char str1[] = "This ";
char str2[] = "is ";
char str3[] = "a cat.";
char *ptr1 = str1;
char *ptr2 = str2;
char *ptr3 = str3;
char *ptrall[] = { ptr1, ptr2, ptr3, NULL };
char **ptr = ptrall;
while (*ptr) printf("%s", *ptr++);
putchar('\n');
return 0;
}
The program output is
This is a cat.
If the array ptrall is defined as in your question that is like
char *ptrall[] = { ptr1, ptr2, ptr3 };
then it can be outputted the following way using a while loop
#include <stdio.h>
int main( void )
{
char str1[] = "This ";
char str2[] = "is ";
char str3[] = "a cat.";
char *ptr1 = str1;
char *ptr2 = str2;
char *ptr3 = str3;
char *ptrall[] = { ptr1, ptr2, ptr3 };
char **ptr = ptrall;
while (ptr != ptrall + sizeof( ptrall ) / sizeof( *ptrall ) ) printf("%s", *ptr++);
putchar('\n');
return 0;
}
The program output is the same as shown above.
As for the expression used in this call
printf("%s", *ptrall++);
then array designators are non-modifiable lvalues. You may not apply preincrement and postincrement operators to an array designator.
To use this you need to terminate your array of pointers;
char *ptrall[] = {ptr1, ptr2, ptr3, NULL};
for(char**ptr=ptrall;*ptr;) printf("%s\n",*ptr++);
Here is my code:
#include <stdio.h>
#include<stdlib.h>
char *s = (char *)malloc (40);
int main(void)
{
s="this is a string";
printf("%s",s);
}
I am getting the following error:
error: initializer element is not constant char *s = (char *)malloc
(40);
You don't need to allocate memory in this way if you wanna initialize it in code, I mean:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *s = "this is a string"; // char s[] = "this is a string";
printf("%s",s);
return 0;
}
is just enough in this case. If you really want to assign const char string to your char array, this topic should enlighten you: Dynamically allocating memory for const char string using malloc()
You cannot not do that.
You can do this instead -
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
char *s; // probably should avoid using global variables
int main(void)
{
s=malloc(40);
strcpy(s,"this is a string");
printf("%s",s);
free(s);
}
Other than this inside main you can do this -
char *s="this is a string"; //string literal you can't modify it
Or
char s[]="this is a string"; // modifiable string
You assign a pointer to a string constant to a variable, s, which is not declared to point to a constant. This is what you want:
#include <stdio.h>
int main(void)
{
const char *s = "this is a string";
printf("%s\n", s);
return 0;
}
In C there are basically three ways to declare "string" variables.
String constant pointers
If you need a name for a string that will not change, you can declare and initialize it like
const char *s = "a string";
Character arrays
If you need a string variable and you know in advance how long it needs to be you can declare and initialize it like
char s[] = "a string";
or like
char s[9];
strcpy(s, "a string");
Character sequence pointers
If you don't know in advance how large the array needs to be, you can allocate space during program execution:
char *s;
s = malloc(strlen(someString) + 1);
if (s != NULL) {
strcpy(s, someString);
}
The "+1" is to make room for the null character (\0).
Can someone please explain to me what's wrong with the following, and more importantly why?
int main( int argc, char *argv[] )
{
char array[] = "array";
char **test;
test = &array;
*test[0] = 'Z';
printf( "%s\n", array );
return 0;
}
EDIT
My example above was based on a function like this that was crashing:
void apple( char **pp )
{
*pp = malloc( 123 );
*pp[0] = 'a'; // technically this is correct but in bad form
*pp[1] = 'b'; // incorrect but no crash
*pp[2] = '\0'; // incorrect and crash
}
As pointed out to me by Vaughn Cato although *pp[0] = 'a'; does not crash it is in bad form. The correct form is the parenthesis
void apple( char **pp )
{
*pp = malloc( 123 );
(*pp)[0] = 'a'; // correct
(*pp)[1] = 'b'; // correct
(*pp)[2] = '\0'; // correct
}
Also as another poster MK pointed out the FAQ covers the difference between arrays and pointers:
http://www.lysator.liu.se/c/c-faq/c-2.html
test = &array
is wrong because test is of type char** and &array is a char(*)[6] and is a different type from char**
An array isn't the same type as char* although C will implicitly convert between an array type and a char* in some contexts, but this isn't one of them. Basically the expectation that char* is the same as the type of an array (e.g: char[6]) is wrong and therefore the expectation that taking the address of an array will result in a char** is also wrong.
This would be the way to do what you seem to be trying to do:
int main( int argc, char *argv[] )
{
char array[] = "array";
char (*test)[6];
test = &array;
(*test)[0] = 'Z';
printf( "%s\n", array );
return 0;
}
test is a pointer to an array, and an array is different from a pointer, even though C makes it easy to use one like the other in my cases.
If you wanted to avoid having to specify a specific sized array, you could use a different approach:
int main( int argc, char *argv[] )
{
char array[] = "array";
char *test;
test = array; // same as test = &array[0];
test[0] = 'Z';
printf( "%s\n", array );
return 0;
}
char **test; is a pointer to a pointer, but if you're going to take the address of an entire array then it needs to be a pointer to entire array i.e char (*test)[6];