Confusion about the fact that uninitialized pointer points to anywhere - c

#include <stdio.h>
int main(void)
{
int *ptr;
printf("%p", ptr); // Error: uninitialized local variable 'ptr' used
// Output is "0"
}
I'm reading C-FAQ about null pointer. And it says that uninitialized pointer might point to anywhere. Does that mean it points to random location in memory? Also if this statement is true, why does error occur if i try printf("%p",ptr)? Since uninitialized pointer ptr points to some random location, it seems that it must print out this random location!

The contents of an unitialized auto variable (pointer type or otherwise) are indeterminate; in practice, it's whatever was last written to that memory location. The odds that this random bit pattern corresponds to a valid address1 in your program are pretty low; it may even be a trap representation (a bit pattern that does not correspond to a legal value for the type).
Attempting to dereference an invalid pointer value results in undefined behavior; any result is possible. Your code may crash outright, it may run with no apparent issues, it may leave your system in a bad state.
That is, the address of an object or function defined in your program, or a dynamic object allocated with malloc or similar.

Related

Casual value of a not initialized pointer to pointer

When I define a pointer without initializing it:
int *pi;
it points to a random part of the memory.
What happens when I define a pointer to pointer without initializing it?
int **ppi;
Where does it point? It should points to another pointer, but I didn't define it so maybe it points to a random part of the memory? If possible, could you show the difference with an example please?
To make it clear consider the following declaration
T *ptr;
where T is some type specifier. If the declared variable ptr has automatic storage duration then the pointer is initialized neither explicitly nor implicitly.
So the pointer has an indeterminate value.
T can be any type. You can define T as for example
typedef int T;
or
typedef int *T;
Pointers are scalar objects. Thus in this declaration
typedef int *T;
T *ptr;
the pointer ptr has indeterminate value the same way as in the declaration
typedef int T;
T *ptr;
Any local variable that isn't initialized contains an indeterminate value. Regardless of type. There's no obvious difference here between for example an uninitialized int, int* or int**.
However, there is a rule in C saying that if you don't access the address of such an uninitialized local variable, but use its value, you invoke undefined behavior - meaning a bug, possibly a crash etc. The rationale is likely that such variables may be allocated in registers and not have an addressable memory location. See https://stackoverflow.com/a/40674888/584518 for details.
So these examples below are all bad and wrong, since the address of the local variables themselves are never used:
{
int i;
int* ip;
int** ipp;
printf("%d\n, i); // undefined behavior
printf("%p\n, (void*)ip); // undefined behavior
printf("%p\n, (void*)ipp); // undefined behavior
}
However, if you take the address of a variable somewhere, C is less strict. In such a case you end up with the variable getting an indeterminate value, which means that it could contain anything and the value might not be consistent if you access it multiple times. This could be a "random address" in case of pointers, but not necessarily so.
An indeterminate value may be what's known as a "trap representation", a forbidden binary sequence for that type. In such cases, accessing the variable (read or write) invokes undefined behavior. This isn't likely to happen for plain int unless you have a very exotic system that is not using 2's complement - because in standard 2's complement systems, all value combinations of an int are valid and there are no padding bits, negative zero etc.
Example (assuming 2's complement):
{
int i;
int* ip = &i;
printf("%d\n", *ip); // unspecified behavior, might print anything
}
Unspecified behavior meaning that the compiler need not document the behavior. You can get any kind of output and it need not be consistent. But at least the program won't crash & burn as might happen in the case of undefined behavior.
But trap representations is more likely to be a thing for pointer variables. A specific CPU could have a restricted address space or at the low level initialization, the MMU could be set to have certain regions as virtual, some regions to only contain data or some regions to only contain code etc. It might be possible that such a CPU generates a hardware exception even when you read an invalid address value into an index register. It is certainly very likely that it does so if you attempt to access memory through an invalid address.
For example, the MMU might block runaway code which tries to execute code from the data segment of the memory, or to access the contents of the code memory as if it was data.

C pointer initialization differences

I am new to C and have some questions about the pointer.
Question 1 What`s differences b/w the following two? Which way is better to initialize a pointer and why?
int *p=NULL;
int *p;
#include <stdio.h>
void main()
{
char *s = "hello";
printf("%p\t%p",s);
//printf("%p\t%p",&s) it will give me unpredictable result every time
//printf("%p\t%p",(void *)&s) it will be fine
//Question3: why?
}
Question 2: I try to google what is %p doing. According to my reading, it is supposed to print the pointer. It that mean it print the address of the pointer?
Question 1, these are definitions of pointer p. One initializes the pointer to NULL, another leaves it uninitialized (if it is local variable in a function, and not global variable, global variables get initialized to 0 by default). Initializing with NULL can be good, or it can be bad, because compiler can warn you about use of uninitialized variables and help you find bugs. On the other hand compiler can't detect every possible use of uninitialized variable, so initializing to NULL is pretty much guaranteed to produce segmentation fault if used, which you can then catch and debug with a debugger very easily. Personally I'd go with always initializing when variable defined, with the correct value if possible (if initialization is too complex for single statement, add a helper function to get the value).
Question 2, %p prints the address value passed to printf. So printf("%p", pointer); gets passed value of variable pointer and it prints that, while printf("%p", &pointer); (note the extra & there) gets passed address of the variable pointer, and it prints that. Exact numeric format of %p is implementation defined, it might be printed just as a plain number.
Question 3 is about undefined behavior, because format string has more items than what you actually pass to printf. Short answer is, behavior is undefined, there is no "why". Longer answer is, run the application with machine code debugger and trace the execution in disassembly view to see what actually happens, to see why. Note that results may be different on different runs, and behavior may be different under debugger and running normally, because memory may have different byte values in different runs for various reasons.
1) The first is an initialization (to NULL in this case) the second is only a declaration of p as a pointer to int, no initial value is assigned to p in this case. You should always prefer an initialization to prevent undefined behavior.
2) You should cast to void* when using %p to print out a pointer (beware that you are using it too many times in your format specifier). The memory address to which p points is printed.
1)
int *p = NULL
defines and initializes a pointer 'p' to NULL. This is the correct way to initialize pointers in order to get "Seg Fault" if you forget to assign a valid address to this pointer later.
int *p
Only defines a pointer "p" with an unknown address. If you forget to assign a valid value to this pointer before using it, then some compilers will notify you about this mistakes while some others will not and you may access a non-valid address and get a run time error or undefined behaviour of the program.
2) "%p" is printing the address where the pointer is points. Since the pointer holds an address, then "%p" prints this address.
printf("%p\t%p",s);
So the first "%p" will print the address where the pointer "s" points which is the address which stores the string "hello". However, note that you are using twice "%p" but you providing only one pointer to print its address !!
Most compilers will not scream about this cause it is effect-less; however try to avoid it.
Answer1 :
int *p=NULL;
p is a pointer to a int variable initialized with NULL. Here NULL means pointer p is not pointing to any valid memory location.
int *p;
p is a pointer to a int variable. p in uninitialized. Reading uninitialized variables is Undefined Behavior. (one possibility if try to use is that it will throw a segmentation fault)
Answer2:
It prints content of pointer. I mean base address of string "hello"
The main difference is that in *p = NULL, NULL is a pre-defined and standard 'place' where the pointer points.
Reading from Wikipedia,
The macro NULL is defined as an implementation-defined null pointer constant,
which in C99 can be portably expressed as the integer value 0
converted implicitly or explicitly to the type void*.
This means that the 'memory cell' called p contains the MACRO value of NULL.
If you just write int *p, you are naming the memory cell with the name p but this cell is empty.

What address is this pointer assignment returning?

I was playing around with pointers the other day and came up with the following code where I explicitly cast an int variable to int * and print out the address of the explicitly casted variable
#include <stdio.h>
int main (void)
{
int d;
int *p1, *p2;
printf("%p\n", p1 = &d);
printf("%p\n", p2 = (int *) d);
return 0;
}
Here's the output:
ffbff71c
ffbff878
My question is what is that second address and what is contained there?
Garbage - you're printing out the value of an uninitialized variable. It's just total coincidence that it looks like your other address; initialize d to get a meaningful answer.
In the second print, you are not printing an address, but a value converted to an address!
In the first assignment, you're taking the address of the variable, which is just some RAM address. In the second assignment, you're converting the variable's value to a pointer. Since the variable is not initialized, that's the garbage value located at that RAM address.
It is just a random address in memory since d is not initialized.
As others have pointed out, you are converting an indeterminate value to a pointer. Performing that conversion, or indeed doing anything with that value other than overwriting it, produces undefined behavior.
If d's value were set prior to the conversion, then it would matter that C explicitly permits integers to be converted to pointers. However, for this case and most others, the standard says:
the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
[C2011, 6.3.2.3/5]
So basically, don't do that unless you know enough to determine reliably for yourself what the result will be with your particular combination of code, C implementation, compile and link options, and platform.

Assigning an int value to a pointer in C

According to this Berkeley course and this Stanford course, assigning an int to a pointer like so should crash my program:
#include<stdio.h>
int main() {
int *p;
*p = 5;
printf("p is %d\n", *p);
return 0;
}
Yet when I compile this on OSX 10.9.2 using GCC {Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)} I get the following output:
Chris at iMac in ~/Source
$ ./a.out
p is 5
How come? I see the reverse question has been asked (Allocating a value to a pointer in c) but this only confuses me further as my program is nearly identical to the code posted in that question.
You are not allocating int to a pointer. If p is a pointer, *p points to its value. You are assigning *p = 5; which is plain integer to integer assignment.
In this case, p is not initialized and may give rise to segmentation fault.
According to this Berkeley course and this Stanford course, allocating an int to a pointer like so should crash my program:
First off let's get your terminology correct. You are not "allocating an int to a pointer". Allocation is the creation of a storage location. An int is a value. A pointer is a value. A pointer may be dereferenced. The result of dereferencing a valid pointer is to produce a storage location. The result of dereferencing an invalid pointer is undefined, and can literally do anything. A value may be assigned to a storage location.
So you have:
int *p;
You have allocated a (short-lived) storage location called p. The value of that storage location is a pointer. Since you did not initialize it to a valid pointer, its value is either a valid pointer or an invalid pointer; which is it? That's up to your compiler to decide. It could always be invalid. It could always be valid. Or it could be left up to chance.
Then you have:
*p = 5;
You dereferenced a pointer to produce a storage location, then you stuck 5 in that storage location. If it was a valid pointer, congratulations, you stuck 5 into a valid storage location. If it was an invalid pointer then you've got undefined behaviour; again, anything could happen.
printf("p is %d\n", *p); // 5!
Apparantly you got lucky and it was a valid storage location this time.
According to this Berkeley course and this Stanford course [this] should crash my program:
Then those courses are wrong, or you are misquoting them or misunderstanding them. That program is permitted to do anything whatsoever. It is permitted to send an email inviting the president of Iran to your movie night, it is permitted to print anything whatsoever, it is permitted to crash. It is not required to do anything, because "permitted to do anything" and "required to do something" are opposites.
My answers: You're lucky!
The fact is, the value you happen to have in p is a valid memory address, that you can actually write to, this is why it works...
Try playing with optimising options (-O3) in your compiler, than you'll get different results...
Your program is not guaranteed to fail, neither is it guaranteed to succeed. You are dereferencing a pointer which could hold any address. It is undefined behaviour.
It's not that it should crash, but it is undefined behavior.
Depending on the system and the runtime circumstances, assigning to a dereferenced and uninitialized pointer can either segfault or continue running "normally," which is to say that it appears work but may have unusual side effects.

Can pointers behave as variable?

I have a confusion related to this program.
#include <stdio.h>
int main(void)
{
int value = 10;
char ch = 'A';
int* ptrValue = &value;
char* ptrCh = &ch;
int* ptrValue1 = value;
char* ptrCh1 = ch;
printf("Value of ptrValue = %d and value of ptrValue1 = %d\n", *ptrValue, ptrValue1);
printf("Value of ptrCh = %c and value of ptrCh1 = %c\n", *ptrCh, *ptrCh1);
}
I get two warnings while compiling this program
unipro#ubuguest:/SoftDev/ADSD/Module
1/Unit 1/Rd/C/System$ cc
charPointers.c -o charPointers
charPointers.c: In function
‘main’: charPointers.c:11:
warning: initialization makes pointer
from integer without a cast
charPointers.c:12: warning:
initialization makes pointer from
integer without a cast
And I know what they mean.
While running the program I get the following error.
unipro#ubuguest:/SoftDev/ADSD/Module
1/Unit 1/Rd/C/System$
./charPointers Value of ptrValue
= 10 and value of ptrValue1 = 10 Segmentation fault
I know I am getting the error at second printf method.
So my question is if I store a value in pointer, why can't we de-reference it? Does it behave like a variable?
Thanks.
With the assignment
char* ptrCh1 = ch;
you will set the address to 0x41, not the value. The program will later try to de-reference 0x41 (ie. fetch the data at adress 0x41), which is an illegal address. Hence, the segmentation fault
A pointer store the address of something (or NULL). Thus an int* can store the address of an int. You get the address of something with the unary & operator.
So, what does it mean to store 10 in an int pointer ? Well, 10 is not the address of an int, so thus you get the "initialization makes pointer from integer without a cast" warning, and since you are storing something else than the address of an int in an int* and try to dereference it, you get undefined behavior.
What's likely occuring in your case is 10 gets interpreted as a memory address, and when you dereference a pointer it goes out to fetch whatever is at that address (memory address 10 in your case). There's likely nothing there, that memory area is not mapped, and you segfault.
You can dereference it, but the chances that you get a valid chunk of memory are pretty slim. Valid here means, that your process has access rights to that spot.
The OS will prevent you from modifying memory that does not belong to your process. It responds to that kind of invalid memory access with a segmentation fault "exception".
A pointer points to a memory location (in which you can then store some value). Here
int* ptrValue1 = value;
char* ptrCh1 = ch;
you assign a pointer to the value of a variable (not to its address), so the pointer most likely points to an invalid memory location, thus the segfault.
Note that in many architectures, valid memory locations start at a high offset, so a small integer value like 10 or (the ASCII value of) 'A' can never point to a valid memory location. Such low memory locations are typically reserved/used by the OS itself (thus they are protected from modification - if you try, you get a segfault). The same happens usually if you try to directly access memory used by another process.
It's because of *ptrCh1 in the last line, you are trying to dereference it. Remove the * to make it work (not that it makes much sense, though).
Sure that it must segfault. Your are storing whatever value in a pointer (and as you say the compiler warned you) and then you dereference it, regardless where this points to.
What else do you expect?

Resources