I am trying to assign char array value in a structure and retrieving the data but facing some problem while retrieving.
struct first {
int a;
int b;
};
struct second {
int c;
int d;
struct first * f_t[2];
};
int main()
{
struct second *p;
char a[24] = {1, 0, 0, 0,
2, 0, 0, 0,
3, 0, 0, 0,
4, 0, 0, 0,
5, 0, 0, 0,
6, 0, 0, 0};
p = (struct second *)a;
p->f_t[0] = (struct first *) (a + 8);
p->f_t[1] = (struct first *) (a + 16);
printf("%d %d %d %d %d %d",
p->c, p->d, p->f_t[0]->a, p->f_t[0]->b, p->f_t[1]->a, p->f_t[1]->b);
}
Output:
1 2 1245008 1245016 1245024 6
First two values are coming properly (1 and 2) but the rest seems like some garbage values.
Please help to identify some wrong initialization or some other method for the same.
First of all, never assume the padding in a struct. It works fairly reliably, but is technically undefined behavior.
And much more importantly, you are breaking the strict aliasing rule. This is an assumption by the compiler that you never access the same memory location with pointers of different types (in this case, struct first* and char*). You can get around this with the -fno-strict-aliasing or use unions to do type-punning, as it's usually called. Go here for more info.
The more correct version of this code will be -
#include <stdio.h>
#include <stdlib.h>
#include <alloca.h>
#include <string.h>
struct first {
int a;
int b;
};
struct second {
int c;
int d;
struct first * f_t[2];
};
int main()
{
struct second *p;
char a[24] = {1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0};
p = alloca(sizeof(struct second));
memset(p, 0, sizeof(struct second));
memcpy(p, a, sizeof(int)*2);
p->f_t[0]= alloca(sizeof(struct first));
p->f_t[1]= alloca(sizeof(struct first));
memset(p->f_t[1], 0, sizeof(struct first));
memset(p->f_t[0], 0, sizeof(struct first));
memcpy(p->f_t[0], a + 8, sizeof(struct first));
memcpy(p->f_t[1], a + 16, sizeof(struct first));
printf("%d %d %d %d %d %d",p->c,p->d,p->f_t[0]->a,p->f_t[0]->b,p->f_t[1]->a,p->f_t[1]->b);
}
NOTE: Using alloca() is bad practice. Don't use it unless you know what you're doing. It's fine here since it's simply one small struct being allocated on the stack, but in general steer away from it and use malloc() or just use local variables.
This still technically falls under undefined behavior, since we're assuming how the structs are padded, which is implementation specific, but most platforms use self aligned data types and are a lot faster when using properly aligned structures, so it's easy to guess. For more information on this, go here. I still strongly discourage this as this is undefined behavior, and it's very easy to mess up.
Also, the next time onward, make sure to provide a minimal, complete and compilable example.
Well, you have a lot of (potential) problems with strict aliasing rule, possible padding, size of variables, alignment.
But let's assume that your compiler is set to no-strict-aliasing and that all sizes, padding and alignment match.
Then look at these lines:
p->f_t[0]=(Struct first *) (a+8);
p->f_t[1]=(Struct first *) (a+16);
What they will do is to overwrite a[8] and forward with the value of the pointer (aka address). Consequently a is no longer equal to the initialized value.
Try this to see for your self:
// Print all element in a
p->f_t[0]=(Struct first *) (a+8);
// Print all element in a
p->f_t[1]=(Struct first *) (a+16);
// Print all element in a
So your problem is that you try to use a[8] to a[23] for storing
a) two pointers
and
b) two struct first
Of cause that's impossible
Other comments and posts have already addressed the strict aliasing problems that accompany casting one type to another, and have detailed other issues as well.
It is appears from your existing code that you are attempting to reference each member of an array of struct usingpointer variables.
This answer is limited to an illustration of how to do what I think you are trying to do in simple terms: (read in-line comments for explantions)
typedef struct { //using struct instead of Struct
int a;
int b;
}FIRST; //create typedef tag (improved readability throughout code)
typedef struct {
int c;
int d;
FIRST f_t[2]; // changed from *[] to []
}SECOND; // (the rest of your post indicates that is what you meant)
int main()
{
SECOND *p1; //for illustration, create two pointers to reference 2 elements of arr[2]
SECOND *p2;
//Create array of SECOND, populate with unique values in each location
//to provide verification during printf that assignments were made correcly.
SECOND arr[2] = {{1,2,{3,4,5,6}},{7,8,{9,10,11,12}}};
//note values are arranged to follow the definitions of 2 elements of SECOND arr[2].
//Create 2 pointers, 1 for each element of SECOND arr[2]
p1 = &arr[0]; //assigns address of 1st element of SECOND arr[0], to pointer p1
p2 = &arr[1];//assigns address of 1st element of SECOND arr[1], to pointer p2
printf("Elements of p1[0]:\n%d, %d, %d, %d, %d, %d\n", p1[0].c, p1[0].d, p1[0].f_t[0].a,p1[0].f_t[0].b,p1[0].f_t[1].a,p1[0].f_t[1].b );
printf("Elements of p2[0]:\n%d, %d, %d, %d, %d, %d\n", p2[0].c, p2[0].d, p2[0].f_t[0].a,p2[0].f_t[0].b,p2[0].f_t[1].a,p2[0].f_t[1].b );
getchar();//stop execution to view result (needed in my environment)
}
Related
I have a pointers in C, and I can't figure out how it works.
Below is the code:
// ptr points to an array of 2 ints
int (*ptr)[2];
int torf[2][2] = {12, 14, 16};
ptr = torf;
int (*ptr_2)[2];
int torf_2[2][2] = { {12}, {14, 16}};
ptr_2 = torf_2;
printf("%d %d\n", **ptr, **(ptr + 2));
printf("%d %d\n", **ptr_2, **(ptr_2 + 2));
The answer I want should be:
12 16
12 14
But actually I got on my PC:
12 6422000
12 12
Any ideas?
try this:
// ptr points to an array of 2 ints
int(*ptr)[2];
int torf[2][2] = { 12, 14, 16 };
ptr = torf;
int(*ptr_2)[2];
int torf_2[2][2] = { {12}, {14, 16} };
ptr_2 = torf_2;
printf("%d %d\n", **ptr, **(ptr + 1));
printf("%d %d\n", **ptr_2, **(ptr_2+1));
when you use pointers it is like the indexes of the array it begin from 0;
good work
If you add these lines to the end of your program:
printf("%p: %p %p\n", ptr, ptr+1, ptr+2);
printf("%p: %p %p\n", *ptr, *ptr+1, *ptr+2);
printf("%p: %p %p\n", **ptr, **ptr+1, **ptr+2);
You will note that in the first case, the numbers increase by 8, which could either be the size of a pointer or two ints. Same goes for the second, but the third increases by the size of an int; so that is good.
So, to disambiguate 2 ints or 1 address, lets do a s/2/3/g.
Now, we see the first case the increment is now 12 ( = 3 * 4 ).
Your second case ( *ptr + i ) increments by 4, so is the address of successive ints
Your third case is the integer values themselves.
Where did it get confusing? Quick checklist:
When you are trying to workout pointer / indexing problems, use unique values as much as possible.
Pay attention when the compiler warns you. Eventually you will know to ignore "format '%p' expects argument ... ", but it takes time to build the confidence.
There is a handy program, cdecl, which converts C type expressions into something english like.
In virtually all C implementations, int x[2][2], y[4]; have the same layout; that is, C multi-dimensional arrays are just an overlay of a single dimension array, with the arithmetic cleverly hidden. For this reason, definitions like int (*p)[2]; are rare and rarely useful.
If you must go down this road, it is likely better to do something like:
typedef int pair[2];
pair torf[2] = { { 0, 1 }, { 2, 3 }};
pair *ptr = torf;
if nothing else, somebody has a chance to understand it...
While going through a quiz in SoloLearn app, I came across a certain code.
#include <stdio.h>
struct node{
int a, b, c;
};
int main()
{
struct node num = {3, 5, 6};
struct node *ptr = #
printf("%d\n", *ptr);
printf("%d\n", *((int*)ptr + 1 + (3-2)));
return 0;
}
I got the answer right as the result printing 3 and 6, but I am not sure it I understood the struct statement and pointer function properly.
The following steps are how I understood how the code works.
Due to struct node, num 3, 5, 6 are set into a, b, c in the num variable.
*ptr points the first address of num due to struct node *ptr = # which means that it points to the address of the index = 0 which is 3 in {3, 5, 6}.
Therefore, printf("%d\n", *ptr); prints 3,
printf("%d\n", *((int*)ptr + 1 + (3-2))); is printing *(0+1+1) which is index = 2 of num which equals to 6.
Is this right?
Yes, but allow me to adjust your terminology. In particular, using the phrase "index" seems a little off to me, since we're not talking about an array. I will also break up your point#4 to be more explicit about what happens there.
Due to the initializer, 3, 5, 6 are set into a, b, c in the num variable.
ptr points to the start address of num due to struct node *ptr = #, which is the same as the address of num.a.
Therefore, printf("%d\n", *ptr); prints 3.
(int*)ptr yields a pointer to num.a with the proper type.
Adding 2 to ptr means that we add the size of two ints to the address. Note that the typecast is very important, as we would've otherwise added the size of two struct nodes to the address; the effect of adding to a pointer depends on the pointer type.
The resulting address is the same as the address of num.c. At that address, we find the integer value of 6.
I'm testing an issue that I'm having when casting void pointers to a different type within the same variable. The issue seems to be when trying to use the same variable for the casted pointer. Below I have a section of code that tests this. Would someone be able to tell me why the program fails to compile for that case?
#include <stdlib.h>
typedef struct test {
int a;
}test;
int main() {
void * check;
test * check2;
check = malloc(sizeof(test));
check = ((test *) check);
check2 = (test *)check;
check->a = 2; //this raises an error (dereferencing void pointer) when compiling
check2->a = 2; //this works
((test *)check)->a = 2; //this also works
}
Casting a pointer is just lying to your compiler
void * ptr = malloc(sizeof(test));
((test *)ptr)->a = 5;
In the second line, we are telling the compiler "I know I declared ptr as a (void *), but I'm smarter than you, and trust me, it's actually a (test *)". Nothing has changed, ptr is still just a pointer, an address of a memory location, but the compiler assumes it's pointing to something specific.
check->a = 2; //this raises an error (dereferencing void pointer) when compiling
You must cast your variables every single time you want the compiler to treat it as something different from what you declared it to be.
A more interesting scenario to explain what you can do with casting pointers...
// struct with two ints, a and b
typedew struct testAB {
int a;
int b;
} testAB;
// struct with two ints, named in reverse order
typedef struct testBA {
int b;
int a;
} testBA;
int main(void) {
// construct a testAB struct
void *ptr = malloc(sizeof(testAB));
((testAB *)ptr)->a = 0
((testAB *)ptr)->b = 1
// treat ptr as a testBA struct
if ( ((testBA *)ptr)->a == 1) {
printf("this shouldn't happen, 'a' was set to 0");
}
}
if you run the above code, you will find that the printf statement will be executed. Even though we set 'a' to be 0, and the if statement checks that a == 1.
This is because structs are stupidly simple. In the above example the struct(s) is just two int's packed next to eachother. Much like an array of two ints, like this:
int array[2] = {0, 1};
void *ptr = &array;
Even with this representation, we can lie to the compiler, we can force the compiler to treat this 'array' as one of our structs.
if ( ((testAB *)array)->a == 0 )
printf("a is 0");
This is because, under the hood, the compiler treats named variables in a struct as just offests from where the struct is.
// the following two lines have the same affect
((testAB *)array)->a = 0;
array[0] = 0;
// the following two lines have the same affect
((testAB *)array)->b = 2;
array[1] = 2;
if we tell the compiler that it's a (testAB *), then 'a' means the first int, and 'b' means the second. If we tell the compiler that it's a (testBA *), then 'a' is the second, and 'b' is the first.
In compiled code ALL variable names are lost. The compiler reduces the struct assignment, down to "set the second int of the struct to 2". Or more specifically, if we are dealing with 32-bit ints, set bytes 5, 6, 7 and 8 of the struct to 0000, 0000 0000 0010 (in binary. (or perhaps in reverse order, if we are compiling for a little endian CPU)
In C, is it not possible to make the return type an array? I'm starting to learn about pointers in my operating systems course and I need to make a function that takes 2 arrays as parameters and returns an array containing only the elements that are in both parameter arrays.
This is what I have so far for my C function that returns an array:
#include <stdio.h>
main()
{
printf("Hello world");
int array1[4] = {1, 2, 3, 4};
int array2[4] = {3, 4, 5, 6};
int* inter = intersection(array1, array2);
printf(inter); // <-- also, I don't know how I could get this to work for testing
//freezes program so it doesn't terminate immediately upon running:
getchar();
}
int* intersection(int array1[], int array2[])
{
int arrayReturn[sizeof(array1) + sizeof(array2)];
int count = 0;
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
if(array1[i]==array2[j])
{
arrayReturn[count] = array1[i];
count = count + 1;
}
}
}
return arrayReturn;
}
Another question I have is how could I test this function in the main() method using a printf() statement?
The reason why I need to do this is because we're learning about processes and memory allocation and pointers play a big role in OS development. My professor told me that pointers are so difficult to understand that they leave pointers out of many programming languages.
here we go
#include <stdio.h>
/* declare function, you need to capture array size as well, and also allow
to get result target pointer, result space info and pointer to place where the
size of result will be captured */
int* intersection(int * array1, int a1len , int * array2, int a2len, int* result, int *resultsize, int resultspace);
main()
{
printf("Hello world\n");
int array1[4] = {1, 2, 3, 4};
int array2[4] = {3, 4, 5, 6};
int arrayr[32]; /*result will be in this table */
int resultsize;
int resultspace = 32;
int i;
/* here comes confusion - int resultsize means it will be read as integer,
so we need to write &resultsize to get the pointer,
array declaration like int arrayr[number] is actually understood by system
as a pointer to an integer, pointing to first element of array,
allowing you to use indexes
so arrayr[3] actually means *(arrayr + 3 * sizeof(int))
*/
int* inter = intersection(array1, 4, array2, 4, arrayr, &resultsize, resultspace);
/* inter is now a pointer to arrayr */
for (i = 0; i<resultsize; i=i+1) {
printf("%d\n", inter[i]);
}
//freezes program so it doesn't terminate immediately upon running:
getchar();
}
int* intersection(int * array1, int a1len , int * array2, int a2len, int* result, int *resultsize, int resultspace)
{
/* as we received a pointer to resultsize (*resultsize)
we need to de-reference it using "*" to get or set the actual value */
*resultsize = 0;
int i, j;
for(i = 0; i < a1len; i++)
{
for(j = 0; j < a2len; j++)
{
if(array1[i]==array2[j])
{
result[*resultsize] = array1[i];
*resultsize = *resultsize + 1;
if (resultspace == *resultsize)
return result;
}
}
}
return result;
}
In C, is it not possible to make the return type an array?
No. Some of the characteristics that differentiate arrays from pointers are:
sizeof array evaluates to n * sizeof *array, where n is the number of elements, instead of the size of a pointer.
&array evaluates to a pointer to an array, instead of a pointer to a pointer.
You can use an array to initialise a pointer, eg. int *ptr = (int[]){ 1, 2, 3, 4 };, but you can't use a pointer to initialise an array, eg. int array[4] = ptr;.
You can't assign to an array eg. int array[4]; array = (int[]){ 1, 2, 3, 4 };, but you can assign to a pointer: int *ptr; ptr = (int[]){ 1, 2, 3, 4 };, unless the pointer is declared as a const pointer to int, eg. int * const ptr = NULL; ptr = (int[]){ 1, 2, 3, 4 };
I'm starting to learn about pointers in my operating systems course
and I need to make a function that takes 2 arrays as parameters and
returns an array containing only the elements that are in both
parameter arrays.
This isn't possible. Firstly, your array arguments are actually pointer arguments. Look at sizeof array1 and sizeof array2. Try to initialise an array with them. Try to assign to them. How many of the tests above seem to indicate that they're pointers? When you pass an array to a function, the array expression evaluates to a pointer to the first element of the array. Perhaps you'd want to declare your function to accept pointer to arrays, eg:
int *intersection(size_t sz1, int (*array1)[sz1], // array1 is a pointer to int[sz1]
size_t sz2, int (*array2)[sz2]) // array2 is a pointer to int[sz2]
{ ... }
Secondly, your function clearly returns a pointer value, not an array. Regarding that return value, arrayReturn is declared inside intersection as an array that has automatic storage duration, and so it will be destroyed when intersection returns. When main attempts to use that value, it'll be attempting to use a destroyed array. Returning an array using automatic storage duration isn't possible. Returning a fixed-size struct using automatic storage duration is possible, but this isn't helpful for your problem because your return value would need to be dynamic in size.
Another question I have is how could I test this function in the
main() method using a printf() statement?
You can't do anything with the return value of that function, because using an object that has been destroyed is undefined behaviour.
The reason why I need to do this is because we're learning about
processes and memory allocation and pointers play a big role in OS
development.
The C programming language is independant of OS implementations; It doesn't matter if an OS delays the destruction of objects with automatic storage duration. If you use a destroyed object, you're invoking undefined behaviour.
My professor told me that pointers are so difficult to understand that
they leave pointers out of many programming languages.
Has he/she written out his/her lesson plan? If not, then he/she is missing a crucial point where improvement can be identified. How successful has his/her written lesson plan been in the past? If it's been 100% successful, it doesn't make sense to be using words like "difficult"; Why would you want to unnecessarily trigger overwhelming feelings in students? If parts are too complex, then it makes more sense to identify and clarify those parts, rather than identifying those parts and specifying them as "difficult". It also makes no sense to mention other programming languages in a course about C.
When a professor's lesson plan becomes fairly successful, it becomes feasible to publish it as a book. One example is K&R's "The C Programming Language, Second Edition". Do you have a book?
I was going through how offset of a particular variable is found in a given structure.
I tried the following program .
struct info{
char a;
int b;
char c;
int d;
};
struct info myinfo;
int main(int argc, char **argv)
{
struct info *ptr = &myinfo;
unsigned int offset;
offset = (unsigned int) &((struct info *) 0)->d;
printf("Offset = %d\n",offset);
return 0;
}
I just wanted to know how the line offset = (unsigned int) &((struct info *) 0)->d works.
I am confused because of dereferencing of 0.
It does not really dereference 0, although it looks like it. It really takes the address of some member if it was dereferenced at address 0, hypothetically.
This is a kind of dirty hack (plus, some nasty macro stuff), but it gets you what you're interested in (the offset of the member in the struct).
A more "correct" way of doing the same thing would be to generate a valid object, take its address, and take the address of the member, then subtract these. Doing the same with a null pointer is not all pretty, but works without creating an object and subtracting anything.
You're not actually dereferencing 0. You're adding zero and the offset of the member, since you're taking the address of the expression. That is, if off is the offset of the member, you're doing
0 + off
not
*(0 + off)
so you never actually do a memory access.