Suppose:
6 char arr[] = "ABC";
7
8 char *ptr = &arr;
9 char *ptr2 = &ptr;
Using ptr2, how can i access elements of c?
I would have thought the following would work, but ... it does not.
**ptr2[1]
You currently don't have a pointer-to-a-pointer.
Your code should be:
char c[] = "ABC";
char *ptr = c; // Note no &
char **ptr2 = &ptr; // Note **, not *. This is now a pointer-to-pointer
Then to access, you want this:
(*ptr2)[1]
ptr is a pointer to an array so its type is char (*ptr)[] not char *
And ptr2 is a pointer to a pointer of pointer so its type is : char (**ptr2)[].
Related
Assume this code in C:
int a = 5;
int *b = &a;
*b = 6;
Notice that b had to be dereferenced using * to have a value reassigned.
However, the same doesn't go with a char pointer (a String):
char *name = "test";
name = "test2";
name did not have to be dereferenced. Why is that?
In this code snippet
int a = 5;
int *b = &a;
*b = 6;
the last assignment stores the integer constant to the object pointed to by the pointer b. That is the value of the object a is changed not the value (address) stored in the pointer b.
In this code snippet
char *name = "test";
name = "test2";
the value of the pointer itself is changed not the object pointed to by the pointer. So at first the pointer name pointed to the first character of the string literal "test" and then it is reassigned to point to the first character of the string literal "test2".
It is the similar to the following code
int a = 5;
int *b = &a;
int a2 = 6;
b = &a2;
If you want to change an object pointed to by a pointer of the type char * you could write
char s[] = "test";
char *name = s;
*name = 'T';
In this case the array s will have "Test".
Pay attention that you may not change a string literal. That is if instead of the array s you will write
char *s = "test";
char *name = s;
*name = 'T';
then the code will have undefined behavior.
Also bear in mind that in this declaration
char *s = "test";
the string literal having the type char[5] is implicitly converted to pointer to its first element.
The type of "test2" is already char[6] (which in turn decays to char*). There's simply no need to use address-of on the rvalue, or dereference the lvalue to do the assignment for the types to work out.
Why is that?
Because the two examples you show are not the same.
The were the same if you did:
/* your 1st example: */
int a = 5;
int *b = &a; /* b is a pointer to a what a is. */
*b = 6;
a equals 6 now.
/* your second example adjusted: */
char *a = "test";
char **b = &a; /* b is a pointer to a what a is. */
*b = "test2";
a points to "test2" now.
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++);
Lets say I have the following variables:
char c[] = "ABC";
char *ptr = &c;
char **ptr2 = &ptr;
I know I can iterate over a pointer to an array of char, this way:
int i;
for(i=0; i<3; i++){
printf("TEST******************, %c\n", ptr[i]);
}
How do I iterate over a pointer to a pointer?
Suppose:
6 char c[] = "ABC";
7
8 char *ptr = &c;
9 char *ptr2 = ptr;
10 char **ptr3 = &ptr;
In this scenario:
ptr represents an address of c
ptr2 represents an address of ptr. A pointer to a pointer
ptr3 is a value stored in ptr, which is an address of c.
**ptr3=&ptr means - Take address of ptr, look inside and assign its value (not address) to ptr3
If I understood your question correctly, you need to use pointers to pointers: ptr2 in my example instead of ptr3
If so, you can access elements like :
ptr2[0] = A
ptr2[1] = B
ptr2[2] = C
For the record the following will yeld the same results. Try it.
12 printf ("===>>> %x\n", ptr2);
13 printf ("===>>> %x\n", *ptr3);
Good discussion for your reference is here
For your example:
int i;
for(i=0; i<3; i++){
printf("TEST******************, %c\n", (*ptr2)[i]);
}
If I did not misunderstand your question, this code should make a job
printf("TEST******************, %c\n", (*ptr2)[i]);
let me give an example,
char **str; // double pointer declaration
str = (char **)malloc(sizeof(char *)*2);
str[0]=(char *)"abcdefgh"; // or *str is also fine instead of str[0]
str[1]=(char *)"lmnopqrs";
while(*str!=NULL)
{
cout<<*str<<endl; // prints the string
str++;
}
free(str[0]);
free(str[1]);
free(str);
or one more best example which you can understand.
here i have used 2 for loops because i am iterating over each character of the array of strings.
char **str = (char **)malloc(sizeof(char *)*3); // it allocates 8*3=24 Bytes
str[0]=(char *)"hello"; // 5 bytes
str[1]=(char *)"world"; // 5 bytes
// totally 10 bytes used out of 24 bytes allocated
while(*str!=NULL) // this while loop is for iterating over strings
{
while(**str!=NULL) // this loop is for iterating characters of each string
{
cout<<**str;
}
cout<<endl;
str++;
}
free(str[0]);
free(str[1]);
free(str);
i have to char[] in C and i wanted to swap between them, by only swaping the pointer
to the array and not one char at a time so i wrote this code:
#include <stdio.h>
void fastSwap (char **i, char **d)
{
char *t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "012345678910";
char num2[] = "abcdefghujk";
fastSwap ((char**)&num1,(char**)&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
I get this output (note the last 4 characters)
abcdefgh8910
01234567ujk
When I expect:
abcdefghujk
012345678910
NOTE: I am working on a 64 bit Linux System.
You can't modify the addresses of num1 and num2, your code should work if your test was instead:
int main ()
{
char num1[] = "012345678910";
char num2[] = "abcdefghujk";
char *test1 = num1;
char *test2 = num2;
fastSwap (&test1,&test2);
printf ("%s\n",test1);
printf ("%s\n",test2);
return 0;
}
Arrays are not pointers. While they decay to pointers when you call your fastSwap(), these pointers are not the actual arrays. The fact that you need a cast should give you a hint that something is wrong.
This would work:
void fastSwap (const char **i, const char **d)
{
const char *t = *d;
*d = *i;
*i = t;
}
const char* num1 = "012345678910";
const char* num2 = "abcdefghujk";
fastSwap (&num1,&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
This will work:
int main ()
{
char *num1 = "012345678910";
char *num2 = "abcdefghujk";
fastSwap (&num1,&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
num1 is an array, and &num1 is the address of the array itself - it is not an address of a pointer.
The address of an array itself is the same location in memory as the address of the first element of the array, but it has a different type. When you cast that address to char **, you are claiming that it points at a char * value - but it does not. It points at a block of 13 chars. Your swap function then accesses that array of 13 chars as if it were a char * - since the latter is the same size as 8 chars on your platform, you end up swapping the first 8 chars of each array.
Your fastSwap only seems to work. You're invoking undefined behavior by casting '&num1' and '&num2' (which are pointers to the characters of num1 and num2) to pointers to pointers of characters (char**).
char *t = *d
t will point to whatever d's contents are pointing to, however d is pointing to the actually characters of num2 ("abcdefghujk" or 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x75 0x6B 0x00). This means that '*d' is actually copying the contents of 'num2' and not the pointer to num2 as you probably expected.
't' then is a bad pointer however since it is never dereferenced you avoid a crash/segment fault.
Because you're on a 64 bit machine/OS pointers are 8 bytes the value of 't' is now the first 8 bytes of 'num2' and this is what gets put into num1 after
*i = t
If you intend to swap pointers you must first create pointer variables as Mark did
char *test1 = num1;
char *test2 = num2;
fastSwap (&test1,&test2);
Or change num1 and num2 into pointers (char *) rather than arrays (char[]) as sb1/Karl did
char *num1 = "012345678910";
char *num2 = "abcdefghujk";
fastSwap (&num1,&num2);
I've had the same situation and solved it with the following trick:
p.s. windows platform, vs-2012
void FastSwap (void **var1, void **var2) {
void *pTmp = *var1;
*var1 = *var2;
*var2 = pTmp;
}
int main () {
char *s1 = "1234567890123456";
char *s2 = "abcdefghij";
printf ("s1 before swap: \"%s\"\n", s1);
printf ("s2 before swap: \"%s\"\n", s2);
// if you change arguments in the FastSwap definition as (char **)
// then you can erase the (void **) part on the line below.
FastSwap ((void **) &s1, (void **) &s2);
printf ("s1 after swap : \"%s\"\n", s1);
printf ("s2 after swap : \"%s\"\n", s2);
return (0);
}
Change fastSwap to:
void fastSwap (char *i, char *d)
{
while ((*i) && (*d))
{
char t = *d;
*d = *i;
*i = t;
i ++;
d ++;
}
}
then call fastSwap (num1, num2);
int swap(char *a, char *b){
char *temp = (char *)malloc((strlen(a) + 1)*sizeof(char));
strcpy(temp, a);
strcpy(a, b);
strcpy(b, temp);
}
int main(){
char a[10] = "stack";
char b[10] = "overflow";
swap(a, b);
printf("%s %s", a, b);
}
While given answers already showed how to do it right (and hinted to undefined behaviour), you still might be interested in the details...
At very first, you have to character arrays. Applying the addressof operator to won't give you a pointer to pointer, but a pointer to array:
int(*ptr1)[10] = &num1;
Syntax might look strange, but that's C. The important thing here now is: You have a pointer with one level of indirection. But you cast it to a pointer with two levels of indirection (char**).
What now happens in fastSwap is:
char* t = *d;
This will copy as many bytes of *d into t as pointers on your system have size. Solely: In reality, you do not have a pointer to pointer, but a pointer to array which only has been casted. So the first sizeof(void*) bytes of the array will be copied into t. Similarly for the other assignments, explaining the results you get.
If now your arrays were shorter than the size of pointers, then memory after the arrays would have been read:
int a[] = "123";
int b[] = "456";
int c[] = "789";
fastSwap ((char**)&a, char**(&b));
printf("%s %s %s", a, b, c);
would have printed on your system (as pointer size is 8 bytes):
456 789 456
Explanation:
char *t = *d;
// copied the four bytes of b into t - AND the next four bytes (those of c!!!)
*d = *i;
// copied the eight bytes of a AND b int b AND c
// b contains "123", c "456"
*i = t;
// copied the eight bytes that were copied from b and c into a and b
// the "123" in b now got overwritten, that's why you never see them...
Be aware that you don't have guarantee for such result, it is just the most likely one. You invoked undefined behaviour, anything might happen instead, you even might switch off the sun by accident (if your compiler happened to produce the appropriate code...).
I asked some time ago on an account I can't remember how to manipulate basic pointers and someone gave me a really good demo
for example
char *ptr = "hello" (hello = a char array)
so now *ptr is pointing at 'h'
ptr++ means moving the ptr to point at the next element, to get its value I do *ptr and that gives me e
ok so far everything works as I hope :D, but now I need to manipulate a char **ptr and was wondering how I do this in a way that mimics the effects of a 2d array?
Some basic tips would be much appreciated as I need to do an assignment that has a **ptr to imitate a 2d array and without knowing how it does this first means I can't even solve it on paper (for example, how do you dereference a **ptr, how do you get [x][y] values etc)
thanks
You can subscript a pointer the same way you can subscript an array, provided all the addresses have been set up correctly.
Assuming the following declaration:
char **ptr;
here are the types of the various expressions:
Expression Type Equivalent expressions (yield same value)
---------- ---- -----------------------------------------
ptr char ** &ptr[0]
*ptr char * ptr[0]
*(ptr+i) char * ptr[i]; &ptr[i][0]
**ptr char ptr[0][0]
*(*(ptr+i)) char ptr[i][0]; *ptr[i]
*(*(ptr+i)+j) char ptr[i][j]
thus:
ptr can be treated as though it was an array of strings (2-d array of char)
ptr[i] points to the beginning of the i'th string in the list
ptr[i][j] is the value of the j'th character of the i'th string in the list
The expressions ptr++ and ++ptr will advance ptr to point to the next string
The expressions (*ptr)++ and ++(*ptr) will advance *ptr to point to the next character
As for setting up your pointers, this arrangement assumes everything has already been allocated as static arrays or dynamically through malloc. You cannot just write
char **ptr = {"foo", "bar", "bletch"}; // using aggregate initializer on
// non-aggregate type; bad juju,
// a.k.a undefined behavior
or
char **ptr; // ptr has not been initialized to point anywhere
ptr[0] = "foo"; // dereferencing ptr via subscript invokes undefined
ptr[1] = "bar"; // behavior
ptr[2] = "bletch";
Generally, when you're using a pointer as though it was an array, you'll use malloc or something similar to allocate your buffers:
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
ptr[0] = "foo"; // ptr[i] gets address of
ptr[1] = "bar"; // string literal
ptr[2] = "bletch";
...
}
or
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
size_t i;
for (i = 0; i < N; i++)
{
ptr[i] = malloc(sizeof *ptr[i] * M); // strictly speaking, the sizeof
if (ptr[i]) // is not necessary here
{
//initialize ptr[i]
}
}
}
A pointer to a pointer is just that. For example:
// Declare our double-indirection pointer.
char** ptr;
// And initialize it:
char s1[] = "hello";
char s2[] = "world";
ptr = malloc(sizeof(char*) * 2);
ptr[0] = s1;
ptr[1] = s2;
// ptr now points to a pointer that points to 'h'.
char* ptr2 = *ptr;
// ptr2 points to 'h'.
char* ptr3 = *(ptr + 1);
// ptr3 points to "w".
char c = **ptr; // could be written as *(*ptr)
// c = 'h'.
char c2 = *(*(ptr + 1));
// c2 = 'w'.
char c3 = *(*(ptr) + 1);
// c3 = 'e'.
You may use them as you would a normal two-dimensional array. (Since effectively, that's what they are)
char** ptr = {"lorem", "ipsum", "dolor"};
char* s1 = ptr[0]; //Points to the beginning of "lorem"
char* s2 = ptr[1]; //Points to the beginning of "ipsum"
char c = ptr[2][4]; //Contains 'r'
This is due to the fact that:
int *a;
//...
int i = a[6];
int j = *(a + 6); //Same as previous line!
Cheers,
Amit Ron--