My understanding is that when you declare a pointer, say int *a = 5, a is the pointer, and *ais the int pointed to - so the * indicates you're accessing the pointer data. (And the & is accessing the address). Hopefully this is correct?
How come when I'm doing printf it doesn't seem to work the way I want?
int main()
{
int *a = 5;
printf("%d\n",a);
return 0;
}
This gives me the correct result, which I didn't expect. When I did *a instead of a in the printf, it failed, which I'm confused with?
Nopes, int *a = 5; does not store an int value of 5 into the memory location pointed by a, the memory location itself is 5 (which is mostly invalid). This is an initialization statement, which initializes the variable a which is of type int * (a pointer) to 5.
For ease of understanding, consider the following valid case
int var = 10;
int *ptrVar = &var;
here, ptrVar is assigned the value of &var, the pointer. So, in other words, ptrVar points to a memory location which holds an int and upon dereferencing ptrVar, we'll get that int value.
That said, in general,
printf("%d\n",a);
is an invite to undefined behavior, as you're passing a pointer type as the argument to %d format specifier.
The declaration int *a does declare a to be a pointer. Thus, the declaration
int *a = 5;
initializes a with the value 5. Just like how
int i = 5;
would initialize i with the value 5.
There are very few situations where you would want to initialize a pointer variable with a literal value (other than 0 or NULL). Those would likely be embedded (or otherwise esoteric) applications where certain addresses have a defined meaning on a particular platform.
Related
Though it is very basic and might seem silly, I am trying to understand what is difference between the int *ptr = 45 or 0xc8750; (some number) vs. int *ptr= &a; (address of variable).
What I already know is:
Pointers are made to store address of variables and to modify contents of pointed variables ( but I want to know how it will be achieved)
In latter case, I can assign *ptr to different address that is legal.
But, in first case it is illegal!.
Why the latter is illegal if both address/number are integers?
How differently will they be treated while storing in memory?
I have two piece of code/programs basically to highlight the same:
case-1:
#include <stdio.h>
int main()
{
int *ptr = 0xc42; // is this stored in read only memory?!! which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
return 0;
}
case-2:
int main()
{
int a=10, b=20;
int *ptr = &a; // is here get any special treatment and object will be created for *ptr!!!
*ptr = &b; //legal
printf(" *ptr = %d \n", *ptr);
*ptr = 20; //legal !!
printf(" *ptr = %d \n", *ptr);
*ptr = 50; //legal
printf(" *ptr = %d \n", *ptr);
return 0;
}
As we can see the *ptr = 20 and *ptr = 50 are legal and fine! (No segmentation faults).
Why is this assignment of int *ptr = 0xc989 or 5 different from int *ptr = &variable?.
Let's start from basics: a pointer is a variable containing the address pointing to data of a given type. If we declare
datatype* foo;
foo (that is currently not initialized) will contain the address of a variable of type datatype, and deferencing it
*foo = ...;
we are accessing that address and storing there its value.
In both cases we have * foo, but they're not the same!
In the first case the asterisk refers to datatype. The variable type is datatype *; the variable name is foo. foo contains an address.
In the second case we are dereferencing the address, in order to access it. The asterisk refers to the variable in order to perform the pointer dereferentiation.
So, when you write
int *ptr = 0xc42; // is this stored in read only memory?!!
// which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
With int *ptr = 0xc42; you are saying to the compiler that you are declaring a variable named ptr, of type int * and whose first value is 0xC42. (Note: as correctly stated by user Lundin, this assignment requires a further cast in order to be valid C).
With *ptr = 45; you are accessing the address pointed by ptr and assigning value 45. Is it legal? Well, it is if you previously assigned a valid address (and generally speaking it is if you assign to a pointer another variable's address with & operator, e.g int *ptr = &a;). But if you assign a random integer to it... it will likely lead to a segmentation fault.
Logically, if you are sure that the location, 0xc989, preserves what you need, int *ptr = 0xc989 perfectly valid (with regard to your thinking concept, as said by Roberto Caboni).
Technically, as said by Lundin, you need to cast it according to C standards.
First of all int *ptr = 0xc42; is not valid C and will not compile cleanly on a compiler configured to strict standard C. With gcc, clang and icc this means compiling with -std=c11 -pedantic-errors. For details, see "Pointer from integer/integer from pointer without a cast" issues.
int *ptr = (int*)0xc42; is valid C but fishy. To clarify, this stores an address inside the pointer variable itself, it doesn't store a value. So if you know that there is an int-sized item at memory address 0xc42, such as a memory-mapped hardware register, then you can point directly do it. But when doing so, it will only be meaningful to do that using volatile: volatile int *ptr = (volatile int*)0xc42;. Code like that mostly makes sense in embedded systems and other hardware-related programming.
As for why your second example works fine, the addresses there are assigned by the linker and not by the programmer, so they will point at valid, allocated data.
I'm struggling to understand how pointers work.
The way I got it is that, when I declare a pointer to, say, int, I create both a variable that'll contain an address (that must be initialized to even operate on the int) and an int variable. Visually, I'd represent this this way (address;int). For example, if I declared
int* number;
I'd have "number" being the address variable and "*number" being the int variable.
Likewise, declaring something such as int** d should mean to create a pointer to (address;int). That'd be [address;(address;int)].
With this in mind, I was trying to modify the int value of **d by using an external function, incrementer_3, and this so called pass by reference, but I get an error on runtime. So, I was wondering what I'm missing.
#include <stdio.h>
void incrementer(int* a) {
(*a)++;
}
void incrementer_2(int** a) {
(**a)++;
}
void incrementer_3(int*** a) {
(***a)++;
}
int main() {
int b = 7;
incrementer(&b);
printf("%d\n", b);
int* c = (int*)malloc(sizeof(int));
*c = 4;
incrementer_2(&c);
printf("%d\n", *c);
int** d = (int**)malloc(sizeof(int*));
**d = 6;
incrementer_3(&d);
printf("%d\n", **d);
system("pause");
}
FYI the part when I increase b and c works fine.
On a side note, I was also wondering if it's possible to modify the value of *c by using the function "incrementer" and not "incrementer_2". In fact I was just thinking that I could have simply written from main
incrementer(&(*c));
or, in a simpler way
incrementer(c);
but none of them work on runtime.
You need to keep in mind that a pointer need not actually refer to anything, and even if it does refer to something that something need not be valid. Keeping track of those things is your job as a programmer.
By convention an invalid pointer will be given the value 0 (which is what NULL eventually comes to) but that is only convention, other values might be used in some circumstances.
So, with "int* number;" you have declared a pointer-to-int but because it is not initialized you have absolutely no idea what value it contains, dereferencing it at this point is undefined behavior - meaning that most anything could happen if you tried doing so, though in reality it will likely simply crash your program.
The problem with:
int** d = (int**)malloc(sizeof(int*));
**d = 6;
is that while d is initialized *d is not. You could do:
*d = malloc(sizeof(int));
or
*d = c;
but *d needs to be pointed at something before you can use **d.
int b
b is an int. We can refer to it by writing b.
b = 7;
Here we assign a number to b.
int* c
c is a pointer that should point to an int. We can refer to that int by writing *c.
c = (int*)malloc(sizeof(int));
We have found a piece of memory that can hold an int, and made a pointer that points to that piece, and assigned it to c. All is well.
*c = 4;
Here we assign a number to *c. See? *c behaves just like b. But that's only because we have initialised it with a valid pointer! Without that, *c = 4; would be invalid.
int** d
d is a pointer that should point to a thing of type int*, which we can refer to by writing *d. That int* thing, in turn, should point to an int, which we can refer to by writing **d.
d = (int**)malloc(sizeof(int*));
We have found a piece of memory that can hold an int*, and made a pointer that points to that piece, and assigned it to d. All is well. Now that int* we call *d, what does it point to?
Nothing. In order to point it to something, we could have found a piece of memory that can hold an int, and made a pointer that points to that piece, and assigned it to our *d, just as we have done earlier with c. See? *d behaves just like c. In order to use *c we had to initialise c with a valid pointer first. In order to use **d we need to initialise *d with a valid pointer first.
*d = (int*)malloc(sizeof(int));
The problem is that you allocate memory for the int* but you don't allocate any memory for the int or set the pointer of the int.
Should be:
int** d = (int**)malloc(sizeof(int*));
*d = (int*)malloc(sizeof(int));
**d=6;
The way I got it is that, when I declare a pointer to, say, int, I create both a variable that'll contain an address (that must be initialized to even operate on the int) and an int variable.
No, when you declare a pointer you create a variable that knows how to contain an address. When you use malloc() you allocate memory. malloc() returns an address that you may assign to your pointer.
P.S. - incrementer(c) should work just fine
Output is: 10 and it gives no error.
int main(){
int j=10;
int *i=&j;
printf("%d",*i);
return 0;
}
but it gives me an error:
int main(){
int *i;
int j=10;
*i=&j;
printf("%d",*i);
return 0;
}
I understand that pointer de-referencing is causing the error. But how is that happening?
Because you are using an uninitialized pointer.
Your *i = &j should be i = &j
This defines i as an int * and sets its value to the address of j:
int *i=&j;
This defines i as an int *, then tries to set what i points to to the address of j:
int *i;
int j=10;
*i=&j;
The final *i = ... is trying to dereference an uninitialized variable.
int *i=&j;
Here you're declaring i to be a int *, and assigning the address of j.
*i=&j;
In this case, though, you've already declared i, and you're assigning &j to the location that i points to rather than to i itself. So that's one error. Another is that i doesn't point to anything yet because you haven't initialized it. If you want i to point to j, you should drop the *:
i = &j;
i itself is declared as a "pointer to int". So you should write i = &j; to assign it with the address of j.
In your case, *i = &j dereferences it before the assignment, that is, the value of a pointer is assigned to an int, which resides in a legal or illegal memory block, because i is uninitialised.
Note that accessing an uninitialised variable causes undefined behaviour, not to mention accessing the object an uninitialised pointer points to.
Here is a simple declaration, with initialization, of an integer variable i:
int i = 10;
Normally it is very easy to split up the declaration and the initialization:
int i;
/* ... */
i = 10;
That's fine. But the syntax of pointer declarations in C is unusual, and it leads to a little bit of asymmetry when working with declarations and initializations. You can write
int *i = &j; /* correct */
But if you split it up, the * does not tag along, because it was part of the declaration.
int *i;
/* ... */
i = &j; /* right */
*i = &j; /* WRONG */
int *i;
You've declared i as a pointer to int, but you haven't set it to point to anything yet; the value of i is indeterminate1. It will contain some random string of bits that (most likely) does not correspond to a valid address2. Attempting to dereference i at this point leads to undefined behavior, which can mean anything from an outright crash to corrupted data to working without any apparent issues.
The line
*i = &j;
has two problems, the first one being that i doesn't point anywhere meaningful (and this is where your runtime error is undoubtedly coming from; you're attempting to access an invalid address). The second is that the types of *i and &j don't match; *i has type int, while &j has type int *.
Variables declared locally to a function without the static keyword have automatic storage duration, and are not implicitly initialized to any particular value. Do not assume that any such variable is initially set to 0 or NULL in the absence of an explicit initializer. Variables declared outside of any function body or with the static keyword have static storage duration, and those variables will be initialized to 0 or NULL in the absence of an explicit initializer.
"Valid" meaning the address of an object defined within your program (i.e., another variable, or a chunk of memory allocated via `malloc`, etc.) or a well-known address defined by the platform (such as a fixed hardware input address). NULL is a well-defined invalid address that's easy to test against.
I have to questions about pointers; one theoretical and one practical.
Why, when declaring a pointer in C, must I preface the *var with a type. If a pointer is simply a variable that contains a memory address why does the compiler/language need any more information than that it is a pointer. What is the difference between an int * and a char *. Does this imply that an int * is pointing a some location that contains 2-4 bytes of memory and a char * contains only 1? I have never read anything about the underlying reasoning for why the type matters if ultimately it is a variable pointing to some hexadecimal number as evidence by %p printing them.
Secondly, given this code
int t = 10;
int *i = &t;
int *j = i;
--
*i == 10;
*j == 10;
Why is it that *j is equal to 10 instead of **j being 10? If j is a pointer to i which is a pointer to t which is 10 don't i need to double dereference the variable j? When writing this code in xcode it forces me to use *j.
So these are a few examples of confusion I have had with pointers.
The datatype is required in order to know how many bytes to read when the pointer is dereferenced.
int *i = &t;
Here, the value stored in i is the address of t.
int *j = i;
So now, the value stored in j is the value stored in i which is the address of t. If you wanted to do a double dereference, you'd need to store the address of i.
int **j = &i
why does the compiler/language need any more information than that it is a pointer
To use the pointer only, the compiler doesn't. The type void* means "a pointer to anything".
However, to use the value that is being pointed to, the compiler needs to know the type of what is being pointed to, so that it knows what can be done with it. Dereferencing a void* will cause a compiler error, unless you first cast it to a typed pointer.
Secondly, given this code
j is not a pointer to i. The assignment int *j = i; sets j to the same value as i, which is the address to t (so j would now point to t).
To make j a pointer to i, you would need to declare it as int **j = &i;
why does the compiler/language need any more information than that it is a pointer.
That's because different data types are of different size and size of data types are needed to allocate memory.
What is the difference between an int * and a char *.
int * is a pointer to int and char * is a pointer to a char.
Why is it that *j is equal to 10 instead of **j being 10? If j is a pointer to i which is a pointer to t which is 10 don't i need to double dereference the variable j?
int *j = i; tells the compiler that declare j as pointer to int and point this pointer to the memory location where pointer i points to. Therefore j is a pointer to variable t.
C is a statically typed language. There are other languages, like JavaScript for example, which are dynamically typed, where you can assign objects of different types to the same variable.
Both approaches have their advantages and disadvantages, the most important advantage of statically typed languages is that many errors can be caught at compilation.
It's a design decision.
I am trying to learn C. The reading I've been doing explains pointers as such:
/* declare */
int *i;
/* assign */
i = &something;
/* or assign like this */
*i = 5;
Which I understand to mean i = the address of the thing stored in something
Or
Put 5, or an internal representation of 5, into the address that *i points to.
However in practice I am seeing:
i = 5;
Should that not cause a mismatch of types?
Edit: Semi-colons. Ruby habits..
Well, yes, in your example setting an int pointer to 5 is a mismatch of types, but this is C, so there's nothing stopping you. This will probably cause faults. Some real hackery could be expecting some relevant data at the absolute address of 5, but you should never do that.
The English equivalents:
i = &something
Assign i equal to the address of something
*i =5
Assign what i is pointing to, to 5.
If you set i = 5 as you wrote in your question, i would contain the address 0x00000005, which probably points to garbage.
Hope this helps explain things:
int *i; /* declare 'i' as a pointer to an integer */
int something; /* declare an integer, and set it to 42 */
something = 42;
i = &something; /* now this contains the address of 'something' */
*i = 5; /* change the value, of the int that 'i' points to, to 5 */
/* Oh, and 'something' now contains 5 rather than 42 */
If you're seeing something along the lines of
int *i;
...
i = 5;
then somebody is attempting to assign the address 0x00000005 to i. This is allowed, although somewhat dangerous (N1256):
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
...
5 An integer may be converted to any pointer type. Except as previously specified, 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.56)
...
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17.
56) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.
Depending on the architecture and environment you're working in, 0x00000005 may not be a valid integer address (most architectures I'm familiar with require multibyte types to start with even addresses) and such a low address may not be directly accessible by your code (I don't do embedded work, so take that with a grain of salt).
I understand to mean i = the address of the thing stored in something
Actually i contains an address, which SHOULD be the address of a variable containing an int.
I said should because you can't be sure of that in C:
char x;
int *i;
i = (int *)&x;
if i is a pointer, than assign to it something different to a valid address accessible from you program, is an error an I think could lead to undefined behavior:
int *i;
i = 5;
*i; //undefined behavior..probably segfault
here's some examples:
int var;
int *ptr_to_var;
var = 5;
ptr_to_var = var;
printf("var %d ptr_to_var %d\n", var, *ptr_to_var); //both print 5
printf("value of ptr_to_var %p must be equal to pointed variable var %p \n" , ptr_to_var, &var);
I hope this helps.
This declares a variable name "myIntPointer" which has type "pointer to an int".
int *myIntPointer;
This takes the address of an int variable named "blammy" and stores it in the int pointer named "myIntPointer".
int blammy;
int *myIntPointer;
myIntPointer = &blammy;
This takes an integer value 5 and stores it in the space in memory that is addressed by the int variable named "blammy" by assigning the value through an int pointer named "myIntPointer".
int blammy;
int *myIntPointer;
myIntPointer = &blammy;
*myIntPointer = 5;
This sets the int pointer named "myIntPointer" to point to memory address 5.
int *myIntPointer;
myIntPointer = 5;
assignment of hard-coded addresses, is something that shouldn't be done (even in the embedded world, however there are some cases where it's suitable.)
when declaring a pointer, limit yourself to only assign a value to it with dynamiclly allocated memory(see malloc()) or with the & (the address) of a static (not temporary) variable. this will ensure rebust code, and less chance to get the famous segmentation fault.
good luck with learning c.