Basic help needed with pointers (double indirection) - c

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

Related

Dereferencing an int pointer vs char pointer

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.

Swapping 2 elements in an array of pointers (to strings of different length) in C

I am trying to swap 2 elements in an array of pointers, and these pointers point to strings of different length. Another function handled allocating memory to the array and the strings, the swap function will simple take an char** array and swap the elements I need to swap. What I am wondering is when I swap the pointers, is the allocated memory for each string retained when I swap or does this get messed up?
This isn't my exact code from my project, but what it's doing is identical:
int main() {
char** array = malloc(10 * sizeof(char*));
char* a = (char*)malloc(4*sizeof(char*));
char* b = (char*)malloc(14*sizeof(char*));
a = "test";
b = "this is a test";
array[0] = a;
array[1] = b;
char*temp;
temp = array[0];
array[0] = array[1];
array[1] = temp;
free[array];
free[a];
free[b];
return 0;
}
Too summarize, my question is in regard to the allocated memory of a and b. Is that allocated memory still correct/fine after the swap?
The swap is fine. The problem is how you are allocing memory for the a and b pointers and how you are assigning strings to them. And no, when you use the swap algorithm the blocks of memory won't be scrambled. If you do not change a and b, then you will be fine (which you are doing). In C, things work like this:
char *a = malloc(4 * sizeof(char));
a = "test"; // this is an error, and you will lose the memory block
This is allocating 4 units of memory, each unit is of the size of a char. When you do:
char *a = malloc(4 * sizeof(char**));
This is allocating 4 units of memory, each unit is of the size of char *, or a pointer to char. This is not what you intended. Furthermore, if you want to put a string in a pointer to char, you should use the strncpy function (or strndup if available).
char *a = malloc(5 * sizeof(char)); // always alloc space for the NULL byte
strncpy(a, "test", 4);
char *b = strndup("test", 4);
free(a);
free(b);
Note that you did alloc the memory for the array of pointers in the right way, doing:
char **array = malloc(10 * sizeof(char*));
... will give you a block of 10 units of memory, each of which are of the size of char *. Then you can address each of those units of memory by indexing the array pointer.
Couple pointers (no pun): first, you don't need to cast the return of malloc. Second, you don't need to multiply by sizeof(char). Bellow is a little working version of the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char **array = malloc(10 * sizeof(char*));
char *a = malloc(5);
char *b = malloc(15);
strcpy(a, "test");
strcpy(b, "this is a test");
char *temp;
array[0] = a;
array[1] = b;
// prints "test" then "this is a test"
printf("%s\n%s\n\n", array[0], array[1]);
// this swaps them
temp = array[0];
array[0] = array[1];
array[1] = temp;
// now it prints "this is a test" and "test"
printf("%s\n%s\n\n", array[0], array[1]);
free(a);
free(b);
free(array);
}

C: A pointer to an address of a pointer, clarification needed

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)[].

How do I iterate over a pointer to a pointer?

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

Assigning memory to double pointer?

I am having trouble understanding how to assign memory
to a double pointer.
I want to read an array of strings and store it.
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<20; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
instead of this I just assign a large block of memory and
store the string
char **ptr;
ptr = (char**)malloc(sizeof(char)*50*50);
would that be wrong? And if so why is it?
Your second example is wrong because each memory location conceptually would not hold a char* but rather a char. If you slightly change your thinking, it can help with this:
char *x; // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'
x = (char*)malloc(sizeof(char) * 100); // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'
// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'
Because of that, your first loop would be how you do in C an array of character arrays/pointers. Using a fixed block of memory for an array of character arrays is ok, but you would use a single char* rather than a char**, since you would not have any pointers in the memory, just chars.
char *x = calloc(50 * 50, sizeof(char));
for (ii = 0; ii < 50; ++ii) {
// Note that each string is just an OFFSET into the memory block
// You must be sensitive to this when using these 'strings'
char *str = &x[ii * 50];
}
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<50; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
fclose(fp);
may be your typo mistake but your loop should be of 50 instead of 20 if you are looking for 50 x 50 matrix. Also after allocation of memory mentioned above you can access the buffer as ptr[i][j] i.e in the 2D format.
A double pointer is just a pointer to another pointer. So you can allocate it like this:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;
You have to keep in mind where your pointer is stored at (in this example the double pointer points to a pointer variable on the stack so it's invalid after the function returns).
i will give one example, which might clear of the doubt,
char **str; // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2) // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10) // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10) // <same as above>
strcpy(str[0],"abcdefghij"); // 10 length character
strcpy(str[1],"xyzlmnopqr"); // 10 length character
cout<<str[0]<<endl; // to print the string in case of c++
cout<<str[1]<<endl; // to print the string in case of c++
or
printf("%s",str[0]);
printf("%s",str[1]);
//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);
other simpler way to memorize
Case -1 :
step-1 : char *p;
step -2 :
please read it like below
char (*p); ==> p is a pointer to a char
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char) * some_len);
Case -2 :
step-1 : char **p;
step -2 :
please read it like below
char* (* p); ==> p is a pointer to a char *
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char *) * some_len);
Case -3 :
No one uses this but just for sake of explanation
char ***p;
read it as,
char** (*p); ==> p is a pointer to a char** (and for this check case-2 above)
p = malloc(sizeof(char**) * some_len);
Adding to Pent's answer, as he correctly pointed out, you will not be able to use this double pointer once the function returns, because it will point to a memory location on the function's activation record on stack which is now obsolete (once the function has returned). If you want to use this double pointer after the function has returned, you may do this:
char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;
The return type of the function must obviously be char ** for this.
well, this is how I do it:
#include <stdlib.h>
int main(void)
{
int i = -1; // just a counter
int j = 5; // how many strings
char *s[j];
while(++i < j)
s[i] = malloc(sizeof(char*)); // allocating avery string separately
return (0);
}
this also works:
char **allocate(int lines)
{
int i = -1;
char **s = malloc(sizeof(char *) * lines); // allocating lines
while (++i < lines)
{
s[i] = malloc(sizeof(char*)); // alicating line
scanf("%s", s[i]);
}
return (s);
}
int main(int ac, char *av[])
{
int lines = 5; // how many lines
char **s = allocate(lines);
return (0);
}
Double pointer is, simply put, a pointer to a pointer,
In many cases it is used as an array of other types.
For example, if you want to create an array of strings you can simply do:
char** stringArray = calloc(10, 40);
this will create an array of size 10, each element will be a string of length 40.
thus you can access this by stringArray[5] and get a string in the 6th position.
this is one usage, the others are as mentioned above, a pointer to a pointer, and can be allocated simply by:
char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.
read more here:
good array tutorial

Resources