Passing pointers as argument - c

int *tomato(int *a, int *b) {
int *foo = (int*)malloc(sizeof(int));
*foo = *a + *b;
return foo;
}
In this function I have foo that is allocated in heap and returns a pointer to int, but are the pointers *a and *b in the function arguments also allocated in heap? I am a bit confused here, generally, arguments are allocated in stack.

The pointers are local variables in the tomato function, just like foo.
The values that they point to can be allocated anywhere. For instance, you can call it like this:
int foo = 1;
int *bar = malloc(sizeof(int));
*bar = 3;
int *result = tomato(&foo, bar);
a will point to a the foo variable, while b will point to the memory allocated by malloc.

Parameters in C are not necessarily allocated in the stack (*), but their scope will necessarily be restricted to the tomato function block, and they will necessarily be passed by value.
When you dereference a and b in the assignment *foo = *a + *b, you are interpreting the memory address stored in pointers a and b as integers, summing them, and writing the result in the memory address stored in pointer foo (which, in your example, happens to be in the heap).
After the assignment, you could change a and b at will by assigning different memory addresses to them (i.e. pointers), and there would be no consequence to any external memory references as their scope is limited to the function block (e.g. a = foo). If, however, you changed the memory contents referred by them (e.g. *a = 0), this would become visible outside the scope of the function as you would be writing on a memory space (stack or heap) allocated somewhere else.
(*) Parameters may not be passed in memory (i.e. stack) to functions. Depending on the compiler/architecture, they may be directly assigned to a processor register. Either way, this is a transparent compiler optimization and you don't have to worry about it... the parameters will behave just the same.

Related

Memory segments stack and heap

i've looked over so many topics and i still could not find out why this happens:
struct B
{
int _arr[5];
};
struct A
{
struct B * _pb;
};
int main() {
int i;
struct B b;
struct A *pa = (struct A*)malloc(sizeof (struct A));
for (i=0;i<5;++i)
{
b._arr[i] = i;
}
pa->_pb=&b;
Struct A a = *pb;
}
How come pa found on stack and *pa is found on heap! both are local variables and should be only valid through scope so it should be on stack.
also why is ‪a._pb->_arr[2] on stack should not be on heap? can anyone clarify for me when it should be on stack and when on heap
The variable pa is on the stack. The memory it points to is on the heap.
Somewhat graphically a pointer variable can be describes like this:
+----+ +--------------------------------+
| pa | --> | allocated memory for structure |
+----+ +--------------------------------+
The two locations illustrated above (pa and the memory it points to) can be in different "segments", or they can be in the same.
And a._pb->_arr[2] is on the stack because a._pb is pointing to b which is on the stack.
Lastly a note about the "stack". While it's common to store local variables on the stack, the C specification doesn't say anything about it. Local variables are really automatic variables, and the C specification only specifies the semantics of those not where they should be stored.
First off, the C standard says nothing about stacks and heaps. Those are implementation details of a given compiler. That being said, most compilers for desktop applications use both of these.
You are correct that pa is local to the main function and therefore resides on the stack. *pa however is not a local variable. It is an expression which evaluates to an instance of struct A.
In this case, the malloc function returns a pointer to a block of memory big enough for a struct A and the value of that pointer is stored in pa.
Generally speaking, anything returned by malloc, realloc, or calloc lives in the heap, while variables declared local to a function (even pointer variables which may point to the heap) reside on the stack.
Short answer: *pa (what pa points to) is found on the heap because that's where you allocated the memory using malloc(). The variable pa, the pointer itself, is allocated on the stack because it's a local variable.
Long answer: Make sure you note the difference between a pointer and what the pointer refers to.
A declaration like this:
int a[5]
Tells the compiler to reserve space for a 5-element array, while a declaration like this:
int *a;
Tells the compiler to reserve space for a pointer. If you want the pointer to refer to an array then you need to allocate the memory, usually on the heap using malloc() and then release it when you're done using free().
And just to confuse things, in the C language, the array operator, [], is equivalent to the pointer arithmetic *() so that these two statements are wholly equivalent, regardless of whether a was declared as a pointer or an array:
a[2] = 5;
*(a + 2) = 5;
Digression: Which leads to some amusing possibilities. The above two statements are also equivalent to this one:
2[a] = 5;
Because addition is commutative in C:
2[a] = 5;
*(2 + a) = 5;
*(a + 2) = 5;
a[2] = 5;
But this absolutely does not work in C++ for reasons that are too far afield for this digression.

Questions on use of malloc() and free()

Thanks for notice my question.
In C Primer Plus, it first writes
The argument to free() should be a pointer to a block of memory allocated by malloc(); you can’t use free() to free memory allocated by other means
which means ONE malloc(), ONE and ONLY one free().
But later it goes
It’s okay to use a different pointer variable with free() than with malloc(); what must agree are the addresses stored in the pointers.
which seems contradict to the first statement.
So my understanding is that as long as a pair of malloc() and free() share the same address there is no error, and the name of pointers doesn't matter. Am I right?
For example:
void* p = malloc (100);
void* q = p;
free (q);
...is fine. The argument for free () is the value that was returned by malloc. The sentence
"It’s okay to use a different pointer variable with free() than with
malloc()"
is actually pointless and just creates confusion - of course it is fine to use different variables as long as the value is the same.
Just remember that freeing any alias, makes all the pointers invalid
int *a, *b, *c, *d, *e;
a = malloc(42 * sizeof (int));
b = a;
c = b;
d = c;
e = d;
a[0] = 42;
b[1] = 100; // same as a[1]
c[2] = 999; // same as a[2]
d[3] = -1; // same as a[3]
e[4] = 0; // same as a[4]
free(d); // for example
// all of a, b, c, d, and e are now invalid;
Variables contain some value, which could be a pointer (i.e. a memory address).
Two variables could contain the same pointer (that is, the same address), it is called pointer aliasing.
What matters to free is to get the value of a pointer previously given by malloc (that is a memory address previously given by malloc)

Declare and initialize pointer concisely (i. e. pointer to int)

Given pointers to char, one can do the following:
char *s = "data";
As far as I understand, a pointer variable is declared here, memory is allocated for both variable and data, the latter is filled with data\0 and the variable in question is set to point to the first byte of it (i. e. variable contains an address that can be dereferenced). That's short and compact.
Given pointers to int, for example, one can do this:
int *i;
*i = 42;
or that:
int i = 42;
foo(&i); // prefix every time to get a pointer
bar(&i);
baz(&i);
or that:
int i = 42;
int *p = &i;
That's somewhat tautological. It's small and tolerable with one usage of a single variable. It's not with multiple uses of several variables, though, producing code clutter.
Are there any ways to write the same thing dry and concisely? What are they?
Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?
String literals are a corner case : they trigger the creation of the literal in static memory, and its access as a char array. Note that the following doesn't compile, despite 42 being an int literal, because it is not implicitly allocated :
int *p = &42;
In all other cases, you are responsible of allocating the pointed object, be it in automatic or dynamic memory.
int i = 42;
int *p = &i;
Here i is an automatic variable, and p points to it.
int * i;
*i = 42;
You just invoked Undefined Behaviour. i has not been initialized, and is therefore pointing somewhere at random in memory. Then you assigned 42 to this random location, with unpredictable consequences. Bad.
int *i = malloc(sizeof *i);
Here i is initialized to point to a dynamically-allocated block of memory. Don't forget to free(i) once you're done with it.
int i = 42, *p = &i;
And here is how you create an automatic variable and a pointer to it as a one-liner. i is the variable, p points to it.
Edit : seems like you really want that variable to be implicitly and anonymously allocated. Well, here's how you can do it :
int *p = &(int){42};
This thingy is a compound literal. They are anonymous instances with automatic storage duration (or static at file scope), and only exist in C90 and further (but not C++ !). As opposed to string literals, compound literals are mutable, i.e you can modify *p.
Edit 2 : Adding this solution inspired from another answer (which unfortunately provided a wrong explanation) for completeness :
int i[] = {42};
This will allocate a one-element mutable array with automatic storage duration. The name of the array, while not a pointer itself, will decay to a pointer as needed.
Note however that sizeof i will return the "wrong" result, that is the actual size of the array (1 * sizeof(int)) instead of the size of a pointer (sizeof(int*)). That should however rarely be an issue.
int i=42;
int *ptr = &i;
this is equivalent to writing
int i=42;
int *ptr;
ptr=&i;
Tough this is definitely confusing, but during function calls its quite useful as:
void function1()
{
int i=42;
function2(&i);
}
function2(int *ptr)
{
printf("%d",*ptr); //outputs 42
}
here, we can easily use this confusing notation to declare and initialize the pointer during function calls. We don't need to declare pointer globally, and the initialize it during function calls. We have a notation to do both at same time.
int *ptr; //declares the pointer but does not initialize it
//so, ptr points to some random memory location
*ptr=42; //you gave a value to this random memory location
Though this will compile, but it will invoke undefined behaviour as you actually never initialized the pointer.
Also,
char *ptr;
char str[6]="hello";
ptr=str;
EDIT: as pointed in the comments, these two cases are not equivalent.
But pointer points to "hello" in both cases. This example is written just to show that we can initialize pointers in both these ways (to point to hello), but definitely both are different in many aspects.
char *ptr;
ptr="hello";
As, name of string, str is actually a pointer to the 0th element of string, i.e. 'h'.
The same goes with any array arr[], where arr contains the address of 0th element.
you can also think it as array , int i[1]={42} where i is a pointer to int
int * i;
*i = 42;
will invoke undefined behavior. You are modifying an unknown memory location. You need to initialize pointer i first.
int i = 42;
int *p = &i;
is the correct way. Now p is pointing to i and you can modify the variable pointed to by p.
Are there any ways to write the same thing dry and concisely?
No. As there is no pass by reference in C you have to use pointers when you want to modify the passed variable in a function.
Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?
If you are learning C then you can't avoid pointers and you should learn to use it properly.

Store pointer value

As I know, when a pointer is passed into a function, it becomes merely a copy of the real pointer. Now, I want the real pointer to be changed without having to return a pointer from a function. For example:
int *ptr;
void allocateMemory(int *pointer)
{
pointer = malloc(sizeof(int));
}
allocateMemory(ptr);
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays? Not by subscript, but by pointer arithmetic. Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself. For example:
int *a;
why not:
allocateMemory(*a)
but
allocateMemory(a)
I know I always have to do this, but I really don't understand why. Please explain to me.
The last thing is, in a pointer like this:
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer? I always think a is the memory address of the actual value it is pointing, but I am not sure about this. By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
I'll try to tackle these one at a time:
Now, I want the real pointer to be changed without having to return a pointer from a function.
You need to use one more layer of indirection:
int *ptr;
void allocateMemory(int **pointer)
{
*pointer = malloc(sizeof(int));
}
allocateMemory(&ptr);
Here is a good explanation from the comp.lang.c FAQ.
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays?
One allocation for the first dimension, and then a loop of allocations for the other dimension:
int **x = malloc(sizeof(int *) * 2);
for (i = 0; i < 2; i++)
x[i] = malloc(sizeof(int) * 3);
Again, here is link to this exact question from the comp.lang.c FAQ.
Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
ABSOLUTELY NOT. Pointers and arrays are different. You can sometimes use them interchangeably, however. Check out these questions from the comp.lang.c FAQ.
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself?
why not:
allocateMemory(*a)
It's two things - C doesn't have pass-by-reference, except where you implement it yourself by passing pointers, and in this case also because a isn't initialized yet - if you were to dereference it, you would cause undefined behaviour. This problem is a similar case to this one, found in the comp.lang.c FAQ.
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer?
That question doesn't really make sense to me, but I'll try to explain. a (when correctly initialized - your example here is not) is an address (the pointer itself). *a is the object being pointed to - in this case that would be an int.
By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
Correct in both cases.
To answer your first question, you need to pass a pointer to a pointer. (int**)
To answer your second question, you can use that syntax to access a location in an existing array.
However, a nested array (int[][]) is not the same as a pointer to a pointer (int**)
To answer your third question:
Writing a passes the value of the variable a, which is a memory address.
Writing *a passes the value pointed to by the variable, which is an actual value, not a memory address.
If the function takes a pointer, that means it wants an address, not a value.
Therefore, you need to pass a, not *a.
Had a been a pointer to a pointer (int**), you would pass *a, not **a.
Your first question:
you could pass a pointer's address:
void allocateMemory(int **pointer) {
*pointer = malloc(sizeof(int));
}
int *ptr;
allocateMemory(&ptr);
or you can return a pointer value:
int *allocateMemory() {
return malloc(sizeof(int));
}
int *ptr = mallocateMemory();
I think you're a little confused about what a pointer actually is.
A pointer is just variable whose value represents an address in memory. So when we say that int *p is pointer to an integer, that just means p is a variable that holds a number that is the memory address of an int.
If you want a function to allocate a buffer of integers and change the value in the variable p, that function needs to know where in memory p is stored. So you have to give it a pointer to p (i.e., the memory address of p), which itself is a pointer to an integer, so what the function needs is a pointer to a pointer to an integer (i.e., a memory address where the function should store a number, which in turn is the memory address of the integers the function allocated), so
void allocateIntBuffer(int **pp)
{
// by doing "*pp = whatever" you're telling the compiler to store
// "whatever" not in the pp variable but in the memory address that
// the pp variable is holding.
*pp = malloc(...);
}
// call it like
int *p;
allocateIntBuffer(&p);
I think the key to your questions is to understand that there is nothing special about pointer variables. A pointer is a variable like any other, only that the value stored in that variable is used to represent a position in memory.
Note that returning a pointer or forcing the caller to move the pointer in an out of a void * temp variable is the only way you can make use of the void * type to allow your function to work with different pointer types. char **, int **, etc. are not convertible to void **. As such, I would advise against what you're trying to do, and instead use the return value for functions that need to update a pointer, unless your function by design only works with a specific type. In particular, simple malloc wrappers that try to change the interface to pass pointer-to-pointer types are inherently broken.

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