Dereferencing char * array[] and storing in char ** array[] (C) - c

Edit. Sorry for the minimal information included previously
Say I have the following code:
char ** a[16];
a[15] = '\0';
int i;
for (i = 0; i < 5; i++) {
char * b[3];
b[2] = '\0';
b[0] = "foo";
b[1] = "bar";
if (i == 4) {
b[0] = "hello";
b[1] = "world";
}
a[i] = b;
}
Straight after the for loop, if I include the following two lines:
printf("%s %s\n", a[0][0], a[0][1]);
printf("%s %s\n", a[4][0], a[4][1]);
I want the output to be:
foo bar
hello world
However it is instead:
hello world
hello world
I am aware this is because of my declaration, a[i] = b;, where b is an array of char pointers. Each loop, the character pointers pointed to by b[0] and b[1] are changed.
In the final loop they are set to "hello" and "world" respectively. Since I assigned b to a[i], every index of a now points to the same thing.
What I would like to do is dereference b, such that a[i] is given the value b points to rather than b itself. Therefore after the loop all indexes of a are not the same.
I tried using the following but both resulted in segmentation faults:
*a[i] = *b
and
**a[i] = **b
Any help would be much appreciated, as I'm totally lost. Thank you :)

What I would like to do is dereference b, such that a[i] is given the value b points to rather than b itself. Therefore after the loop all indexes of a are not the same.
Note that b itself is an array, so you cannot just assign value b points to rather than b itself because b does not point to a single value.
To really do this (not sure why you would want this) replace the line:
a[i] = b;
a[i][0] = b[0];
a[i][1] = b[1];
a[i][2] = b[2];

Related

What is the effect of ` c = (int *) ((char *) c + 1)`?

I meet the question in OS course. Here is the code from 6.828 (Operating System) online course. It meant to let learners practice the pointers in C programming language.
#include <stdio.h>
#include <stdlib.h>
void
f(void)
{
int a[4];
int *b = malloc(16);
int *c;
int i;
printf("1: a = %p, b = %p, c = %p\n", a, b, c);
c = a;
for (i = 0; i < 4; i++)
a[i] = 100 + i;
c[0] = 200;
printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c[1] = 300;
*(c + 2) = 301;
3[c] = 302;
printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = c + 1;
*c = 400;
printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = (int *) ((char *) c + 1);
*c = 500;
printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
b = (int *) a + 1;
c = (int *) ((char *) a + 1);
printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}
int
main(int ac, char **av)
{
f();
return 0;
}
I copy it to a file and compile it use gcc , then I got this output:
$ ./pointer
1: a = 0x7ffd3cd02c90, b = 0x55b745ec72a0, c = 0x7ffd3cd03079
2: a[0] = 200, a[1] = 101, a[2] = 102, a[3] = 103
3: a[0] = 200, a[1] = 300, a[2] = 301, a[3] = 302
4: a[0] = 200, a[1] = 400, a[2] = 301, a[3] = 302
5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302
6: a = 0x7ffd3cd02c90, b = 0x7ffd3cd02c94, c = 0x7ffd3cd02c91
I can easily understand the output of 1,2,3,4. But it's hard for me to understand the output of 5. Specially why a[1] = 128144 and a[2] = 256?
It seems this output is the result of
c = (int *) ((char *) c + 1);
*c = 500;
I have trouble understand the function of the code c = (int *) ((char *) c + 1).
c is a pointer by definiton int *c. And before the output of 5th line, c points to the second address of array a by c = a and c = c + 1. Now what's the meaning of (char *) c and ((char *) c + 1) ,then (int *) ((char *) c + 1)?
Although this is undefined behavior per the standard, it has a clear meaning in "ancient C", and it clearly works that way on the machine/compiler you're working with.
First, it casts c to a (char *), which means that pointer arithmetic will work in units of sizeof(char) (i.e. one byte) instead of sizeof(int). Then it adds one byte. Then it converts the result back to (int *). The result is an int pointer that now refers to an address one byte higher than it used to. Since c was pointing at a[1] beforehand, afterwards *c = 500 will write to the last three bytes of a[1] and the first byte of a[2].
On many machines (but not x86) this is an outright illegal thing to do. An unaligned access like that would simply crash your program. The C standard goes further and says that that code is allowed to do anything: when the compiler sees it, it can generate code that crashes, does nothing, writes to a completely unrelated bit of memory, or causes a small gnome to pop out of the side of your monitor and hit you with a mallet. However, sometimes the easiest thing to do in the case of UB is also the straightforward obvious thing, and this is one of those cases.
Your course material is trying to show you something about how numbers are stored in memory, and how the same bytes can be interpreted in different ways depending on what you tell the CPU. You should take it in that spirit, and not as a guide to writing decent C.
At the first output, c is point to a random address.
After c = a;, c point to a so when you change value of c[0], c[1], *(c + 2), 3[c] the value of a change accordingly.
At the following line:
c = c + 1;
c is now point to a[1] and the address would be 0x7ffd3cd02c94.
Now go to the line that you are asking for: c = (int *) ((char *) c + 1); it will do as following:
Convert c to a pointer type char which still point to same address 0x7ffd3cd02c94.
Do increase the pointer 1, so now the address would be 0x7ffd3cd02c95
Assign the new address again to c (int *).
Before that command, c will point to address: 0x7ffd3cd02c94-0x7ffd3cd02c97. But after that the address would be: 0x7ffd3cd02c95-0x7ffd3cd02c98. That is the reason the value at [5] is
[![enter image description here][1]][1]
Now it is clear why the value changed as you observed.
NOTE: This is correct for little endian system. For big endian the result would be a little bit different. AND for some embedded platform which not allow UNALIGNED access, you should got exception at that line.
[1]: https://i.stack.imgur.com/eU0Tb.png
This is a result of undefined behavior. You invoke undefined behavior because you dereference a null pointer (for array a) and the array size is zero (for array b) - for this case, this is equivalent to c= a; b= 0; c = (int *) ((char *) c + 1). This should trigger a warning, which is why I also added -Wall -pedantic -std=c99 in the above example.
To answer your question about (char *) c and ((char *) c + 1).
(char *) c: Since c is a pointer, c->type is int * (pointer to int). This makes c->type have type char *. You take the address of the second element in the array c and assign it to a. So, c->type is then char * (address of second element in the array c). c[0] (index 0) is therefore the first element in array c.
((char *) c + 1) - c + 1 = &c[1]. c[0] + 1 = c[1] (first element of the array c+1).

point as array index

My background is C#, I have the following code(in C) that I need to tell what would be the output:
#include <stdio.h>
#define N 10
int main()
{
int a[N] = { 3,4 }; //<-- [3][4][0][0][0][0][0][0][0][0]
int *q = a; //<-- some address
char s[N] = "abcdefg";
int k = s[*a] - s[a[*q]]; //<-- what is that mean ?
char *p = s;
a[k] = k;
printf("%d %s\n",k,p+a[k]);
printf("%d %d %d %d %d",q[0],q[1],q[2],q[3],q[4]);
return 0;
}
Can someone please explain about line number 4?
I can't understand s[*a] is that mean s at index of *a? but *a is address not an integer. same question about s[a[*q]]
Considering
int k = s[*a] - s[a[*q]];
First *a gets the value at a[0] which is 3.
We know that q == a so *q is the same as *a which again is the value 3. The value at a[3] is 0.
So now we have s[3] - s[0] which is 'd' - 'a' which is 3 (assuming ASCII encoding), the value printed out for k.
Without the rest of the code, it is unclear if it will work at all. What is N, for example?
Specifically, s[*a]: a is the name of an array. *a is the same as a[0], because a is a pointer to the first element. So *a is 3, and s[*a] is s[3], which is the character 'd'

Why can uninitialized pointer to int array be assigned variable's value?

I have read answers to questions like why a pointer can be assigned value? however I'm still a bit confused about changing the values of pointers. Some of the comments don't seem to be completely accurate, or maybe it's implementation specific. (example: a[1] is exactly the same as writing *(a + 1). Obviously you can write *a = 3 since a is int*, so you can also write *(a + 1) = 3, so you can also write a[1] = 3).
Writing *a = 3 produces a warning: initialization makes pointer from integer without a cast. As well as a segfault.
My question is as follows.
int main(void)
{
int b = 5, c = 10;
int *a = b;
*a = c; /* Will not work. (Should technically change the value of b to 10, leaving the pointer still pointing to b.) */
printf("%d\n", *a);
return 0;
}
The above example will not work, and will produce a segfault, but the following works for some reason I am not aware of.
int main(void)
{
int a[10], i;
for (i = 0; i < 10; ++i) {
*(a + i) = i; /* Supposedly the same logic as '*a = c;', but works*/
}
for (i = 0; i < 10; ++i) {
printf("%d\n", *(a + i));
}
return 0;
}
Thanks for your time and efforts.
**EDIT: Thank you for the answers, since it is *a = &b (I knew this (typo), but now the second example with the loop is unclear), the array indices are treated as variables, not as addresses I presume?
This:
int b = 5, c = 10;
int *a = b;
Doesn't work. You think the second line means this:
int *a;
*a = b;
But it doesn't. It means this:
int *a;
a = b;
The above error means that when you do this:
*a = c;
Your program crashes (or maybe not, undefined behavior!), because a is an invalid pointer (it points to address 5, which is wrong in many ways).

Difference between 2D char Array and char** (OR, 3D char Array and char*** etc)

Firstly, I've already reviewed these:
How are multi-dimensional arrays formatted in memory?
Memory map for a 2D array in C
From there, it is known that a 2D array is not the same as char** but in memory they look exactly same. This sounds strange and so I've researched the following:
#include <stdio.h>
char func(char** m) {
return m[0][0]; //only works for char**, already discussed in the other SO question
}
int main() {
//char a[4][2]; //a 2D char array
int row = 4, col = 2; //char**
char** a = malloc(row * sizeof(char*));
int i;
for (i = 0; i < row; i++) {
a[i] = malloc(col * sizeof(char));
}
//checking the output
printf(" &a = %u\n", &a);
printf(" &a[0] = %u\n", &a[0]);
printf("&a[0][0] = %u\n", &a[0][0]);
printf(" a = %u\n", a);
printf(" a[0] = %u\n", a[0]);
//printf(" a[0][0] = %u\n", a[0][0]); //char value in a[0][0], here a garbage value
//char m = func(a); //only works for char**, already discussed in the other SO question
return 0;
}
Possible output for char** :
&a = 3209288 // &a
&a[0] = 4083720 // &(*(a+0)) = a
&a[0][0] = 4083784 // &(*(*(a+0)+0)) = *a
a = 4083720 // a
a[0] = 4083784 // *(a+0) = *a
Possible output for 2D char array :
&a = 3473104 // &a
&a[0] = 3473104 // a
&a[0][0] = 3473104 // *a
a = 3473104 // a
a[0] = 3473104 // *a
It is easy to understand the output of char**. But the output of 2D char array looks strange though it was discussed in the other SO question. I cannot think of a pointer x of whatever data-type when,
x = &x = *x
and all the 3 things physically reside in the same block of memory. Hope that my confusion is understandable. Can anyone explain the mystery?
When you use name of the array is any expression except &array and sizeof array this name will be automaticly converted to pointer to the first element of the array (char [5][10] will be converted to char (*)[10]). Address of this pointer will be equal to the adress of entire array.
So, "sizeof (char [5][10]) == 50", there is no additional pointers.
char arr[5][10];
&a = 3473104 // Address of entire array, (char (*)[5][10])
&a[0] = 3473104 // Address of first row, (char (*)[10])
&a[0][0] = 3473104 // Address of first char, (char *)
a = 3473104 // "a", (char [5][10]), converted to "&a[0]", (char (*)[10])
a[0] = 3473104 // "a[0]", (char[10]), converted ro "&a[0][0]", (char *)

Incrementing variables using pointers

I'm very new to dealing with pointers, and my C knowledge is fairly small. I'm trying to understand pointers. I wrote the following code to print a list of variables (a to f) like so:
0
1
2
3
4
5
I wrote the following code to do this:
#include <stdio.h>
int main(){
int a,b,c,d,e,f;
int *p;
int i;
a = b = c = d = f = 0;
p = &a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}
return 0;
}
The idea was it works through the variables and increments each by an ever-increasing number (i). I am assuming that as you initialize the variables at the same time, they'd be placed next to each other in memory. However, I get the following output:
0
1
2
3
-1218283607
If I change the for loop to only go from 0 to 3 (i < 4), it works fine, printer 0 1 2 and 3. But when I wish to print the variable f as well, it doesn't seem to set it.
As I said, I'm very new to pointers so I've probably overlooked something silly, but I've been looking through my code over and over, trying to work it out.
Thanks in advance.
There is no guarantee that a, b, c, d, e and f will be adjacent in memory. If you want that sort of guarantee you need to use an array.
#include <stdio.h>
int main() {
int a[6];
int *p;
int i;
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = 0;
p = &a[0];
for (i = 0; i < 6; i++){
*p += i;
p++;
}
for(i = 0; i < 6; i++) {
printf("%d\n", a[i]);
}
return 0;
}
Here int a[6] is declaring an array named a that can hold six integers. These six integers can obtained via a[0], a[1], a[2], a[3], a[4] and a[5]. You are guaranteed that a[0], a[1], a[2], a[3], a[4] and a[5] are layed out contiguously in memory. Thus the line
p = &a[0];
sets p to the address of the first element. Each increment of this pointer moves us forward one position in the array.
The second for loop shows that first for loops correctly sets a[i] to i for i in {0, 1, 2, 3, 4, 5}. If you run this program you will see
0
1
2
3
4
5
on the console.
You forgot to initialize e. But yes, use a packed array.
It isn't safe to assume that stack variables are arranged in memory in any particular order.
You need to use an array, a struct or possibly a union to gurantee the ordering of your ints.
union {
int ary[6];
struct {
int a;
int b;
int c;
int d;
int e;
int f;
} s;
} u = {0};
p = &u.s.a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}

Resources