How to set pointers throught functions? - c

I have a question about C pointers. Because I was wondering if I could set pointers through functions.
I mean like this:
void initptr(int **ptr)
{
ptr = (int *) malloc(sizeof(ptr));
}
int main()
{
int *ptr;
initptr(ptr);
}
Let me know.

Yes this is possible in C, you're just missing a dereference and address of operator in your sample
void initptr(int **ptr)
{
*ptr = (int *) malloc(sizeof(int*));
}
int main()
{
int *ptr;
initptr(&ptr);
}
The deference operator in *ptr = ... converts the type of ptr from int** to int* thus making it compatible with the assignment. Note: the casting of malloc is uneedded here.
The address of operator in initptr(&ptr) reversely converts the type of ptr from int* to int** thus making it compatible with the argument slot.
EDIT
As B Mitch pointed out the malloc size needs updating as well. You appear to be allocating an int* value and hence want the size to be that of an int*.

I believe you want this:
*ptr = (int *) malloc(sizeof(**ptr));

yes, but you need dereference ptr in your function in order to change what it points to
e.g.
void initptr(int **ptr)
{
*ptr = ...
}
when you call the method write
initptr( &ptr );

ptr = (int *) malloc(sizeof(ptr));
You missed to dereference the pointer to pointer so that it can actually take a pointer.
*ptr = (int *) malloc(sizeof(ptr));
// * newly added.
And also call to initptr(ptr); is wrong.
void initptr(int **ptr) ;
The function has an pointer to pointer as an argument. So, the argument ptr needs to hold the address of a pointer. So, change it to -
int *ptr = NULL ; // Initialize pointers to NULL
initptr(&ptr); // Passing the pointers address

Related

Pointer initialization: address or value

I have a question regarding pointer initialization in C.
I understand that *ptr will give the value of that pointer is pointing to.
ptr will give you the address.
Now I got following syntax:
int *ptr = (int *) malloc(sizeof(*ptr));
Why is *ptr being initialized with an address of the Heap and not a value? malloc() returns an address right?
Shouldn't it be:
int *ptr;
ptr = malloc(...);
With *ptr, * is acting as the dereferencing operator.
With int *ptr, * is acting as part of the type declaration for ptr.
So the two things are entirely different, even though * is used. (Multiplication and comment blocks are further uses of * in C).
In that line, int * is the type.
int *ptr = (int *) malloc(sizeof(*ptr));
Is just this compressed into one line:
int *ptr;
ptr = (int *) malloc(sizeof(*ptr));
Actually , this:
int *ptr = (int *) malloc(sizeof(*ptr));
Is just short syntax for this:
int *ptr;
ptr = malloc(...);
The * is used for defining a type pointer and not to dereference the pointer .
Both snippets above do the same thing.
In the first case, the * before ptr is not the derefernece operator but is part of the definition of the type. So you actually are assigning a value to (initializing, actually) ptr, not *ptr.
The difference between
int *ptr = (int *) malloc(sizeof(*ptr));
and
int *ptr;
ptr = malloc(...);
is basically the same as the difference between
int i = 5;
and
int i;
i = 5;
The first variant defines and initializes a variable in one go. The second variant defines the variable but leave it uninitialized, and then assign a value to it.

Passing structs into function by address vs a pointer in C

I was hoping someone could help me figure out why one version of the below code works, while the other doesn't. Below I've included the initArray method, stored in "worksheet.c". The function is accessed in main, both versions are given below.
void initArray(struct dynArray *a) {
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
}
This works. I create a dynArray struct and pass it to initArray by reference.
#include "worksheet0.h"
#include <stdio.h>
int main(void)
{
struct dynArray b;
initArray(&b);
return 0;
}
This fails with a seg fault. I thought that passing b here would be the same as passing the struct by reference.
int main(void)
{
struct dynArray *b = NULL;
initArray(b);
return 0;
}
Because in the second case there is no memory allocated to which the struct pointer points to. It is simply a pointer having the value NULL. On your case by dereferencing the value NULL you have invoked undefined behavior.
It would work if you allocate memory, make changes to it and then return it's value. [But then you have to return the address of the allocated memory.] OR you can pass the address of the pointer variable and allocate memory to which dereferenced pointer (here the pointer has type struct dynAray**) would point to and make changes to it.
Let's be more clear now slowly:
Why the first case works? You have a struct dynArray variable whose address you have passed into the function and then you have accessed the content of that address - wait! that means you have accessed the struct dynArray variable itself and made changes to its member variables. Yes that is what exactly happened in the first case.
In the second case, you have a pointer to struct dynArray. And then you passed it - de-referenced it. Where was it pointing to? Is it some struct dynArray variable's address that it contained? No. It was NULL. So it is wrong if you expect it to work.
The second would work - but you have to change things a bit! Let's see how:
struct dynArray* initArray() {
struct dynArray* a = malloc(sizeof *a);
assert(a != NULL);
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
return a;
}
And in main()
struct dynArray* b;
b = initArray();
You don't even need to pass the pointer variable. That would be meaningless if you want to do it like this.
And you know you can also pass the address of the pointer variable so that you can make changes to it -
void initArray(struct dynArray** a) {
*a = malloc(sizeof **a);
assert((*a) != NULL);
(*a)->data = malloc(10 * TYPE_SIZE);
assert((*a)->data != 0);
(*a)->size = 0;
(*a)->capacity = 10;
}
For this in main() you would call it like this
struct dynArray* b;
initArray(&b);
In the first example a pointer holding the address of an actual struct is passed to the function. But, in the second example the pointer b does not point to a struct. Instead, this pointer is initialized to NULL, and when this null pointer is dereferenced in the initArray() function, undefined behavior ensues.

passing pointer as size of an array in C

I want to pass a pointer as a size element of an array
example:
void hello(int array1[how can i refer pointer "ptr" here][2])
{
// i want to access the array used in the main() here
printf("hi");
}
int main()
{
int c=5;
int *ptr=&c;
a[*ptr][2];
a[0][1]=0;
a[0][2]=4;
}
I apologize for not being clear with my question here , i want to access the array used in the main() function in my hello() function.
You will have to use the value pointed to by the pointer:
a[*ptr][2];
ptr is the address pointed to by the pointer not the value stored there. You use the dereference operator * to get the value.
Of course, ptr is not of type int, it's of type int * (integer pointer). An array subscript must be of type int.
Maybe what you want is a[*ptr][2].
You need to deference the pointer by using *ptr so
int c = 5;
int *ptr = &c;
a[*ptr][2];
otherwise you are not using the value of ptr you are using its address in memory which returns an error.
Use the dereference operator *:
a[*ptr][2];
The expression *ptr tells the compiler to use the value pointed to by ptr.
As for your updated question, that's not possible. But it's not needed either, as it's passed as a pointer anyway.
When declaring a function, this:
void foo(int a[5][5])
is the same as this:
void foo(int a[][2])
And also the same as this:
void foo(int (*a)[2])
It has pretty much been answered already, you can't call an adress in the array a[0x3950f2][2]
Always use the pointer* to get the position in the array a[*ptr][2] to get the expected value - in this case: a[*ptr][2] == a[5][2]. You may read this.
Edit to your updated question: You can't to this. You can use the pointer when you call the function or when using the variable in the function.
Your second edit:
void hello(int **array1)
{
// i want to access the array used in the main() here
printf ("hi");
a[0][0] = 24;
}
int main()
{
int c = 5;
int *ptr = &c;
int **a;
a[*ptr][2];
a[0][1] = 0;
a[0][2] = 4;
hello (a);
return 0;
}

Passing arrays in c

I have a question regarding passing arrays in c to a function.
When I run this program it gives me a segmentation fault
int main()
{
char **ptr= NULL;
test(ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char **ptr)
{
ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(ptr[0], "abc");
return;
}
but this worked just fine
int main()
{
char **ptr= NULL;
test(&ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char ***ptr)
{
*ptr = (char **) malloc(sizeof(char *));
*ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(*ptr[0], "abc");
return;
}
Could someone explain why?
You're passing the parameter ptr by value; the formal parameter ptr in test is a different object from the actual parameter ptr in main, so changing the value of test::ptr is not reflected in main::ptr.
Thus, you need to pass a pointer to ptr into test, and test needs to dereference that pointer to write to the correct object.
For any type T, if you want to modify the value of the function argument, you need to do the following:
void foo( T *param )
{
*param = ...;
}
void bar( )
{
T obj;
foo( &obj );
}
In this particular instance, T is char **.
In C, when you pass an array to a function, the array "decays" to a pointer. The function receives a pointer to the first element of the array. It does not receive the array itself. Any changes made to the pointer assignment in the called function are not reflected in the calling function.
In your first example, test() receives the array of strings, and inside the function, it changes what that pointer points to. So the local copy of ptr, which was NULL, gets allocated memory inside the function, as does ptr[0]. However, those changes are local to test(). They are not reflected in the calling function. When test() finishes executing and returns, the value of ptr in the calling function is still NULL. And you have a memory leak because there is no way to access the memory that was allocated in test().
In order for the changes to be reflected in the calling function, you have to pass a pointer to the array of strings: hence the &ptr in the call and the three-level pointer in the definition of test(). Another, simpler approach would be:
int main()
{
char **ptr= NULL;
ptr = test();
printf("%s", ptr[0]);
return 0;
}
char** test(void)
{
char **ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char) * 5);
strcpy(ptr[0], "abc");
return ptr;
}
One clarification: I said "Any changes made to the pointer assignment in the called function are not reflected in the calling function." This is not the same as saying "Any changes to array elements are not reflected in the calling function." Consider this:
int main (void) {
int array [] = { 0, 1, 2, 3, 4 };
test1 (array);
printf ("%d\n", *array);
test2 (array);
printf ("%d\n", *array);
return 0;
}
void test1 (int* array) {
int new_array[] = { 3, 4, 5, 6, 7 };
array = new_array;
return;
}
void test2 (int* array) {
array [0] = 5; // or *array = 5
array [1] = 6;
array [2] = 7;
array [3] = 8;
array [4] = 9;
return;
}
Output:
0
5
Here in test1() the change is to where the array pointer itself is pointing, which won't be reflected in the caller. So in the calling function, *test is still 0. In test2(), the changes are to the array elements, which are reflected in the caller. Hence the difference in output: *test is now 5. All this uses static rather than dynamic memory allocation, but the principle is the same.
It's because you expect your function not to return a value, but to modify a variable you have already created in another scope.
You expect, from your function, to pass ptr and end up with the following structure:
ptr -> b -> []
where b is a pointer to the array [].
In the first example you are not modifying the outer ptr inside the function, but a copy of it. In that case, to get the desired structure you'd need your function to return a char** so that you could return the allocated pointer. And you wouldn't need to pass the original ptr.
In the second example, on the other hand, you are passing a pointer to the outer ptr, so the function will be modifying the same memory space that the outer ptr uses.
I hope this can help a little.
Consider below code for understandling
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test(char **ptr);
int main()
{
char *ptr= NULL;
test(&ptr);
printf("%s\n", ptr);
return 0;
}
void test(char **ptr)
{
*ptr = malloc(sizeof(char *));
strcpy(*ptr, "abc");
return;
}
Whatever doing in function definition has to be reflect in main function. So if you want to make changes in ptr variable you have to pass the address of the ptr variable.
ptr is single pointer(char ptr) variable, we need to pass address of the pointer(&ptr) variable.
In function definition we are receiving address of pointer variable, so argument has to be the type of double pointer.
This concept is similar to call by reference.
Similar things happening in your code also.
You need to pass address of double pointer to make changes in pointer variable.
Address of double pointer has to taken by triple pointer in function definition.
To expand on the answer from #rcrmn.
It is a good program design to have data get passed "up" the calling structure. In this case main() needs to free the storage it received from test.
Notice that this code avoids all of the double pointers in the original question and still meets the requirements. This is the essence of good programming, write clear, simple, code that gets the job done.
#include <stdio.h>
char *test();
int main()
{
char *ptr = test();
printf("%s", ptr);
free(ptr);
return 0;
}
char *test()
{
char *ptr = (char *) malloc(sizeof(char) * 5);
strncpy(ptr, "abc", 3);
return ptr;
}

Given the address of a pointer, how do I get what it points to?

If I am given the address of a pointer, how do I get what the pointer points to?
You might mean:
/**
* #param pointer_to_pointer_to_int: the address of a pointer to an integer.
**/
void function_that_takes_pointer_to_pointer(int **pointer_to_pointer_to_int) {
int the_int = **pointer_to_pointer_to_int;
printf("The pointer points to %d\n", the_int);
}
Assuming it is a valid pointer, you can dereference it using the unary * operator:
int *ptr = ...;
int x;
x = *ptr;
The unary * operator.
int *ptr = malloc(sizeof(int));
*ptr = 45;
printf("address: %p, value: %d", ptr, *ptr);
The most common way to be given the address of a pointer is through a pointer to a pointer. If the value the pointer points to is an integer, the type of the address of the pointer is int **.
To get the pointer to the integer, you need to dereference the double pointer. Then you can dereference the integer pointer to get the integer value.
To dereference a pointer, use the * operator.
int **double_pointer = given;
int *int_pointer = *double_pointer;
int value = *int_pointer;
You can also chain the dereferences to do that on one line.
int **double_pointer = given;
int value = **double_pointer;
The unary * operator returns or sets the value at a memory location.
For example:
int val = 42;
int* ptr = &val;
assert(val == *ptr);
If you have the address of a pointer, you would write **pointerpointer.
Going off of RedX's comment, If you have a situation like
void foo(void *ptr)
{
...
}
where the value of ptr is a pointer to a pointer to int, for example, you could do something like
void foo(void *ptr)
{
int x = **((int **) ptr);
...
}
Basically, you cast ptr to int **, then double-dereference it.
If you don't know what the target type is ahead of time (e.g., the function is meant to handle pointers to multiple types), then you're going to have to figure out a way to encode that type information in a second argument and pass it to the function.
There are two possible answers to your question depending on whether the compiler has a clue about the data that's referred or not.
Declaring a pointer of type int *, char * or mytype * instructs the compiler that a later attempt to dereference it using the unary * operator must yield a result of int, char or mytype respectively.
In the other case you would normally store a pointer either in a void * (generic, untyped pointer) or in a uintptr_t (an unsigned int the same size of a pointer, but without pointer semantics). In such a case the compiler doesn't have a clue how to interpret the dereferencing operator, so you must explicitly cast such a pointer to another pointer type, and only then dereference it:
int x = 5;
void *p = &x; /* p now points to an int, but the compiler doesn't know it */
printf("%d\n", *((int *) p)); /* we know what we did and don't rely on the compiler */
printf("%d\n", *p); /* compile-time error, dereferencing has undefined semantics */
Note that in compiled, unmanaged languages like C there is no runtime information about what kind of data a pointer is pointing to, unlike languages like Java where you can use the instanceof operator to check what a reference is really pointing to at runtime.

Resources