Few doubts about pointers in C - c

1) to initialize a pointer I use:
int number, *Pnumber;
Pnumber=&number;
number=10;
Am I doing this right?
what about:
int *Pnumber;
*Pnumber=10;
When I compile it, I get:
RUN FAILED (exit value 1, total time: 858ms)
btw. do I need to use free(Pnumber) to free the memory?

Am I doing this right?
Yes, you are.
what about:
`int *Pnumber;
*Pnumber=10;`
Pnumber is an unitialized pointer. Dereferencing this pointer leads to an undefined behavior. Pnumber must point to an allocated memory (either to a variable or a dynamically allocated memory area).
btw. do I need to use free(Pnumber) to free the memory?
As long as you don't use malloc, don't use free.

In the first version you point the pointer Pnumber to memory that has already been allocated and thus you may change the value pointed to by the pointer. This version is correct. In the second version you never specify what is the pointer pointing to(it remains uninitialized) and thus when you try to access the memory this will cause an error. So the second version is not correct.

Your first approach is right.
But this wrong:
int *Pnumber;
*Pnumber=10;
Because the pointer doesn't point to valid memory whereas in the first approach it does.

The first one is correct
In the second you are missing pointing the pointer to a memory space.
The pointer is an address so
If we have
int *p;
That means p is an address
and *p is the content of the memory address.
so the pointer should be pointed to a memory space before you fill the memory with
*p = 5;

if you use a Pointer you "point a variable like you did:
int number, *Pnumber;
Pnumber=&number;
number=10;
the advantage of the Pointer is that you save memory to your Program so if you want to change the value of number which is an integer 32bit you can use
*Pnumber = 10;
here you're using integer but if you use a array of them or double or float it a lot of memory and that why it better for you to save the address of the variable in 32 bit in 32bit OS architecture always with pointer in doesn't matter what type you'RE pointing at

Related

Pointer layout in memory in C

I've recently been messing around with pointers and I would like to know a bit more about them, namely how they are organized in memory after using malloc for example.
So this is my understanding of it so far.
int **pointer = NULL;
Since we explicitly set the pointer to NULL it now points to the address 0x00.
Now let's say we do
pointer = malloc(4*sizeof(int*));
Now we have pointer pointing to an address in memory - let's say pointer points to the address 0x0010.
Let's say we then run a loop:
for (i = 0; i<4; i++) pointer[i] = malloc(3*sizeof(int));
Now, this is where it starts getting confusing to me. If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]? And if so, what is pointer[0]?
Continuing, now supposedly pointer[i] contains stored in it an address. And this is where it really starts confusing me and I will use images to better describe what I think is going on.
In the image you see, if it is correct, is pointer[0] referring to the box that has the address 0x0020 in it? What about pointer[1]?
If I were to print the contents of pointer would it show me 0x0010? What about pointer[0]? Would it show me 0x0020?
Thank you for taking the time to read my question and helping me understand the memory layout.
Pointer Refresher
A pointer is just a numeric value that holds the address of a value of type T. This means that T can also be a pointer type, thus creating pointers-to-pointers, pointers-to-pointers-to-pointers, and crazy things like char********** - which is simply a pointer (T*) where T is a pointer to something else (T = E*) where E is a pointer to something else (and so on...).
Something to remember here is that a pointer itself is a value and thus takes space. More specifically, it's (usually) the size of the addressable space the CPU supports.
So for example, the 6502 processor (commonly found in old gaming consoles like the NES and Atari, as well as the Apple II, etc.) could only address 16 bits of memory, and thus its "pointers" were 16-bits in size.
So regardless of the underlying type, a pointer will (usually) be as large as the addressable space.
Keep in mind that a pointer doesn't guarantee that it points to valid memory - it's simply a numeric value that happens to specify a location in memory.
Array Refresher
An array is simply a series of T elements in contiguously addressable memory. The fact it's a "double pointer" (or pointer-to-a-pointer) is innocuous - it is still a regular pointer.
For example, allocating an array of 3 T's will result in a memory block that is 3 * sizeof(T) bytes long.
When you malloc(...) that memory, the pointer returned simply points to the first element.
T *array = malloc(3 * sizeof(T));
printf("%d\n", (&array[0] == &(*array))); // 1 (true)
Keep in mind that the subscript operator (the [...]) is basically just syntactic sugar for:
(*(array + sizeof(*array) * n)) // array[n]
Arrays of Pointers
To sum all of this up, when you do
E **array = malloc(3 * sizeof(E*));
You're doing the same thing as
T *array = malloc(3 * sizeof(T));
where T is really E*.
Two things to remember about malloc(...):
It doesn't initialize the memory with any specific values (use calloc for that)
It's not guaranteed (nor really even common) for the memory to be contiguous or adjacent to the memory returned by a previous call to malloc
Therefore, when you fill the previously created array-of-pointers with subsequent calls to malloc(), they might be in arbitrarily random places in memory.
All you're doing with your first malloc() call is simply creating the block of memory required to store n pointers. That's it.
To answer your questions...
If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]?
Since pointer is just a int**, and remembering that malloc(...) returns the address of the first byte in the block of memory you allocated, *pointer will indeed evaluate to pointer[0].
And if so, what is pointer[0]?
Again, since pointer as the type int**, then pointer[0] will return a value type of int* with the numeric contents of the first sizeof(int*) bytes in the memory block pointed to by pointer.
If I were to print the contents of pointer would it show me 0x0010?
If by "printing the contents" you mean printf("%p\n", (void*) pointer), then no.
Since you malloc()'d the memory block that pointer points to, pointer itself is just a value with the size of sizeof(int**), and thus will hold the address (as a numeric value) where the block of memory you malloc()'d resides.
So the above printf() call will simply print that value out.
What about pointer[0]?
Again assuming you mean printf("%p\n", (void*) pointer[0]), then you'll get a slightly different output.
Since pointer[0] is the equivalent of *pointer, and thus causes pointer to be dereferenced, you'll get a value of int* and thus the pointer value that is stored in the first element.
You would need to further dereference that pointer to get the numeric value stored in the first integer that you allocated; for example:
printf("%d\n", **pointer);
// or
printf("%d\n", *pointer[0]);
// or even
printf("%d\n", pointer[0][0]); // though this isn't recommended
// for readability's sake since
// `pointer[0]` isn't an array but
// instead a pointer to a single `int`.
If I dereference pointer, by doing *pointer what do I get? pointer[0]?
Yes.
And if so, what is pointer[0]?
With your definitions: 0x0020.
In the image you see, if it is correct
It seems correct to me.
is pointer[0] referring to the box that has the address 0x0020 in it?
Still yes.
What about pointer[1]?
At this point, I think you can guess that it woud show: 0x002c.
To go further
If you want to check how memory is managed and what pointers look like you can use gdb. It allows running a program step by step and performing various operations such as showing the content of variables. Here is the main page for GNU gdb. A quick internet search should let you find numerous gdb tutorials.
You can also show the address of a pointer in c by using a printf line:
int *plop = NULL;
fprintf(stdout, "%p\n", (void *)pointer);
Note: don't forget to include <stdio.h>

How to limit the size allocated memory?

While studying pointers I found that if I allocate memory for a 2 digit int I can give that int a higher value. Can someone explain me why it works like that and how to work around it?
Here is the code:
int *p;
p = (int *) malloc(2*sizeof(int));
p = 123456;
First of all, Please see this discussion on why not to cast the return value of malloc() and family in C..
That said, here, you're just overwriting the pointer returned by malloc(). Don't do that. It will cause memory leak. Also, if you try to dereference this pointer later, you may face undefined behavior, as there is no guarantee that this pointer points to a valid memory location. Accessing invalid memory leads to UB.
Finally, to address
I allocate memory for a 2 digit int [...]
let me tell you, you are allocating memory to hold two integers, not a two digit integer. Also, to store the integer values into the memory area pointed by the pointer, you need to dereference the pointer, like *p and store (assign) the value there, like *p=12345;.
malloc() allocates memory of the size of bytes passed as it's argument. Check the sizeof(int) (and 2*sizeof(int), if you want) to make it more clear.
Regarding this, quoting C11, chapter
void *malloc(size_t size);
The malloc function allocates space for an object whose size is specified by size [...]
So, here, malloc() returns a pointer with the size of two integers (i.e., capable of holding two integer values), not two digits or bytes.
Also, it's always a good practice to check the success of malloc() before using the returned pointer to avoid the possible UB by dereferencing NULL in case of malloc() failure.
if i allocate memory for a 2 digit int i can give that int a higher value.
No, you cannot. You have allocated memory for two ints, with full int range. Standard guarantees at least five digits (215-1), but on most modern systems you are safe with eight digits (231-1).
Back to your question, there is no way in C to ensure that your program does not write past the end of the memory that it allocates. It is the responsibility of your program to not do that, including any checks it must perform in order to catch potentially unsafe access.
This is called undefined behavior. The system may crash when you access memory past the end of the allocated area, but it does not have to.
allocate memory for a 2 digit int
malloc(2*sizeof(int)) allocates memory for two integers, not for a single two-digit integer.
you do not need the cast in the first place
You are allocated memory for two integers - typically 32 bits each
You are giving a pointer the value 123456
Perhaps reread the book

Linked Lists in C, last node point to NULL?

In C, must I always initialize my last node pointing to NULL? I generally see this happening in tutorials and in books. But to my understanding, an unitialized pointer holds the same address as a NULL pointer. So why initialize?
But to my understanding, an uninitialized pointer holds the same address as a NULL pointer
It might, by (bad) luck.
In any case reading out an uninitialised pointer invokes undefined behaviour. Whether this would lead to a crash (or any other "strange" behaviour) sooner or later is unknown, as by the nature of undefined behaviour.
However depending on how the memory the pointer variable "lives" in is allocated, the memory might come as "already" initialised, if allocating
it statically or
via calling calloc()
Both methods allocate memory and 0 it out in advance. Which, for most recent systems, is sufficient to have a pointer variable (living inside this memory) carrying the value of NULL.
But please note that there still might be implementations around that use a different bit pattern for NULL than just 0-bits. So to stay 100% portable it is good advice to always initialise with NULL explicitly and not rely on implicitly cleared out memory. And btw, this also helps the potential reader of your sources.
When you create a pointer without initializing it, let's say
char *ptr;
The memory points to some bytes (depending on your pointer type).
Those bytes, may be anything. Like some previous initialized unfreed pointer, or, to some garbage.
Which is not the same as a NULL pointer.
To avoid that, you should take the habit of initializing every of your pointers (except for globals and statics which are initialized to 0) and, add a NULL every-time you work with arrays or anything containing multi-elements.
Let's say that in this case, NULL is the '\0' of the array/list.
For example, if you want to create an array containing a few char *, do it this way :
void function()
{
char *array[4];
array[0] = strdup("Jason");
array[1] = strdup("Mike");
array[2] = strdup("Nicole");
array[3] = NULL;
}
It helps you not to go further than the memory you previously allocated for this pointer, avoiding memory fails, and segmentation faults. In case you're using a counter to get through every case of this array.
Otherwise, don't use NULL everywhere, if you allocated a string, don't fill it with NULL after on.
int main()
{
char *ptr;
if ((ptr = malloc(sizeof(char) * 42)) == NULL)
return (-1);
ptr = NULL;
return (0);
}
This won't work because you're sending NULL into the bytes you cleaned straight before.
If you want to properly use a pointer and clean it before using it, you can use memset. Which will send a x amount of the same byte into the pointer, cleaning the garbage that might be in it by the bytes you passed into memset parameters.
You might think that null pointer is the pointer that is uninitialized, but it's wrong. Null pointer is a special pointer which doesn't points to anywhere.
// To declare a null pointer.
int *ptr=NULL;
if(ptr==NULL) //..do something..
Functions like malloc() and getchar() returns null pointer in case they are unable to perforn their task or complete the task.
An uninitialized pointer can hold any garbage value.
an uninitialized local variable's value is undefined. while the static or global will grantee to be 0.
it is a good practice to initialize all variable you defined, otherwise, it may result very very trick bug.
Contrary to your understanding, the content of an uninitialized pointer is undefined. Only if the object is statically allocated is it guaranteed to be zero initialised.

Putting an int in an int pointer gives runtime error in C .

The following code works fine in ideone but it gives a runtime error in codeblocks IDE . Is my IDE broken or is there any programming language specific issues .
#include<stdio.h>
int main(){
int *pointer;
int num = 45;
*pointer = num;
printf("pointer points to value %d", *pointer);
return 0;
}
replace this
*pointer = num;
by
pointer = &num;
Your pointer should be pointed to a memory space before assignment of value to it.
When you define pointer in this way:
int *pointer;
This meas that you have defined pointer but the pointer is not yet pointing to a memory space. And if you use the pointer directly without pointing it to a memory space (like you did in your code) then you will get undefined behaviour.
pointing the pointer to amemory space could be done by one of the following way:
1) pointing to a static memory
int num;
int *pointer = &num;
num is an int defined as a static. So the pointer could be pointed to the num memory
2) pointing to a dynamic memory
int *pointer = malloc(sizeof(int));
the pointer could be pointed to a dynamic memory. the dynamic memory could be allocated with malloc() and when the memory became useless we can free memory with free(pointer)
Assign address of num to pointer as pointer is supposed to hold address not value. You can read more about pointers here
pointer = &num;
Change value of variable through pointer
*pointer = 11;
First,you have defined a pointer by "int *pointer".
Then, you try to use "*pointer = num" to realize indirect access —— assign num's value to the memory space which the pointer "pointer" has pointed to.
OK, here is the problem! From your codes, you only have defined a pointer, but you have not made it pointed to a memory space. Making indirect access without doing it is very dangerous. So, you see the runtime error.
Now, you should add "int value;pointer = &value;" to your codes. It will make the pointer "pointer" point to "value". And you can assign "num" to "value" through indirect access "*pointer = num".
In my opinion, you should distinguish definition and indirect access when you study pointer.
I'm a person with poor English. This is my first answer in stack overflow. I hope that my answer can help you. Thank you.
First of all u should initialize the pointer as to which its trying to point then use it to modify the pointed value..as...
pointer=&num;
now use the pointer to change or access the value to which its pointing.

Memory allocated in char * var; declaration

In C, declaring a char pointer like this
char* p="Hello";
allocates some memory for a string literal Hello\0. When I do this afterwards
p="FTW";
what happens to the memory allocated to Hello\0? Is the address p points to changed?
There is no dynamic memory allocation in either statement.
Those strings are stored in your executable, loaded in a (likely read-only) section of memory that will live as long as your process does.
The second assignment only changes what p points to. Nothing else happens.
The memory remains occupied by "Hello". It is lost (unless you have other references to it).
The address p is pointing to (the value of p) is changed of course.
In this case, "Hello" is created at compile time and is part of the binary. In most situation "Hello" is stored in read only memory. "FTW" is also part of the binary. Second assignment will only change the pointer.
in addition - "Hello" and "FTW" have static storge duration as Met have pointed out
It creates a string constant that cannot be modified and should be used as it is.
If you try doing
p[0]='m';
It would give segmentation fault since this is not string literal with allocated memory in which you can reassign and read back values.
what if
p = getbuffer();
getbuffer()
{
return buf = malloc(buf, size);
}
how can free this memory before allocating new memory to p! imagine that p should use getbuffer() many times.

Resources