Why is the following C code illegal? - c

Consider a typical environment, why is the following code illegal in C?
{
int x;
&x = (int*) malloc(3*sizeof(int));
...
}

You can't assign something to the address of x because he address of x is not an lvalue
(An lvalue is "something that can be assigned to", i.e. it cannot be on the Left side of an equals sign)
Try
int* x;
x = (int*) malloc(3*sizeof(int)); // TODO: Call free(x)
Now x points to your allocated memory and you can do things like
int foo = *x;
int bar = x[0];
You can assign the address of x to something else, by using the & operator this way:
int x = 1;
int* y = &x; // y now holds the address of x
*y = 2; // Now x = 2

Becauase the address of x is not an lvalue - it is not something that can be modified. C allows you to change things that addresses point to - it does not allow you to change the addreses themselves.

Everyone is correct. The address of X at the time your code executes is a CONSTANT. In other words it says "Hey you can CHANGE where I, the compiler, store the 'x' variable."
you could do this
int main()
{
int* x;
*(&x) = malloc(3*sizeof(int));
}

The address of a variable cannot be changed. Instead you most likely want something like this:
int *x = (int *)malloc(3 * sizeof(int));
...
free(x);

&x returns pointer to x. You can't use it in the left part of an assignment, only on the right.
If you want to assign something to a pointer you have to declare it as a pointer, just like int *x;

Not that this is entirely valuable, but since no one else brought it up (all the above answers are correct, btw, and redundant, I agree that people should vote the right answer up, rather than saying the same thing over and over).
In your example, x is a stack variable. malloc gives you heap memory. That's probably not anything you need to think about too much in today's programming, but if you ever work in an environment where memory is at a premium, you'll want to save your stack as much as possible.
It's also worth noting that for some reason you're allocating 3*sizeof(int). Even if you COULD allocate memory to the stack, in your example, since you're only trying to get 1 int you'd only need 1* sizeof(int), the rest would be wasted.

That's the way the language is designed. To do what you want, use a pointer.

Related

Address of operator and L-values in c

If I run the following code:
int main(){
int x = 0;
int* y = &x;
&x = y;
}
I get the error:
lvalue required as left operand of assignment
I understand this means that when using the addressof operator, the pointer produced is not a valid lvalue, as is reflected in the c documentation.
My question simply is: why?
What is the reason that I cannot change the value of the pointer to my variable x? Is it to prevent the programmer from making mistakes, or does it fundamentally make no sense (in which case please explain why.)
In this line:
&x = y;
Sounds like you're trying to say "I want x to be stored in the address y".
When your declare a variable (x), its address (what you call "pointer value") is a constant value. It's NOT an "lvalue". ("l" for "left", a left part of an assignement operation, so something assignable.)
Also you're not meant to decide yourself where the system sets the datas in memory.
Plus, you're not even sure the "y" address is an allocated place allowed to be written by your process.
Three reasons here to not let you do that. :)
Here & operator gives you the address of the variable x and you are trying to assign something to that address, but that's not possible, it doesn't make sense.
If you want to change the value stored in x, just assign to it:
x = 5;
If you have a pointer (int*) y and you want to assign its value to x, use * operator to get the value y points to (stored in that address) and assign it to x:
x = *y;
If you want to assign the pointer y to x, it is not possible. Use another poiner for for that.
int *y1 = y;
In your code
&x = y
This line shows an error as &x is a constant pointer and hence cannot be changed after it has been initialized

Pointers of pointer and pass by reference

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

How do I use pointers? in C

Im fairly new to C programming and I am confused as to how pointers work. How do you use ONLY pointers to copy values for example ... use only pointers to copy the value in x into y.
#include <stdio.h>
int main (void)
{
int x,y;
int *ptr1;
ptr1 = &x;
printf("Input a number: \n");
scanf("%d",&x);
y = ptr1;
printf("Y : %d \n",y);
return 0;
}
It is quite simple. & returns the address of a variable. So when you do:
ptr1 = &x;
ptr1 is pointing to x, or holding variable x's address.
Now lets say you want to copy the value from the variable ptr1 is pointing to. You need to use *. When you write
y = ptr1;
the value of ptr1 is in y, not the value ptr1 was pointing to. To put the value of the variable, ptr1 is pointing to, use *:
y = *ptr1;
This will put the value of the variable ptr1 was pointing to in y, or in simple terms, put the value of x in y. This is because ptr1 is pointing to x.
To solve simple issues like this next time, enable all warnings and errors of your compiler, during compilation.
If you're using gcc, use -Wall and -Wextra. -Wall will enable all warnings and -Wextra will turn all warnings into errors, confirming that you do not ignore the warnings.
What's a pointer??
A pointer is a special primitive-type in C. As well as the int type stored decimals, a pointer stored memory address.
How to create pointers
For all types and user-types (i.e. structures, unions) you must do:
Type * pointer_name;
int * pointer_to_int;
MyStruct * pointer_to_myStruct;
How to assing pointers
As I said, i pointer stored memory address, so the & operator returns the memory address of a variable.
int a = 26;
int *pointer1 = &a, *pointer2, *pointer3; // pointer1 points to a
pointer2 = &a; // pointer2 points to a
pointer3 = pointer2; // pointer3 points to the memory address that pointer2 too points, so pointer3 points to a :)
How to use a pointer value
If you want to access to the value of a pointer you must to use the * operator:
int y = *pointer1; // Ok, y = a. So y = 25 ;)
int y = pointer1; // Error, y can't store memory address.
Editing value of a variable points by a pointer
To change the value of a variable through a pointer, first, you must to access to the value and then change it.
*pointer1++; // Ok, a = 27;
*pointer1 = 12; // Ok, a = 12;
pointer1 = 12; // Noo, pointer1 points to the memory address 12. It's a problem and maybe it does crush your program.
pointer1++; // Only when you use pointer and arrays ;).
Long Winded Explanation of Pointers
When explaining what pointers are to people who already know how to program, I find that it's really easy to introduce them using array terminology.
Below all abstraction, your computer's memory is really just a big array, which we will call mem. mem[0] is the first byte in memory, mem[1] is the second, and so forth.
When your program is running, almost all variables are stored in memory somewhere. The way variables are seen in code is pretty simple. Your CPU knows a number which is an index in mem (which I'll call base) where your program's data is, and the actual code just refers to variables using base and an offset.
For a hypothetical bit of code, let's look at this:
byte foo(byte a, byte b){
byte c = a + b;
return c;
}
A naive but good example of what this actually ends up looking like after compiling is something along the lines of:
Move base to make room for three new bytes
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable b) to the value of b
Set mem[base+2] (variable c) to the sum mem[base+0] + mem[base+1]
Set the return value to mem[base+2]
Move base back to where it was before calling the function
The exact details of what happens is platform and convention specific, but will generally look like that without any optimizations.
As the example illustrates, the notion of a b and c being special entities kind of goes out the window. The compiler calculates what offset to give the variables when generating relevant code, but the end result just deals with base and hard-coded offsets.
What is a pointer?
A pointer is just a fancy way to refer to an index within the mem array. In fact, a pointer is really just a number. That's all it is; C just gives you some syntax to make it a little more obvious that it's supposed to be an index in the mem array rather than some arbitrary number.
What a does referencing and dereferencing mean?
When you reference a variable (like &var) the compiler retrieves the offset it calculated for the variable, and then emits some code that roughly means "Return the sum of base and the variable's offset"
Here's another bit of code:
void foo(byte a){
byte bar = a;
byte *ptr = &bar;
}
(Yes, it doesn't do anything, but it's for illustration of basic concepts)
This roughly translates to:
Move base to make room for two bytes and a pointer
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable bar) to the value of mem[base+0]
Set mem[base+2] (variable ptr) to the value of base+1 (since 1 was the offset used for bar)
Move base back to where it had been earlier
In this example you can see that when you reference a variable, the compiler just uses the memory index as the value, rather than the value found in mem at that index.
Now, when you dereference a pointer (like *ptr) the compiler uses the value stored in the pointer as the index in mem. Example:
void foo(byte* a){
byte value = *a;
}
Explanation:
Move base to make room for a pointer and a byte
Set mem[base+0] (variable a) to the value of a
Set mem[base+1] (variable value) to mem[mem[base+0]]
Move base back to where it started
In this example, the compiler uses the value in memory where the index of that value is specified by another value in memory. This can go as deep as you want, but usually only ever goes one or two levels deep.
A few notes
Since referenced variables are really just numbers, you can't reference a reference or assign a value to a reference, since base+offset is the value we get from the first reference, which is not stored in memory, and thus we cannot get the location where that is stored in memory. (&var = value; and &&var are illegal statements). However, you can dereference a reference, but that just puts you back where you started (*&var is legal).
On the flipside, since a dereferenced variable is a value in memory, you can reference a dereferenced value, dereference a dereferenced value, and assign data to a dereferenced variable. (*var = value;, &*var, and **var are all legal statements.)
Also, not all types are one byte large, but I simplified the examples to make it a bit more easy to grasp. In reality, a pointer would occupy several bytes in memory on most machines, but I kept it at one byte to avoid confusing the issue. The general principle is the same.
Summed up
Memory is just a big array I'm calling mem.
Each variable is stored in memory at a location I'm calling varlocation which is specified by the compiler for every variable.
When the computer refers to a variable normally, it ends up looking like mem[varlocation] in the end code.
When you reference the variable, you just get the numerical value of varlocation in the end code.
When you dereference the variable, you get the value of mem[mem[varlocation]] in the code.
tl;dr - To actually answer the question...
//Your variables x and y and ptr
int x, y;
int *ptr;
//Store the location of x (x_location) in the ptr variable
ptr = &x; //Roughly: mem[ptr_location] = x_location;
//Initialize your x value with scanf
//Notice scanf takes the location of (a.k.a. pointer to) x to know where
//to put the value in memory
scanf("%d", &x);
y = *ptr; //Roughly: mem[y_location] = mem[mem[ptr_location]]
//Since 'mem[ptr_location]' was set to the value 'x_location',
//then that line turns into 'mem[y_location] = mem[x_location]'
//which is the same thing as 'y = x;'
Overall, you just missed the star to dereference the variable, as others have already pointed out.
Simply change y = ptr1; to y = *ptr1;.
This is because ptr1 is a pointer to x, and to get the value of x, you have to dereference ptr1 by adding a leading *.

Can't understand pointer's mem address result in C

I'm experiencing a mind-blowing doubt concerning the use of pointers in C. So, I've searched a lot about this, but no satisfatory answer was presented to me. Here is the thing:
I declare a pointer of type INT, and a variable of type INT (e.g int x, *pointer). So, let's suppose that both of them occupy sequential addresses in RAM, like 0x102 and 0x106, respectively. No surprises so far. Then, I declare x = 5. My memory map should be like this, shouldn't?
int x, *pointer;
x = 5;
Ok. In the college I learned to assign a pointer this way:
pointer = &x;
And my memory map should be like this:
So far so good. But the question is: if, instead of above, I assign a pointer like this:
*pointer = x;
The memory address of 'x' shouldn't be stored in the pointer's memory address? I always wondered something like the "Memory Map 2", but the result is the same of the "Memory Map 1", that is, the 0x106 address holds a garbage number. So how the program KNOWS where I'd like to point to, if the memory address of 'x' isn't stored at pointer's memory address? Where this information is stored?
It looks like a simple question, but I can't understand. :(
Thanks in advance! :)
Getting how pointers work is tricky. Here's something that might help.
You wrote
int x, *pointer;
which is not just idiomatic; this is telling you something important. It is telling you that the expression x is a variable that can hold an integer; that is hopefully clear. It is also telling you that the expression *pointer is also a variable that can hold an integer.
When you say
x = 123;
that means "store the value 123 in the variable x".
And so when you say
*pointer = 456;
that means "store the value 456 in the variable *pointer".
When you say
pointer = &x;
that means "the expression *pointer -- which remember is a variable that can hold an integer -- is the same variable as x". They are aliases -- two names for the same variable.
So your question is:
How does the program know where I'd like to point to, if the memory address of x isn't stored at pointer's memory address?
Let me rephrase that question using the terminology I've established:
How does the program know which variable *pointer refers to if I do not initialize pointer?
It does not know. If you say:
int x;
printf("%d", x);
then you can get any integer printed; this is undefined behavior. You haven't said what value you want the variable x to have, so it can have any value. When you say:
int *pointer;
*pointer = 123;
Then you are saying "store 123 in variable *pointer", but you haven't said what variable *pointer is. So, just as x can have any value, *pointer can be any variable. Again, we have undefined behavior.
Is that now clear?
int x, *pointer;
*pointer = x;
This is undefined behaviour, because pointer does not point to a valid memory location.
int x, *pointer;
x = 5;
pointer = &x;
*pointer = x;
The last line of this is basically the same as x = x, because pointer points to x;
Since * is the dereference operator, then you will try to:
store the value of x (since there's no addressof, & operator before its name)
to the memory pointed to by pointer (and not into the pointer itself, which wouldn't make sense anyway), which is indeterminate, since your pointer hasn't yet been initialized.
This is not storing the address of x into pointer; what you want is achieved solely by writing pointer = &x;, nothing else will do that. By the way, because of the assignment to the memory pointed to by an uninitialized pointer, *pointer = x invokes undefined behavior.
Doing
*somePtr = someVar
assigns the value of somevar in the place pointed by somePtr ..
To be more comprehensive,
int x = 2, y =3;
int * pointer;
pointer = &x;
*pointer = y;
asiigns the value of y in x . That's it!

What causes this integer pointer reassignment to crash?

I am new to C and i have this question. why does the following code crash:
int *a = 10;
*a = 100;
Because you are trying to write 100 to the memory location 0x0000000A which is probably not allocated to your program. That is,
int *a = 10;
does not mean that the pointer 'a' will point to a location in memory having the value of 10. It means it is pointing to address 10 (0x0000000A) in the memory. Then, you want to write something into that address, but you don't have the "rights" to do so, since it is not allocated
You can try the following:
int *a = malloc(sizeof(int));
*a = 100;
This would work, although horribly inefficient. If you only need a single int, you should just put it into the stack, not the heap. On a 32-bit architecure, a pointer is 32 bits long, and an int is 32 bits long too, so your pointer-to-an-int structure takes up (at least) 8 bytes of memory space this way instead of 4. And we haven't even mentioned caching issues.
You need to assign the pointer to a memory location, not arbitrary value (10).
int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100; // content of cell changed
See my answer to another question, about being careful with C.
I would like to propose a slight change in the use of malloc(), for all the answers that suggest using it to allocate memory for the int. Instead of:
a = malloc(sizeof(int));
I would suggest not repeating the type of the variable, since that is known by the compiler and repeating it manually both makes the code more dense, and introduces an error risk. If you later change the declaration to e.g.
long *a;
Without changing the allocation, you would end up allocating the wrong amount of memory ( in the general case, on 32-bit machines int and long are often the same size). It's, IMO, better to use:
a = malloc(sizeof *a);
This simply means "the size of the type pointed at by a", in this case int, which is of course exactly right. If you change the type in the declaration as above, this line is still correct. There is still a risk, if you change the name of the variable on the left hand side of the assignment, but at least you no longer repeat information needlessly.
Also note that no parenthesis are needed with sizeof when using it on actual objects (i.e. variables), only with type names, which look like cast expressions. sizeof is not a function, it's an operator.
Because you've never allocated any memory for a. You've just allocated some stack space for a pointer to a.
int *a = NULL;
a = malloc (sizeof (int));
if (a != NULL)
{
*a =10;
}
Will work.
Alternatively you could give a the address of some existing variable, which would work as well.
i.e.
int a* = NULL;
int b = 10;
a = &b;
This will now mean that doing something like
*a = 100;
will also set b to be == 100
Check out this:
http://home.netcom.com/~tjensen/ptr/pointers.pdf
The following line,
int *a = 10;
defines a pointer to an integer a. You then point the pointer a to the memory location 10.
The next line,
*a = 100;
Puts the value 100 in the memory location pointed to by a.
The problem is:
You don't know where a points to. (You don't know the value of memory location 10)
Wherever a points to, you probably have no right changing that value. It's probably some other program/process's memory. You thief!
Because You declare a pointer to int, initialize the pointer to 10 (an address) and then try to assign a value to an int at this address. Since the memory at address 10 does not belong to your process, You get a crash. This should work:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
Does this code even compile? 10 isn't convertible to an int *, unless you cast it like so:
int *a = (int *) 10;
*a = 100;
In that case, you're trying to write 100 into the memory address at 10. This isn't usually a valid memory address, hence your program crashes.
It's probably crashing because you are assigning the pointer to some part of memory which you don't have access to and then you're assigning some value to that memory location (which you're not allowed to do!).
You could also write it as:
int* a = 10;
*a = 100;
Note the different spacing on the first line. It's not a popular style, but I personally think it's clearer. It has exactly the same meaning to the compiler.
Then, read it out loud:
"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"
Substituting the actual value:
"Value-pointed-to-by 10 becomes 100"
... at which you realise that 10 is unlikely to point to a piece of memory you can use.
You would pretty much never assign to a pointer with a literal:
int* ptr = (int*)10; // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime
I guess there might be some very low level jobs where you directly specify absolute memory addresses. Kernel implementation for example?
Okay, trying to give the simplest explanation today, while trying to give you more detailed picture about it all. Lets add some parentheses shall we?
(int*) a = 10;
(*a) = 100;
You attempt to write four bytes into the address-range [10-13]. The memory layout of your program starts usually higher, so your application does not accidentally overwrite anything from where it could and still function (from .data, .bss, and stack for instance). So it just ends up crashing instead, because the address-range has not been allocated.
Pointer points to a memory location and C static typing defines a type for a pointer. Though you can override the pointer easily. Simply:
(void*) v = NULL;
Here we go further to things. What is a null pointer? It's simply pointer that points to address 0.
You can also give a struct type for your pointer:
struct Hello {
int id;
char* name;
};
...
struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";
Ok, what is malloc? Malloc allocates memory and returns a pointer to the allocated memory. It has a following type signature:
void* malloc(size_t size);
If you do not have a conservative garbage collector, it is likely that your memory won't end up being freed automatically. Therefore, if you want to get the memory back into use from what you just allocated, you must do:
free(hello_ptr);
Each malloc you do has a size-tag in it, so you do not need to state the size of the chunk you pointed for free -routine.
Ok, yet one thing, what does a character string look like in memory? The one similar to "Cheery" for instance. Simple answer. It's a zero-terminated array of bytes.
0.1.2.3.4.5. 6
C h e e r y \0

Resources