Size of Next pointer in linked list? - c

Hello All given a node of linked list as,
struct node
{
int data;
struct node* next;
};
Consider int with 4 bytes.What will be the size of pointer next?
And also i have the following ,
void * ptr;
printf("%d",sizeof(ptr));
Size of pointer is 8 bytes.
I am getting the sizeof(struct node) as 12,how is the size of next pointer's size in the given struct node is 12.Please help me to understand.
Thank You in advance.

On typical systems, the size of a pointer is independent of the size of the data it points to. On a 32-bit system, pointers are 32 bits (4 bytes), and on a 64-bit system, pointers are 64 bits (8 bytes).
Your structure is 12 bytes presumably because it holds a 4-byte int and an 8-byte pointer. However, this is platform-specific and can vary. Many systems require values to be aligned to a whole multiple of their size — that is, a 64-bit pointer must begin at an address that's a multiple of 8 bytes. Compilers will insert padding between structure members to meet alignment requirements.
On my x86-64 Linux system, the size of your structure is 16 bytes: 4 bytes for the int, 4 bytes of padding to reach an 8-byte boundary, and 8 bytes for the pointer.

sizeof(pointer) is a constant regardless of the plain old data type it points to on most common, modern systems. Since you did:
sizeof(ptr)
and got 8 bytes i would hazard a guess that you are on a 64bit system. This indicates to me that your sizeof(struct node) will be 12 bytes because you have the following:
struct node {
int data; // 4 Bytes (32 bit, a common size for `int`s)
struct node* next; // 8 Bytes, as are all pointers on your system
}; // total size of 12 bytes.

What will be the size of pointer next?
The size is sizeof(struct node*)
Code should not be written to depend on a particular result.
The result could be 4 or 8, or 1 or 16 or others.
Writing portable C code relies on not know precisely the answer other than is is of some sane range like 1 to 64.
OP has not mentioned the reason for needing to know value of the size of sizeof(ptr), but the answer is simply the size of a pointer is sizeof(ptr). Code should use sizeof(ptr) rather than a magic number like 4 or 8.
To print the size of a pointer, use
some_type* ptr;
// printf("%d",sizeof(ptr));
printf("%zu",sizeof(ptr));
z Specifies that a following d, i, o, u, x, or X conversion specifier applies to a size_t C11dr §7.21.6.1 7
The size of a pointer like int *, const int *, void *, int (*)() may differ. Portable code does not assume all pointers to various types are of the same size.

Size of a pointer is the number of bytes needed to store the address:
printf("%zu",sizeof(ptr));
printf("%zu",sizeof(struct node *));
printf("%zu",sizeof &abc);
Each of the above should return 8 on a machine with 64-bit addresses and 4 on a machine with 32-bit addresses.
Size of a node can be obtained by dereferencing the pointer:
struct node abc;
void *ptr = &abc;
printf("%zu",sizeof(*((struct node *)ptr)));
The above should return 12 on a machine with 64-bit addresses, as mentioned above.

Related

What is the reason for seemingly inconsistent sizes of pointers and struct types?

On my machine, the relevant sizes are:
sizeof(char) == 1, sizeof(int) == 4 and sizeof(char*) == 8.
#include <stdio.h>
#include <stdlib.h>
typedef struct person{
char *name;
int age;
}Person;
int main()
{
printf("sizeof(Person): %d\n", sizeof(Person)); //-> 16 bytes
Person *person = (Person*)malloc(sizeof(Person));
printf("sizeof(person): %d\n", sizeof(person)); //-> 8 bytes ( Why 8 and not 16? )
char buffer[32];
printf("sizeof(buffer): %d\n", sizeof(buffer)); //-> 32 bytes
person -> name = (char*)malloc(sizeof(buffer));
printf("sizeof(person->name): %d\n", sizeof(person->name)); //-> 8 bytes ( Why 8 and not 32? )
return 0;
}
I know that sizeof(Person) == 16 because of padding, but I don't understand the following.
If sizeof(Person) == 16, why sizeof(person) == 8 and not 16?
And if sizeof(buffer) == 32, why sizeof(person->name) == 8 and not 32?
Because, as sizeof(char *), sizeof(person) returns the size of a pointer. And in your case, a pointer to a struct (here to a Person struct) is of size 8.
And sizeof(person->name) returns the size of a pointer on a char as name is defined as a char *.
buffer is not a pointer, it is an array. The compiler knows it and sizeof(buffer) returns the size of the array, even through there is some similarities between the name of an array and a pointer, they are not treated the same.
For starters to output an object of the type size_t you shall use the conversion specifier zu
printf("sizeof(Person): %zu\n", sizeof(Person));
^^^
I don't understand the following: If sizeof(Person) == 16, why
sizeof(person) == 8 and not 16?
The name Person denotes the structure
typedef struct person{
char *name;
int age;
}Person;
An object of this type occupies 16 bytes.
The name person declared like
Person *person = (Person*)malloc(sizeof(Person));
denotes a pointer. This pointer occupies 8 bytes and points to a memory allocated for an object of the type Person that occupies 16 bytes.
That is sizeof( Person ) and sizeof( Person * ) that is equivalent to sizeof( person ) are two different expressions.
And if sizeof(buffer) == 32, why sizeof(person->name) == 8 and not 32?
Again the name name has a pointer type and occupies 8 bytes. It is a data member of the structure person declared like
char *name;
This pointer points to a dynamically allocated memory that occupies 32 bytes.
Pay attention to that the size of a pointer does not depend on whether it points to a single object or to the first element of an array. That is you can allocate memory for a very big array but nevertheless the size of the pointer pointing to the allocated memory will not be changed depending on the size of the allocated memory.
Consider for example
int a[10];
int *p = a;
int b[10000];
int *q = b;
In this example the pointers p and q have the same size. You could write for example
int a[10];
int *p = a;
int b[10000];
p = b;
The size of the pointer p will not be changed after the last assignment.
As mentioned in a comment by PSkocik.
person is a pointer, same size as pointer to char. same for person->name.
struct person is a type, same size as Person.
This is a core concept in C. It's your breakthrough moment when you get it things start making sense.
A pointer is an address. I can have the address of your house written on a piece of paper and the paper doesn't need to be the size of your house.
I'm not being silly the way we use 'address' in C is closely associated to that real-life concept. But C pointers (addresses) are places in memory. They're represented by the value of some fixed number of bytes.
OK, so the postal system identifies your house by block of characters.
In computers we identify locations in memory be a sequence of bytes. Yes, we use bytes to store the location of other bytes.
malloc(sizeof(Person)) return the address of (a pointer to) a block of memory large enough to hold a Person structure.
It didn't return the block. That's 'somewhere' identified by, can be 'found', accessed, written to and read from using the address.
An pointer/address isn't the thing it's a reference to a thing. Here using reference in the broad computing sense not the slightly narrower sense it's used in C++.
Your machine clearly uses 64-bit addressing. There are 8-bits in a standard byte and and a size of 8 amounts to 64 bits.
The C Standard in some parts talks about pointers functionally. It tells you applying & to suitable expression returns a pointer that can be de-referenced by * or -> to get to the thing or part of it respectively. But it also talks about the 'address-of' operator (being &) and I believe why it uses ampersand which is a stylised 'a'.
To answer the questions.
sizeof(person) is 8 bytes because that's the address of 16 bytes that malloc() has set aside for you to store 16 bytes as requested (the size of a Person object).
The answer regarding person->name is similar. It's the address of 16 bytes not itself 16 bytes.
Add printf("person: %p\n",(void*)person); it will print out the address.
It's implementation defined how it comes out but it's almost certainly going to be like person: 0x7ffca93ce784 (but a different hex value).
That won't change if you change the values in it (e.g. person->age=50;).
Do take heed of that advice that you need to use %zu to output a size.
Also get into the habit of calling free(person); when you've finished with memory you allocated. Render unto free() anything malloc() rendered unto thee.
If not that memory you were allocated can't be reused. That won't affect this little program. But it will become an issue later.
I'd say formalising the distinction between a reference and its referant is a key Computing notion. The something that identifies a thing and the thing. No one has an issue that their name refers to them but isn't them. But somehow when it all gets abstracted into computing you need to consciously understand the distinction more clearly.
All programming languages have this and useful ones have some notion of pointer-like things. In Java it's an Object Variable. That's a reference to an object. Not the object. It even lets slip and if you abuse want gives you a NullPointerException. But I thought Java didn't have pointers! Secret.
The question you'll ask soon is why sizeof(Person) is 16 but sizeof(char*)+sizeof(int) is 12. What (you will ask) are the other 4 bytes doing? I won't go into it but there may be 'dead' bytes in a structure to make things line up nicely. Many computers need (or work more efficiently) if things like pointers and ints are stored at addresses with some low bits set to 0 - it's called alignment and it's a hardware thing!

How does alignment work with pointers to zero-sized arrays?

I was investigating some code I saw that deals with 0-size arrays. Specifically, they are used in the case of dynamically allocated size of a struct such as in https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
Specifically, this is the code in Callgrind:
struct _EventGroup {
int size;
const char* name[0];
};
I was playing around with this, using gcc 4.1.2 on a 64-bit Red Hat, and noticed that the sizeof function returns a size of 8 bytes for the entire struct _EventGroup when the name field is a pointer. Now if I change it to:
struct _EventGroup {
int size;
const char name[0];
};
I get 4 bytes because gcc identifies the 0-size array as taking up no space, and the int as taking up 4 bytes. That makes sense. If I then change it to:
struct _EventGroup {
int size;
const char* name;
};
sizeof returns 16 bytes because the char* takes up 8 bytes in a 64 bit system, and the int has to get padded to 8 bytes. This makes sense. Now, if I do one last change:
struct _EventGroup {
const char* name[0];
};
I get 0 bytes because gcc is detecting my zero-size array. What I want clarified is what's happening in the first case I presented. How much space is gcc allocating for a pointer to a zero size array and why? I'm asking because this code seems designed to be efficient with memory allocation, however it would make sense that gcc either gives the pointer a size of 0 bytes if it detects it points to essentially nothing, or 8 bytes if it is being treated as a normal pointer. Alignment would dictate that I get either 4 bytes or 16 bytes with my original struct. Why am I getting 8 bytes?
Gcc is adding the right amount of padding such that if you actually allocate extra space for the array, the pointer &(eventGroup->name) will be properly aligned.
It seems you're on a platform that has 4-byte ints and 8-byte pointers, so this means you have:
bytes 0-3 -- the int
bytes 4-7 -- padding
bytes 8-15 -- where the first (char *) would be stored, 8-byte aligned
Since it's actually an array of zero size, you don't actually have that first char *, but you do have the padding. Hence, the struct has size 8.
In your second example, there is no alignment requirement for a one-byte char, so you have:
bytes 0-3 -- the int
byte 4 -- where the first (char) would be stored, "1-byte aligned"
Again, no actual char in the struct, so it has size 4.

Size of type and memory allocation [duplicate]

This question already has answers here:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
(13 answers)
Closed 9 years ago.
I've got a trouble with dynamic memory allocation.
Somehow, actual size of my struct (sum of all the parts) is less than size of the type itself. Here is the code:
#include <stdio.h>
#include <malloc.h>
struct Lol {
int a;
char b;
char s[20];
};
void main() {
Lol* lol = (Lol*)malloc(sizeof(Lol));
printf("Type size: %d bytes\n", sizeof(Lol));
printf("Actual struct size: %d bytes\n", sizeof(lol -> a) + sizeof(lol -> b) + sizeof(lol -> s));
}
in this case struct size should be 25 bytes (4 bytes for int, 1 byte for char and 20 bytes for char array), but sizeof(Lol) shows me 28 for some reason as is char type would be treated as int type. What's up with this all? Does this mean i lose 3 bytes on nothing?
actual size of my struct (sum of all the parts) is less than size of the type itself"
Because many computer operations are faster when the values they work on are aligned at certain memory boundaries, the C language standard allows implementations to do such alignment. On most systems, ints will be aligned on 4- or 8- byte boundaries, depending on the size of the int. The size of a struct must be aligned so that the address of the next struct in an array will be properly aligned, so a struct starting with an int aligned to a 4 byte boundary must have a size that is a multiple of 4.
Does this mean i lose 3 bytes on nothing?
Yes. (Well, it's not exactly nothing ... your program will generally be faster because of it.) With modern machines supporting up to 2 terabytes of RAM, this is less of a concern than it once was.

Is size of char * same as size of int *?

I know:
char * is a pointer to char.
and
int * is a pointer to int.
So, i want to confirm following two things:
So now suppose I am on 32 bit machine, then that means memory addresses are 32 bit wide.
Thus that means size of char * and int * is both 32 bits ( 4 bytes), right ?
Also is size of char * * also same as size of int * ?
suppose I have:
int * ptr;
Thus now doing *((char * *) ptr) = 0x154 is same as *((int *) ptr) = 0x514 same, right ?
( 0x514 is just any random memory address)
Platform: I am on x86.
P.S.: I know type casting is not a suggested way to code. But I am doing Kernel coding, thus I HAVE TO do type casting !
In C pointers are not guaranteed to have the same size. Now in reality most implementations pointers will be the same size, but that is an implementation detail of the compiler.
From the C Faq:
The old HP 3000 series uses a different addressing scheme for byte
addresses than for word addresses; like several of the machines above
it therefore uses different representations for char * and void *
pointers than for other pointers
Depending on the ``memory model'' in use, 8086-family processors (PC
compatibles) may use 16-bit data pointers and 32-bit function
pointers, or vice versa.
Also *((char *)ptr) = 0x154 is not the same as *((int *)ptr) = 0x154. Because you are dereferencing the pointer you will write data the size of a char and the size of an int into the location pointed to by ptr. Assuming an 8 bit char and a 32 bit int, *((char *)ptr) = 0x154 will write0x154 to the memory address assigned to ptr and *((int *)ptr) = 0x154 will write 0x0000000154 to the 4 bytes starting at the address assigned to ptr.
Technically speaking, the C standard only guarantees that sizeof(char) == 1, and the rest is up to the implementation. But on modern x86 architectures (e.g. Intel/AMD chips) it's fairly predictable.
You've probably heard processors described as being 16-bit, 32-bit, 64-bit, etc. This usually means that the processor uses N-bits for integers. Since pointers store memory addresses, and memory addresses are integers, this effectively tells you how many bits are going to be used for pointers. sizeof is usually measured in bytes, so code compiled for 32-bit processors will report the size of pointers to be 4 (32 bits / 8 bits per byte), and code for 64-bit processors will report the size of pointers to be 8 (64 bits / 8 bits per byte). This is where the limitation of 4GB of RAM for 32-bit processors comes from -- if each memory address corresponds to a byte, to address more memory you need integers larger than 32-bits.
In practice, pointers will be size 2 on a 16-bit system (if you can find one), 4 on a 32-bit system, and 8 on a 64-bit system, but there's nothing to be gained in relying on a given size

size of C structure

struct st1{
int a:1; int b:3; int c:6; int d:3;
}s1;
struct st2{
char a:3;
}s2;
int main(){
printf("%d : %d",sizeof(s1),sizeof(s2));
getchar();
}
I am getting the output as 2 : 1
will you please tell me, how this program works and whats the use of : operator (a:1) here.
Thank you
The : defines a bit-field.
In your example, objects of type struct st1 use 13 bits in some arrangement chosen by the compiler.
The particular arrangement chosen when you compiled the code originated an object that occupies 2 bytes. The 13 bits are not necessarily the first (or last) in those bytes.
The other struct type (struct st2) occupies (3 bits out of) 1 byte.
The : operator used there specifies sizes in bits of the fields contained there. sizeof() return byte boundary length, so for the first, 13 bits (2 bytes), and for the second, 1 byte.
There's at least two things worth noting here:
Every object must be addressable, which means it will at least occupy the size of one char.
The implementation is free to add padding for alignment or other issues as it sees fit. Iow, a struct containing two ints is not guaranteed to be equal in size to sizeof(int)*2.

Resources