Explanation for the size of structs in C? - c

So I'm looking at this code:
#include <stdio.h>
struct Student {
int id;
char name[32];
} s, *sp;
int main() {
printf("sizeof(structStudent) = %u\n", sizeof(structStudent));
printf("sizeof(s) = %u\n", sizeof(s));
printf("sizeof(structStudent*) = %u\n", sizeof(structStudent*));
printf("sizeof(sp) = %u\n", sizeof(sp));
return 0;
}
The output is the following:
sizeof(struct Student) = 36
sizeof(s) = 36
sizeof(struct Student*) = 4
sizeof(sp) = 4
Why is the size of struct Student* 4 and why is the size of sp also 4? My powerpoint does not elaborate on this. I know why the size of struct Student and s is 36: because 32 char bytes+4 bytes(for one int)=36 total.

struct Student * is a pointer and it doesn't contain almost any data, it's merely a pointer. But pointers are stored somewhere and take some space, 4 bytes in your case.
struct Student, however, is a fully-featured struct that occupies as much space as you've calculated (the array and the id take their space).

On your platform, simple pointers occupy 32 bits. That's basically the definition of a 32-bit platform.
The address of the White House doesn't have to be longer than my address just because the White House is bigger than my house.

Related

how to use pointers in structures?

I used pointer while printing structure elements but its working without using pointer in the print statement but shouldn't we use pointers to gather the element from the variable address why is it different in the structure case and its different in string also . Can anyone tell me why is that ?
#include <stdio.h>
int main(){
struct books{
char name[10];
int page;
};
struct books b1={"book1",1};
struct books *ptr;
ptr=&b1;
printf("%s %d",ptr->name,ptr->page);
}
printf("%s %d",*ptr->name,*ptr->page);
is wrong. A->B means (*A).B. You should do either
printf("%s %d",ptr->name,ptr->page);
or
printf("%s %d",(*ptr).name,(*ptr).page);
What MikeCAT said.
Beware though that an array would also be a pointer so *ptr->name would compile but will produce the first character of 'name'.
struct books{
char name[10];
int page;
};
ptr=&b1;
printf("%c",*ptr->name);
Pointers used when the object is too big and copying such object vastes time. But in your struct it takes 10 bytes for char array + 4 bytes for int and it's not a problem. In 64 bit machine pointers take 8 bytes in 32 bit 4 bytes. Suppose you have a big a struct and per object it takes 50 bytes of memory if you copy it will take more space and will be slower and by copying a brand new object will be created and that won't change anything in original one.
Let's see in practice when pointers can be used:
#include <stdio.h>
struct person{
char name[10];
int age;
};
void grow(struct person p) {
++p.age;
}
int main(){
struct person Mike = { "Mike", 20 };
grow(Mike);
printf("Name: %s\tAge: %d", Mike.name, Mike.age);
}
OUTPUT:
Name: Mike Age: 20
This code won't change age of Mike because void grow(struct person p) function copies struct person by creating a new object then increments age and at the end destroys struct person p. If you pass it as pointer then Mike will be modified.

What is the sizeof the pointer pointing to a structure variable?

I am trying to print the size of pointers in both the cases. For both the cases I am getting 8 16 as output.
#include <stdio.h>
struct Book
{
char name[10];
int price;
};
int main(void)
{
struct Book a; // Single structure variable
struct Book* ptr; // Pointer of Structure type
ptr = &a;
struct Book b[10]; // Array of structure variables
struct Book* p; // Pointer of Structure type
p = &b;
printf("%ld %ld\n",sizeof(ptr),sizeof(*ptr));
printf("%ld %ld\n",sizeof(p),sizeof(*p));
return 0;
}
First of all, sizeof operator yields a type size_t, you must use %zu to print that.
Then, usually in any architecture, the size of a pointer is always constant, irrespective of the type they point to. In other words, a pointer needs to hold a memory location, and for any normal architecture, the address (of a memory location) has a fixed size. So, the size of any pointer, is same.
Is this what you want, in the second case:
printf("%zu %zu\n", sizeof(p1), sizeof(*p1));
// Output
8 160
Okay! Let's start from the beginning.
As Sourav Ghosh stated in his answer, "A pointer needs to hold a memory location, and for any normal architecture, the address (of a memory location) has a fixed size. So, the size of any pointer is the same.", regardless of its data type which it points to.
Now coming to your problem, consider and try to understand this modified version of your program:
#include <stdio.h>
struct Book
{
char name[10];
int price;
};
int main(void)
{
struct Book b[10]; // Array of structure variables
struct Book* p; // Pointer to type struct Book
struct Book (*p1)[10]; // Pointer to type struct Book[], which is array of type struct Book
p = b; // same as p = &b[0] but not as p = &b
p1 = &b; // this is how assignment of a pointer to array is done
printf("%zu %zu\n", sizeof(struct Book*), sizeof(struct Book));
printf("%zu %zu\n",sizeof(p),sizeof(*p));
printf("%zu %zu\n",sizeof(p1),sizeof(*p1));
return 0;
}
Output:
// perhaps on your PC
8 16
8 16
8 160
// on my PC
4 16
4 16
4 160
You see in the output that sizeof(struct Book), sizeof(p), and sizeof(p1), all are the same. Thus, size of any type of pointer is the same.
But when you are printing the size of the struct Book, i.e. you are asking the compiler, "tell me how much bytes of memory this struct Book contains",
for the first two cases (sizeof(struct Book) or sizeof(*p)), it is 16 and for the last case it is 160 which is size of 10 variables of type struct Book.
And if you're wondering why 16 as the size of a variable of type stuct Book, that's because of the 2 padding bytes in between the char and int member.
Read this SO question about padding and packing in structures.

sizeof structs and nested structs

I have set up structs in this way.
When I print the sizeof(DATA), I get 16. Why is it 16? I thought it would be 8 as 4 for idx, and 4 for the ptr.
I allocate memory for the STUDENT struct and STATS struct array of size 50. Have I allocated enough memory?
typedef struct {
int idNum;
int classNum;
} STATS;
typedef struct {
STATS * stats;
int currGrade;
}STUDENT;
typedef struct {
STUDENT * ptr;
int idx;
} DATA;
//student_main.c
void function1()
{
DATA d;
func(&d);
}
//student.c
void func(DATA * d)
{
Student * s = malloc(sizeof(STUDENT));
d->ptr = s;
d->ptr->currGrade = 1;
STATS * arr = malloc(sizeof(STATS)* 50);
d->ptr->stats = arr;
d->ptr->stats[0].idNum = 1;
d->ptr->stats[0].classNum = 1;
}
I have set up structs in this way. When I print the sizeof(DATA), I
get 16. Why is it 16? I thought it would be 8 as 4 for idx, and 4 for
the ptr.
Because compiler (may) add padding between/behind struct elements to satisfy alignment constraints. You can read something about data structure alignment here.
In your case of DATA, its 16B because (if your machine is x64)
typedef struct
{
STUDENT * ptr; // 8B pointer
int idx; // 4B int
// 4B padding
} DATA;
I allocate memory for the STUDENT struct and STATS struct array of
size 50. Have I allocated enough memory?
It depends on your needs. You have allocated enough space for 50 structures. Remember to always use sizeof(type) while allocating dynamical memory.
The compiler will pad structures, for example to allow faster access to subsequent elements in 64 bit architectures.
You shouldn't ever need to worry about the numeric value of the size of a struct, as the compiler handles it. Use it only for comparisons, and ignore the absolute value (unless your hobby is reverse engineering the compiler)
It can be 16 for one of two reasons - either You have 32 bit machine and the compiler adds some "space" in Your structure to make the operations faster. You can stop this behavior if You want your structures to be of the exact size, by adding __attribute__ ((__packed__)) to the struct definition. Or You have 64 bit machine with 64 bit pointers and integers. Or a mix of both.
You have allocated enough memory. Doing malloc(x * sizeof(struct xxx)) gives You the confidence.
I recommend reading this excellent article: The Lost Art of C Structure Packing

Declaring multiple structs and overlaying them on already allocated memory

I am very new to C/C++, so I know that this question is probably trivial but I don't understand how to proceed. I have allocated blocks of memory that are 512 bytes each like so (Sector is a struct of size 512 bytes):
char* block = (char *) malloc (sizeof(Sector));
I have another struct that is 128 bytes in size:
typedef struct inode {
int fileSize;
int fileType;
int* blockPointer[30];
} inodeFile;
What I want to do is overlay this struct on the block. I need each block to contain 4 inode structs, but each struct may not have any values associated with it until later on in the program. So for example:
((*inodeFile) block)->fileSize = 10;
If I am understanding correctly, this is setting the first 4 bytes of the pointer block to fileSize. I would continue to do this for each field of the struct.
My question is, how can I do this for 4 different inodes? And since there are 4 different inodes, how can I return the values of each field for the different structs? It seems like simply saying block->fileSize wouldn't work because there can be up to four different file sizes.
You can use a union to overlay the blocks on the sectors. Because the fields are of int type or pointer or size 512 there shouldn't be an alignment problem so long as the natural size is 32-bit.
typedef struct {
int fileSize;
int fileType;
int* blockPointer[30];
} inode;
typedef union {
unsigned char bytes[512];
inode block[4];
} sector;
int main()
{
sector thisec;
thisec.bytes[511] = 0;
thisec.block[0].fileSize = 10;
return 0;
}

Data padding on a 64 bit system discrepancy

This program creates and measures a struct with a pointer (8 bytes) and 3 ints (4 bytes each) and shows there are 4 bytes of data padding.
I don't understand why there are 4 bytes of data padding, either the CPU handles it 8 bytes at a time and there should be another 8 bytes of padding or it handles it 4 bytes at a time and there should be none right?
Or does it stick 2 4 byte values in an 8 byte section of memory and let the CPU split it up at runtime? (This would explain the discrepancy but it seems a bit inefficient to me)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct test {
char *name;
int age;
int height;
int weight;
};
struct test *create(char *name, int age, int height, int weight)
{
struct test *thing = malloc(sizeof(struct test));
thing->name = strdup(name);
thing->age = age;
thing->height = height;
thing->weight = weight;
return thing;
}
void destroy(struct test *thing)
{
free(thing->name);
free(thing);
}
int main(int argc, char *argv[])
{
struct test * t1 = create("bleh",1,2,3);
printf("Sizeof struct: %lu\n",sizeof(struct test));
printf("Sizeof pointer (On 64bit system): %lu\n",sizeof(char *));
printf("Sizeof int: %lu\n",sizeof(int));
destroy(t1);
return 0;
}
Output:
Sizeof struct: 24
Sizeof pointer (On 64bit system): 8
Sizeof int: 4
The entire struct is probably padded at the end, for alignment reasons. This is needed since you might want to have an array of this struct.
The padding you mention makes the struct always end up on an address which is evenly divisible by 8.
The pointer presumably needs to be aligned on 8 bytes. Think about what happens when you form an array of your class, test a[10]. The only way to ensure that a[i].name is aligned on 8 bytes is by padding the class to a multiple of 8 bytes.

Resources