pointer-to-pointer to char

J

Jack

The following code can be compiled. But When I run it, it causes
"Segmentation fault".

int main(){
char **c1;

*c1 = "HOW"; // LINE1

++(*c1);
*c1 = "ARE";

++(*c1);
*c1 = "YOU";
}

c1 is a pointer-to-pointer to char. How to initialize c1 to three
strings: "HOW", "ARE", "YOU"?

Thanks a lot.
 
I

Ian Collins

Jack said:
The following code can be compiled. But When I run it, it causes
"Segmentation fault".

int main(){
char **c1;

*c1 = "HOW"; // LINE1
c1 doesn't point to anything...
c1 is a pointer-to-pointer to char. How to initialize c1 to three
strings: "HOW", "ARE", "YOU"?
char *c1[] = { "HOW", "ARE", "YOU" };
 
I

Ian Collins

Ian said:
Jack said:
The following code can be compiled. But When I run it, it causes
"Segmentation fault".

int main(){
char **c1;

*c1 = "HOW"; // LINE1

c1 doesn't point to anything...
c1 is a pointer-to-pointer to char. How to initialize c1 to three
strings: "HOW", "ARE", "YOU"?

char *c1[] = { "HOW", "ARE", "YOU" };
I should have said

const char *c1[] = { "HOW", "ARE", "YOU" };
 
J

Joe Wright

Jack said:
The following code can be compiled. But When I run it, it causes
"Segmentation fault".

int main(){
char **c1;

*c1 = "HOW"; // LINE1

Boom! Crash and burn! c1 is not initialized and *c1 is garbage.
++(*c1);
*c1 = "ARE";

++(*c1);
*c1 = "YOU";
}

c1 is a pointer-to-pointer to char. How to initialize c1 to three
strings: "HOW", "ARE", "YOU"?

Thanks a lot.
#include <stdlib.h>

char **c1 = malloc(3 * sizeof *c1);
c1[0] = "HOW";
c1[1] = "ARE";
c1[2] = "YOU";
 
T

Tomás

char **c1;

*c1 = "HOW";


Most (if not all) novices make this mistake at some stage, but it doesn't
take long before you can spot it from a mile away. Here's a sample:

char *p;

The variable "p" stores a memory address (at which resides a char). You
didn't initialise it, so it contains white noise. Let's say its value is:
8374534.

*p = 'a';


Now you dereference this pointer value, and write to the memory. So
you're writing 'a' to the memory location: 8374534.

You have to give "p" a legitimate value:

char k;

char *p = &k;


Let's say that k is stored at the memory address: 234873. Now p is
storing the value: 234873. This is a legitimate memory location to
access:

*p = 'e';


The crux of the matter is this: When you define a pointer variable,
you're DON'T actually allocate memory for the variable which it points
to. But it's easist to think along the following lines: A "char*" stores
a memory address.


-Tomás
 
J

Joe Wright

Tomás said:
Most (if not all) novices make this mistake at some stage, but it doesn't
take long before you can spot it from a mile away. Here's a sample:

char *p;

The variable "p" stores a memory address (at which resides a char). You
didn't initialise it, so it contains white noise. Let's say its value is:
8374534.

*p = 'a';

The value of an unitialized pointer is of no interest. The above
statement is undefined behavior and may cause segment fault or other error.
Now you dereference this pointer value, and write to the memory. So
you're writing 'a' to the memory location: 8374534.
Please see my comment above.
You have to give "p" a legitimate value:

char k;

char *p = &k;
That's better. p holds the address of k and k is sufficient to hold 'e'.
Let's say that k is stored at the memory address: 234873. Now p is
storing the value: 234873. This is a legitimate memory location to
access:
Again, the actual value of a pointer is of no interest.
*p = 'e';
This works and now (k == 'e') is true.
The crux of the matter is this: When you define a pointer variable,
you're DON'T actually allocate memory for the variable which it points
to. But it's easist to think along the following lines: A "char*" stores
a memory address.
More correctly, an object of type char* may contain the address of an
object of type char.
 
T

Tomás

Joe Wright posted:

The value of an unitialized pointer is of no interest.


It is for the purpose of my tutorial -- it gives the original poster a
concrete, down-to-earth example of what's going on. When you don't
initialise a variable, it sort of has a random value (which may not even
be a valid bit-pattern for the given type).

The above
statement is undefined behavior and may cause segment fault or other
error.


Congratulations, you understand.

That's better. p holds the address of k and k is sufficient to hold
'e'.


Should I presume that the remainder of your post simply repeats every
point I made in my previous post?

This works and now (k == 'e') is true.


An inaccurate method of testing. I bet you I could get the following to
work on my system:

char *p;

*p = 'e';

if ( *p == 'e' ) NaivelyIndicateSuccess();

More correctly, an object of type char* may contain the address of an
object of type char.


(Maybe I'm getting mixed up with C and C++ here, but in C++, you can use
a char* to access ANY memory. Would you have to use an unsigned char* in
C?)


-Tomás
 
J

Joe Wright

Tomás said:
Joe Wright posted:




It is for the purpose of my tutorial -- it gives the original poster a
concrete, down-to-earth example of what's going on. When you don't
initialise a variable, it sort of has a random value (which may not even
be a valid bit-pattern for the given type).




Congratulations, you understand.




Should I presume that the remainder of your post simply repeats every
point I made in my previous post?




An inaccurate method of testing. I bet you I could get the following to
work on my system:

char *p;

*p = 'e';

if ( *p == 'e' ) NaivelyIndicateSuccess();
But we agree that this is undefined, don't we?
(Maybe I'm getting mixed up with C and C++ here, but in C++, you can use
a char* to access ANY memory. Would you have to use an unsigned char* in
C?)
Yes, 'unsigned char*' is the method to access any byte in memory in C.
Since C89 we have 'void*' to hold any memory address but it can't be
used to access memory directly.
 
J

Jack

Thanks a lot.
But why the following code works well?
int *p;
*p = 5;

Moreover, I find that many textbooks use the following code to
initialize a char pointer:
char *c;
c = "test";

Is it wrong?

Thanks.
 
B

Ben Pfaff

Jack said:
But why the following code works well?
int *p;
*p = 5;

There's always the chance that an uninitialized pointer happens
to point to memory that, when modified, doesn't exhibit any
immediately bad behavior. That's bad: it means that the error
doesn't show up in testing, or perhaps that it makes the error
look like it's in some unrelated part of your program.
Moreover, I find that many textbooks use the following code to
initialize a char pointer:
char *c;
c = "test";

Is it wrong?

No, this is correct code[*]. The difference here is that this
statement sets the value `c'. The former code does not set the
value of `c'; rather, it *uses* the (uninitialized) value of `c',
by dereferencing it.

[*] Although it would be better to declare `c' as type `const
char *', because literal strings are non-modifiable.
 
T

Tomás

Jack posted:
Thanks a lot.
But why the following code works well?
int *p;
*p = 5;


Learn to be more articulate when asking questions.


Question: Why does it compile?

Answer: Because there's nothing in the Standard which it must not
compile.


Question: When I run the executable, why does it run normally without
error?

Answer: Because you're luck (or unlucky). Your system simply isn't
complaining about you accessing memory which isn't yours to access. If
you've got a Disk Format Program running at the same time, you may alter
its boolean value which determines whether it should format the C drive.

Moreover, I find that many textbooks use the following code to
initialize a char pointer:
char *c;
c = "test";


Stupid, but not wrong. I'm too lazy to explain why though. Go to:

http://www.possibility.com/Cpp/const.html

and do a text search for "undefined, modifying static buffer!!!"


-Tomás
 
J

Jack

What is the problem with the following code?

int **p1;
int a1[] = {2,3,4};
int a2[] = {22,33};
int a3[] = {22,33,44,55};

int *b1, *b2, *b3;

b1 = a1;
b2 = a2;
b3 = a3;

p1 = &b1;
p1++;
p1=&b2;
p1++;
p1=&b3;

p1 = p1-2;

for(int i = 0; i < 3; i++){
std::cout <<"*((*p1)+"<<i<<"): "<< *((*p1)+i)<<std::endl; //LINE1
}

p1++;
for(int i = 0; i < 2; i++){
std::cout <<"*(*(p1+1)+"<<i<<"): "<< *(*(p1)+i)<<std::endl; //LINE2
}


LINE1 prints unexpected numbers. LINE2 causes "Segmentation fault".
Why?

Thanks.
 
T

Tomás

Jack posted:

int **p1;

OK.


int a1[] = {2,3,4};

OK.


int a2[] = {22,33};

OK.


int a3[] = {22,33,44,55};

OK.



int *b1, *b2, *b3;

OK.


b1 = a1;
b2 = a2;
b3 = a3;

OK.


p1 = &b1;

OK.


p1++;


p1 now contains garbage.

p1=&b2;

OK.


p1++;


p1 now contains garbage.

p1=&b3;

OK.


p1 = p1-2;


p1 now contain garbage.

LINE1 prints unexpected numbers. LINE2 causes "Segmentation fault".
Why?


Your code makes the unfounded presumption that b1, b2, and b3 are
contiguous in memory. What you want is something like:

int *array_pointers[3];

#define b1 (*array_pointers)
#define b2 (array_pointers[1])
#define b3 (array_pointers[2])


Here's the revised code:



int main(void)
{

int **p1;
int a1[] = {2,3,4};
int a2[] = {22,33};
int a3[] = {22,33,44,55};

int *array_pointers[3];

#define b1 (*array_pointers)
#define b2 (array_pointers[1])
#define b3 (array_pointers[2])

b1 = a1;
b2 = a2;
b3 = a3;

p1 = &b1;
p1++;
p1=&b2;
p1++;
p1=&b3;

p1 = p1-2;
}


As for using C standard output rather than C++ standard output... I'll
leave that one up to you.

-Tomás
 
J

Jack

Thanks a lot. I tested your code. It works well!
Do you mean that the pointers stored in p1, (p1+1) and (p1+2) must be
contiguous in memory?
My thought is that p1, (p1+1) and (p1+2) are contiguous in memory. So
even if b1, b2 and b3 in my code are not contiguous in memory, I can
still access it through p1, (p1+1) and (p1+2). I must be wrong. Why?

To make it easy to read, part of my code is below:

int **p1;
int a1[] = {2,3,4};
int a2[] = {22,33};
int a3[] = {22,33,44,55};

int *b1, *b2, *b3;

b1 = a1;
b2 = a2;
b3 = a3;

p1 = &b1;
p1++;
p1=&b2;
p1++;
p1=&b3;

p1 = p1-2;


Thanks.
 
K

Keith Thompson

Jack said:
What is the problem with the following code?

int **p1; [snip]
for(int i = 0; i < 3; i++){
std::cout <<"*((*p1)+"<<i<<"): "<< *((*p1)+i)<<std::endl; //LINE1
}
[snip]

There are at least two major problems.

1. It's not a complete program, though you could easily have made it
one (which would have made it easier for us to help).

2. It's not C, it's C++.

Please take the time to post a complete, self-contained program.
 
A

Andrew Poelstra

Thanks a lot. I tested your code. It works well!
Do you mean that the pointers stored in p1, (p1+1) and (p1+2) must be
contiguous in memory?
My thought is that p1, (p1+1) and (p1+2) are contiguous in memory. So
even if b1, b2 and b3 in my code are not contiguous in memory, I can
still access it through p1, (p1+1) and (p1+2). I must be wrong. Why?
p1+1 points to the memory location immediately after the original p1.
Here's a small diagram to help:

--------------------
| p1 | p1+1 | p1+2 |
--------------------
| | |
--------------------------------
| b1 | ? | ? | b2 | b3 |
--------------------------------

That is a very artificial example, as b1, b2, and b3 could be
millions of bytes away from each other! However, p1+1 will always
point to the place after p1.

To make it easy to read, part of my code is below:

int **p1;
int a1[] = {2,3,4};
int a2[] = {22,33};
int a3[] = {22,33,44,55};

int *b1, *b2, *b3;

b1 = a1;
b2 = a2;
b3 = a3;

p1 = &b1;
p1++;
p1=&b2;
p1++;
p1=&b3;

p1 = p1-2;
I've left that for people to comment.
 
J

Jack

Andrew said:
p1+1 points to the memory location immediately after the original p1.
Here's a small diagram to help:

--------------------
| p1 | p1+1 | p1+2 |
--------------------
| | |
--------------------------------
| b1 | ? | ? | b2 | b3 |
--------------------------------

That is a very artificial example, as b1, b2, and b3 could be
millions of bytes away from each other! However, p1+1 will always
point to the place after p1.

Do you mean that the memory that p1, (p1+1) and (p1+2) point to must be
contiguous?
p1, (p1+1) and (p1+2) are contiguous. b1's address is stored in p1,
b2's address is stored in (p1+1), and b3's address is stored in (p1+2).
Why b1, b2, and b3 must be contiguous? Thanks.

Jack

To make it easy to read, part of my code is below:

int **p1;
int a1[] = {2,3,4};
int a2[] = {22,33};
int a3[] = {22,33,44,55};

int *b1, *b2, *b3;

b1 = a1;
b2 = a2;
b3 = a3;

p1 = &b1;
p1++;
p1=&b2;
p1++;
p1=&b3;

p1 = p1-2;
I've left that for people to comment.
 
A

Andrew Poelstra

Do you mean that the memory that p1, (p1+1) and (p1+2) point to must be
contiguous?
p1, (p1+1) and (p1+2) are contiguous. b1's address is stored in p1,
b2's address is stored in (p1+1), and b3's address is stored in (p1+2).
Why b1, b2, and b3 must be contiguous? Thanks.
If b1's address is stored in p1, you have double indirection. I'm not
sure that that is what you mean or want, but here's an expaination:

---------------------------
| p1 | p1+1 | p1+2 |
---------------------------
| | |
---------------------------
| *p1 | *(p1+1) | *(p1+2) |
---------------------------
| | \-----------\
| | |
| \-------------\ |
--------------------------------
| b1 | ? | ? | b2 | b3 |
--------------------------------

In this case, *p1, *(p1+1), and *(p1+2) are all pointers in themselves.
I recommend you avoid double indirection until you have a firm grasp
on other aspects of pointers.
 
J

Jack

Andrew said:
If b1's address is stored in p1, you have double indirection. I'm not
sure that that is what you mean or want, but here's an expaination:

---------------------------
| p1 | p1+1 | p1+2 |
---------------------------
| | |
---------------------------
| *p1 | *(p1+1) | *(p1+2) |
---------------------------
| | \-----------\
| | |
| \-------------\ |
--------------------------------
| b1 | ? | ? | b2 | b3 |
--------------------------------

In this case, *p1, *(p1+1), and *(p1+2) are all pointers in themselves.
I recommend you avoid double indirection until you have a firm grasp
on other aspects of pointers.

Thank you for your creative figure using text format.
The figure below expresses what I mean. Why it does not work?

------------------------------------
| p1 | p1+1 | p1+2 |
----------------------------------
| | |
| | \--------\
| | |
| \-------------\ |
-------------------------------------
| b1 | ? | ? | b2 | b3 |
-------------------------------------

p1 = &b1;
p1++;
p1 = &b2;
p1++;
p1 = &b3;

p1 = p1-2;

Does p1 point to b1 now? I can not figure out what the problem is.

Thanks a lot.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,836
Latest member
BuyBlissBitesCBD

Latest Threads

Top