Incrementing pointers to pointers in C [closed] - c

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++);

Related

how to initialize char *** from string liertal

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]);

Quesion regarding pointers in C [duplicate]

This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 1 year ago.
void fun1(char *s1, char *s2) {
char *temp;
temp = s1;
s1 = s2;
s2 = temp;
}
int main () {
char *str1 = "Hello", *str2 = "there!"
fun1(str1, str2);
printf("%s %s", str1, str2);
return 0;
}
Given the code above, from my understand we pass the pointers by value, so if for example the values are str1 = 1000, str2 = 2000, fun1 switches them around, so str1 = 2000, str2 = 1000.
So when we are trying to print them, we should get "there! Hello", but the answers says that it prints "Hello there!" and I don't understand why.. by switching them around str1's value should be the memory adress of the first character of "there!" and str2 of the first character of "Hello"..
I feel like I'm missing something important..
The pointers are passed by value, so switching values of s1 and s2 will not affect str1 and str2.
If you want functions modify what caller specifies, you should pass pointers to what should be modified like this:
#include <stdio.h>
void fun1(char **s1, char **s2) {
char *temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
int main (void) {
char *str1 = "Hello", *str2 = "there!"
fun1(&str1, &str2);
printf("%s %s", str1, str2);
return 0;
}

Why did I get EXC_BAD_ACCESS?

I want to reverse a string, but I got a error on swap char.
Could someone help me with this?
char* reverse_char(char* src){
char *p,*q;
p = q = src;
while(*(p) != '\0'){
p++;
}
p--;
char temp = '\0';
while (p > q) {
temp = *p;
*p = *q; // I got exec bad access here ??? why
*q = temp;
p--;
q++;
}
return src;
}
This is the main method.
int main(int argc, char const* argv[])
{
char *hi = "hello world!\n";
printf("%s", hi);
reverse_char(hi);
printf("%s", hi);
return 0;
}
Replace char *hi = "hello world!\n"; with char hi[] = "hello world!\n";
"hello world!\n" is string literal and may not be writable causing the access error. Modifying the contents of string literal is undefined behavior, it may write the contents silently, raise an access error or may do something else unexpected. (So you should not write to string literal)
Summing up
char a[] = "..."; /* Contents of a can be assigned */
char *a = "..."; /* Writing to contents of memory pointed by a leads to UB */
Though string literals in C have types of non-const character arrays they may not be changed.
From the C Standard (6.4.5 String literals)
7 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.
it is better to declare a pointer initialized with a string literal as having type const char * as it is done in C++. For example
const char *hi = "hello world!\n";
In this case instead of a run-time error you would get a compile-time error that would be understandable because the parameter of the function is declared as a non-const character pointer.
You have to use a character array instead of a pointer to a string literal.
For example
char hi[] = "hello world!\n";
As for the function that it has some problem when a pointer points to an empty string. In this case after operation
p--;
you can get invalid pointer that is not necessary less than src.
I would write the function the following way
char* reverse_string( char *s )
{
char *p = s;
while ( *p ) ++p;
if ( p != s )
{
for ( char *q = s; q < --p; ++q )
{
char c = *q;
*q = *p;
*p = c;
}
}
return s;
}

Why char value copy won't work in OS X?

It's a textbook C code
void strcpy_new(char *s, char *t) {
while ((*s = *t) != '\0') {
s++;
t++;
}
}
int main(int argc, const char * argv[])
{
char *s = "this is line a";
char *t = "this is line b";
printf("%s", s);
strcpy_new(s, t);
printf("%s", s);
return 0;
}
when I run it with Xcode, I got EXEC_BAD_ACCESS.
The reason you get EXEC_BAD_ACCESS is because those string literals "this is line a" and "this is line b" are stored in read-only memory. Attempting to write to it (*s = *t) is undefined behavior and you are receiving a crash because of it.
To remedy this code you should allocate some memory for s so that it is large enough to hold the second string (t):
char s[] = "this is line a"; // contrived example, s and t are the same length
char *t = "this is line b";
strcpy_new(s, t);
I'm willing to bet that you're trying to run strcpy_new with a destination char *s that is a string literal
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char *b = "Another string";
strcpy(b, a);
return 0;
}
will give an EXEC_BAD_ACCESS. The following, however, won't
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char b[] = "Another string";
strcpy(b, a);
return 0;
}
The difference is that in the first case, b points to a block of memory in the __TEXT,__cstring,cstring_literals section of the executable, which is write protected. In the second case, it points to a block of memory on the stack.
The problem is that the effect of overwriting a string literal is undefined.
char *s = "this is line a";
char *t = "this is line b";
strcpy_new(s, t);
s and t are both off in the data section of the code, and your particular setup happens to give you an EXEC_BAD_ACCESS when you try changing them.
String literal are read-only. A good answer is found here: http://ubuntuforums.org/showthread.php?t=357869
String literals in C are read-only. In your sample code, "My string" is a string literal.
The str[] declaration copies the literal into writable memory (stack or heap). Therefore, your program can modify the string.
The * declaration initializes a pointer to the literal itself, so you have a pointer to a read-only segment. If you try to overwrite it, you get the SEGV.

C - 'char **' differs in levels of indirection from 'char (*)[6]'

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];

Resources