Pointers, structs and memset in C [duplicate] - c

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Why isn't the size of an array parameter the same as within main?
(13 answers)
Closed 5 months ago.
I have been learning C for a few days now without any other programming experience, so I might not be clear when asking my question. It is mostly about pointers. For convenience purposes I named the variables so no one gets confused.
#include <stdio.h>
#include <string.h>
struct car {
char* name;
int speed;
float price;
};
void fun(struct car* p);
int main(void) {
struct car myStruct = { .name = "FORD", .speed = 55, .price = 67.87 };
fun(&myStruct);
printf("%d\n", myStruct.name == NULL);
printf("%d\n", myStruct.speed == 0);
printf("%d\n", myStruct.price == 0.0);
return(0);
}
void fun(struct car* p) {
memset(p, 0, sizeof(p));
}
This is my code.
I declare the struct car type globally, so it can be seen by other functions.
I write a function prototype that takes an argument of type struct car* and stores a copy of the argument into the parameter p that is local to the function.
Later, I write the actual function body. As you can see, I call the memset function that is in the string.h header. According to Linux man pages, it looks like this void* memset(void* s, int c, size_t n);.
What the memset function does in this case, is it fills the first sizeof(struct car* p) bytes of the memory area pointed to by the struct car* p with the constant byte c, which in this case is 0.
In the main function I initialize the myStruct variable of type struct car and then call the function fun and pass the address of myStruct into the function. Then I want to check whether all of the struct car "data members" were set to 0 by calling the printf function.
The output I get is
1
0
0
It means that only the first "data member" was set to NULL and the rest weren't.
On the other hand, if I call the memset function inside the main function, the output I get is
1
1
1
If I understand pointers correctly (it's been a few days since I've first heard of them, so my knowledge is not optimal), struct car myStruct has its own address in memory, let's say 1 for convenience.
The parameter struct car* p also has its own address in memory, let's say 2 and it stores (points to) the address of the variable struct car myStruct, so to the 1 address, because I passed it to the function here fun(&myStruct);
So by dereferencing the parameter p, for example (*p).name, I can change the value of the "data member" variable and the effects will be seen globally, because even though the p parameter is only a copy of the original myStruct variable, it points to the same address as the myStruct variable and by dereferencing the pointer struct car* p, I retrieve the data that is stored at the address the pointer points to.
So (*p).name will give me "FORD" and (*p).name = "TOYOTA" will change the data both locally in the function fun and globally in other functions as well, which is impossible without creating a pointer variable, if I do p.name = "TOYOTA", it changes only the value of the copy, that has its own address in the memory that is different from the address of the original struct variable, of the "data member" variable name locally, inside the function fun. It happens, because in this case I operate only on the copy of the original myStruct variable and not on the original one.
I think that in C there is only pass by value, so essentially every parameter is only a copy of the original variable, but pointers make it so that you can pass the address of the original variable (so it's like "passing by reference", but the copy is still made regardless, the thing is that then the function operates on the original address instead of on the parameter's address).
What I don't know is, why the memset function only changes the first "data member" variable to NULL and not all of them ?
void fun(struct car* p) {
memset(p, 0, sizeof(p));
p->name = NULL;
p->speed = 0;
p->price = 0.0;
}
If I do this then it changes all the values to NULL, 0, 0, but I don't know, if it is a good practice to do that as it is unnecessary in this case, because I explicitly initialize all the "data members" in the struct with some value.
void fun(struct car* p) {
memset(&p, 0, sizeof(p));
}
This also works and gives NULL, 0, 0. So maybe I should actually pass &s into the function instead of s, but I don't know how this works. The function void* memset(void* s, int c, size_t n); takes void* as the argument and not void**, the latter is understandable, because:
struct car myStruct = { .name = "FORD", .speed = 55, .price = 67.87 }; // It has its own address in memory and stores the struct at this address
struct car* p = &myStruct; // It points to the address of myStruct and retrieves the data from there when dereference happens, so first it goes to address 1 and then gets the data from this address
void** s = &p; // It points to the address of p and retrieves the data from there when double dereference happens, so it first goes to address 2 and gets the data and the data is address 1, then it goes to address 1 and gets the data, so the struct
But void* means pointer to void, so to any data type. It confuses me why void* s = &p; works, even though p itself is a pointer, so s should be a pointer to pointer to void, so void** s instead of void* s.
Also the memset function returns a pointer to the memory area s, so if s = &p and p = &myStruct, then it returns a pointer to the memory area of the struct, so a pointer to &myStruct. Maybe that's why it works.

In this call
memset(p, 0, sizeof(p));
you are setting to 0 only a part of object of the structure that is equal to the size of the pointer p.
Instead you need to write
memset(p, 0, sizeof(*p));
that is to set the whole object of the structure type with 0.
Pay attention to as the variable p is a pointer then this record
p.name = "TOYOTA";
is just syntactically incorrect.
This function
void fun(struct car* p) {
memset(&p, 0, sizeof(p));
}
does not set the passed object of the structure type through the pointer p to zeroes. Instead it sets to zeroes the memory occupied by the local variable p itself.
As for this question
But void* means pointer to void, so to any data type. It confuses me
why void* s = &p; works, even though p itself is a pointer, so s
should be a pointer to pointer to void, so void** s instead of void*
s.
then according to the C Standard (6.3.2.3 Pointers_
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
So you can write for example
struct car myStruct =
{
.name = "FORD", .speed = 55, .price = 67.87
};
struct car *p = &myStruct;
void *q = &p;
and then
( *( struct car ** )q )->name = "My Ford";

Related

Passing in double pointer as params in C

Let's say there is an API as follows:
void myAPI(int8** ptr)
If I want to pass a pointer of a struct into this function this is my code:
typedef myStruct {
int a;
};
myStruct *ptr = NULL;
memset(ptr, 0, sizeof(myStruct));
myAPI((int8**)&ptr);
My question is what if instead of using ptr I now have the following?
myStruct myStruct_info;
memset(&myStruct_info, 0, sizeof(myStruct));
Would I also be doing myAPI((int8**)&myStruct_info)?
Would I also be doing myAPI((int8**)&myStruct_info)?
Short answer is no you can not.
&myStruct_info is the address of your myStruct_info variable.
And the parameter for your myAPI function needs the address of a pointer to a variable.
If you say int8 ** a = (int8**)&myStruct_info; then:
a - holds the address of myStruct_info
*a - the value of myStruct_info
and
**a - means that you take the value stored in myStruct_info and use it as a pointer - REALLY BAD -

Passing struct with 2d array to thread function and getting value of it's index

I am trying to pass struct to thread. Unfortunatelty when it happens i can no longer use p[i][j]. I am getting error: subscripted value is neither array nor pointer nor vector
typedef struct MY_M {
int *p1;
int *p2;
} MY_M;
int *M1[r];
for (i=0; i<r; i++){
M1[i] = (int *)malloc(c * sizeof(int));}
pthread_t thread1;
struct MY_M *p = malloc(sizeof(struct MY_M));
p-> p1 = *M1;
p-> p1 = *M2;
int ret = pthread_create(&thread1,NULL,thread,(void*) p);
thread here:
void* thread(void* parameter )
{
MY_M **p = (MY_M*)parameter;
p->p1[0][0] = 5;
}
When i comment p[0][0] the program is working fine. Why it is not working? I would be grateful for any help.
I can't tell exactly what you are trying to accomplish here, but I can see a number of errors.
In the first place, you assign two values to p->p1. I assume this is probably a mistake and you meant to assign one value to p->p1 and another to p->p2. (And where did M2 come from?)
Second, int *M1[r]; will allocate r pointers to int on the stack, which means the array containing the buffers will become invalidated shortly after the function returns.
You are also dereferencing M1 during assignment, which means you are only pointing to the first buffer that you allocated. Again, I can't tell exactly what you are trying to do with that, so I don't know what to recommend.
p1 is also type int*, which means it contains the address of an int, so it can only be dereferenced once and will resolve to int. If you want to dereference it twice (p->p1[x][y]) it should be type int** or pointer to some other dereference-able type.
Also, you cast parameter to MY_M*, but then assign it to a variable of type MY_M**. That is not correct (in fact, isn't that giving you a compiler error?)
As far as I can tell, you are simply trying to allocate some structure that your thread will later have access to. If that is the case, the code would be something like this:
typedef struct MY_M {
int* p1;
int* p2;
} MY_M;
MY_M* p = (MY_M*)malloc( sizeof(MY_M) );
p->p1 = (int*)malloc( c * sizeof(int) );
p->p2 = (int*)malloc( c * sizeof(int) );
pthread_t thread1;
int ret = pthread_create(&thread1, NULL, thread, (void*)p);
thread here:
void* thread(void* parameter)
{
MY_M *p = (MY_M*)parameter;
p->p1[0] = 5;
}
Overall, it seems that you don't fully understand pointers properly. I can try to give a brief rundown, but do consult other guides and references to fully understand the concept.
First: a pointer is an address. So int* a = &b; means that a of type int* will contain b's address, and therefore it points to b. If you dereference a pointer, that means you take the address value that it holds and follow the address to its original source. So *a dereferences a, resolving to the value stored in b.
Array index syntax is equivalent to offset + dereferencing, so when you say p->p1[0][0], that is really equivalent to *((*(p->p1+0))+0), which dereferences the variable twice.
You can't dereference something that isn't a pointer (i.e., doesn't contain an address). That's why your int* can't be dereferenced twice. After dereferencing it once, it is now an int, which does not contain an address and cannot be dereferenced.
I hope this helps.
What you're actually using is an array of pointers (to arrays), rather than a proper 2D array -- though that isn't really a problem here. As for why it isn't working, you simply have the wrong type for p in your thread function -- it should be int ** rather than int *.

How do I correctly use a void pointer in C?

Can someone explain why I do not get the value of the variable, but its memory instead?
I need to use void* to point to "unsigned short" values.
As I understand void pointers, their size is unknown and their type is unknown.
Once initialize them however, they are known, right?
Why does my printf statement print the wrong value?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(int a, void *res){
res = &a;
printf("res = %d\n", *(int*)res);
int b;
b = * (int *) res;
printf("b =%d\n", b);
}
int main (int argc, char* argv[])
{
//trial 1
int a = 30;
void *res = (int *)a;
func(a, res);
printf("result = %d\n", (int)res);
//trial 2
unsigned short i = 90;
res = &i;
func(i, res);
printf("result = %d\n", (unsigned short)res);
return 0;
}
The output I get:
res = 30
b =30
result = 30
res = 90
b =90
result = 44974
One thing to keep in mind: C does not guarantee that int will be big enough to hold a pointer (including void*). That cast is not a portable thing/good idea. Use %p to printf a pointer.
Likewise, you're doing a "bad cast" here: void* res = (int*) a is telling the compiler: "I am sure that the value of a is a valid int*, so you should treat it as such." Unless you actually know for a fact that there is an int stored at memory address 30, this is wrong.
Fortunately, you immediately overwrite res with the address of the other a. (You have two vars named a and two named res, the ones in main and the ones in func. The ones in func are copies of the value of the one in main, when you call it there.) Generally speaking, overwriting the value of a parameter to a function is "bad form," but it is technically legal. Personally, I recommend declaring all of your functions' parameters as const 99% of the time (e.g. void func (const int a, const void* res))
Then, you cast res to an unsigned short. I don't think anybody's still running on a 16-bit address-space CPU (well, your Apple II, maybe), so that will definitely corrupt the value of res by truncating it.
In general, in C, typecasts are dangerous. You're overruling the compiler's type system, and saying: "look here, Mr Compiler, I'm the programmer, and I know better than you what I have here. So, you just be quiet and make this happen." Casting from a pointer to a non-pointer type is almost universally wrong. Casting between pointer types is more often wrong than not.
I'd suggest checking out some of the "Related" links down this page to find a good overview of how C types an pointers work, in general. Sometimes it takes reading over a few to really get a grasp on how this stuff goes together.
(unsigned short)res
is a cast on a pointer, res is a memory address, by casting it to an unsigned short, you get the address value as an unsigned short instead of hexadecimal value, to be sure that you are going to get a correct value you can print
*(unsigned short*)res
The first cast (unsigned short*)res makes a cast on void* pointer to a pointer on unsigned short. You can then extract the value inside the memory address res is pointing to by dereferencing it using the *
If you have a void pointer ptr that you know points to an int, in order to access to that int write:
int i = *(int*)ptr;
That is, first cast it to a pointer-to-int with cast operator (int*) and then dereference it to get the pointed-to value.
You are casting the pointer directly to a value type, and although the compiler will happily do it, that's not probably what you want.
A void pointer is used in C as a kind of generic pointer. A void pointer variable can be used to contain the address of any variable type. The problem with a void pointer is once you have assigned an address to the pointer, the information about the type of variable is no longer available for the compiler to check against.
In general, void pointers should be avoided since the type of the variable whose address is in the void pointer is no longer available to the compiler. On the other hand, there are cases where a void pointer is very handy. However it is up to the programmer to know the type of variable whose address is in the void pointer variable and to use it properly.
Much of older C source has C style casts between type pointers and void pointers. This is not necessary with modern compilers and should be avoided.
The size of a void pointer variable is known. What is not known is the size of the variable whose pointer is in the void pointer variable. For instance here are some source examples.
// create several different kinds of variables
int iValue;
char aszString[6];
float fValue;
int *pIvalue = &iValue;
void *pVoid = 0;
int iSize = sizeof(*pIvalue); // get size of what int pointer points to, an int
int vSize = sizeof(*pVoid); // compile error, size of what void pointer points to is unknown
int vSizeVar = sizeof(pVoid); // compiles fine size of void pointer is known
pVoid = &iValue; // put the address of iValue into the void pointer variable
pVoid = &aszString[0]; // put the address of char string into the void pointer variable
pVoid = &fValue; // put the address of float into the void pointer variable
pIvalue = &fValue; // compiler error, address of float into int pointer not allowed
One way that void pointers have been used is by having several different types of structs which are provided as an argument for a function, typically some kind of a dispatching function. Since the interface for the function allows for different pointer types, a void pointer must be used in the argument list. Then the type of variable pointed to is determined by either an additional argument or inspecting the variable pointed to. An example of that type of use of a function would be something like the following. In this case we include an indicator as to the type of the struct in the first member of the various permutations of the struct. As long as all structs that are used with this function have as their first member an int indicating the type of struct, this will work.
struct struct_1 {
int iClass; // struct type indicator. must always be first member of struct
int iValue;
};
struct struct_2 {
int iClass; // struct type indicator. must always be first member of struct
float fValue;
};
void func2 (void *pStruct)
{
struct struct_1 *pStruct_1 = pStruct;
struct struct_2 *pStruct_2 = pStruct;
switch (pStruct_1->iClass) // this works because a struct is a kind of template or pattern for a memory location
{
case 1:
// do things with pStruct_1
break;
case 2:
// do things with pStruct_2
break;
default:
break;
}
}
void xfunc (void)
{
struct struct_1 myStruct_1 = {1, 37};
struct struct_2 myStruct_2 = {2, 755.37f};
func2 (&myStruct_1);
func2 (&myStruct_2);
}
Something like the above has a number of software design problems with the coupling and cohesion so unless you have good reasons for using this approach, it is better to rethink your design. However the C programming language allows you to do this.
There are some cases where the void pointer is necessary. For instance the malloc() function which allocates memory returns a void pointer containing the address of the area that has been allocated (or NULL if the allocation failed). The void pointer in this case allows for a single malloc() function that can return the address of memory for any type of variable. The following shows use of malloc() with various variable types.
void yfunc (void)
{
int *pIvalue = malloc(sizeof(int));
char *paszStr = malloc(sizeof(char)*32);
struct struct_1 *pStruct_1 = malloc (sizeof(*pStruct_1));
struct struct_2 *pStruct_2Array = malloc (sizeof(*pStruct_2Array)*21);
pStruct_1->iClass = 1; pStruct_1->iValue = 23;
func2(pStruct_1); // pStruct_1 is already a pointer so address of is not used
{
int i;
for (i = 0; i < 21; i++) {
pStruct_2Array[i].iClass = 2;
pStruct_2Array[i].fValue = 123.33f;
func2 (&pStruct_2Array[i]); // address of particular array element. could also use func2 (pStruct_2Array + i)
}
}
free(pStruct_1);
free(pStruct_2Array); // free the entire array which was allocated with single malloc()
free(pIvalue);
free(paszStr);
}
If what you want to do is pass the variable a by name and use it, try something like:
void func(int* src)
{
printf( "%d\n", *src );
}
If you get a void* from a library function, and you know its actual type, you should immediately store it in a variable of the right type:
int *ap = calloc( 1, sizeof(int) );
There are a few situations in which you must receive a parameter by reference as a void* and then cast it. The one I’ve run into most often in the real world is a thread procedure. So, you might write something like:
#include <stddef.h>
#include <stdio.h>
#include <pthread.h>
void* thread_proc( void* arg )
{
const int a = *(int*)arg;
/** Alternatively, with no explicit casts:
* const int* const p = arg;
* const int a = *p;
*/
printf( "Daughter thread: %d\n", a );
fflush(stdout); /* If more than one thread outputs, should be atomic. */
return NULL;
}
int main(void)
{
int a = 1;
const pthread_t tid = pthread_create( thread_proc, &a );
pthread_join(tid, NULL);
return EXIT_SUCCESS;
}
If you want to live dangerously, you could pass a uintptr_t value cast to void* and cast it back, but beware of trap representations.
printf("result = %d\n", (int)res); is printing the value of res (a pointer) as a number.
Remember that a pointer is an address in memory, so this will print some random looking 32bit number.
If you wanted to print the value stored at that address then you need (int)*res - although the (int) is unnecessary.
edit: if you want to print the value (ie address) of a pointer then you should use %p it's essentially the same but formats it better and understands if the size of an int and a poitner are different on your platform
void *res = (int *)a;
a is a int but not a ptr, maybe it should be:
void *res = &a;
The size of a void pointer is known; it's the size of an address, so the same size as any other pointer. You are freely converting between an integer and a pointer, and that's dangerous. If you mean to take the address of the variable a, you need to convert its address to a void * with (void *)&a.

Dynamic Struct Array allocation within a function

I am trying to allocate an array of structs within a function.
My struct is as follows:
typedef struct{
uint16_t taskNumber;
uint16_t taskType;
double lat;
double lon;
double speed;
uint8_t successCriteria;
uint16_t successValue;
uint8_t nextPoint;
}missionPoint;
In my code I declare a missionPoint-pointer which I then pass into the function that will dynamically allocate it after parsing a file and figuring out how big it needs to be.
Currently this is how my code looks:
missionPoint* mission; //declaring the pointer
parseMission(mission);
The parseMission function will then parse a specific file and find out how many missionPoints I need and will then allocate it in the following manner:
mission = (missionPoint*) malloc(n * sizeof(missionPoint));
where n is the parsed number of missionPoints I need.
The problem is that within the function I can see the proper values but not outside of it; once the function returns it's like nothing happened.
I would appreciate your help in making it so that the function modifies the original pointer and I can see the data from outside the function.
You need to pass a reference to the pointer, i.e. a double pointer, because the address itself is going to be modified:
missionPoint *mission;
parseMission(&mission);
The argument of parseMission should now be of type missionPoint ** instead of missionPoint *:
*mission = (missionPoint*) malloc(n * sizeof(missionPoint));
This wouldn't be necessary if you only wanted to modify the memory mission is pointing to, but it cannot be avoided since you are assigning a new value to the pointer itself.
Also note that casting the return value of malloc is not necessary in C.
Pass a reference (i.e. pointer) to the mission pointer rather than the value of the mission pointer itself. So the declaration of your function would look like:
void parseMission(missionPoint** pointer_ref);
rather than:
void parseMission(missionPoint* pointer_val);
then pass the address of mission (i.e., &mission) as the argument value for parseMission.
Think that a pointer in C is just a integer, storing some memory address.
Think that malloc allocates some memory and returns you the address of this memory (a new pointer).
Understand that this snippet will print "2", regadless of what the called function does with the passed value.
int a = 2;
doSomething(a);
printf("%d\n",a);
Once you understand all this, you can predict what this code will produce, and why you need to pass the "reference to the pointer" (pointer to the pointer) instead of of the pointer itself (value of the pointer) to your allocator function.
void remalloc(char * p1) {
printf("pointer before remalloc (inside function): %X\n",(unsigned int)(p1));
free(p1);
p1 = (char*)malloc(200000);
printf("pointer after remalloc (inside function): %X\n",(unsigned int)(p1));
}
int main(){
char * p;
printf("pointer before malloc: %X\n",(unsigned int)(p));
p = (char*)malloc(10);
printf("pointer after malloc: %X\n",(unsigned int)(p));
remalloc(p);
printf("pointer after remalloc: %X\n",(unsigned int)(p));
}

Decayed multidimensional array return from function

related to (gcc) Multi-Dim Array or Double Pointer for Warning-free Compile , is there a way to return so-called "decayed array pointer" from a function? in summary (suppose 2 dim array) returning int (*a)[5] format rather than int** format?
as far as I see, when returned int** pointer is sent to another function waiting (int*)[] parameter, it is not working correctly.
Yes, but the syntax won't look nice
int(*f())[5] {
static int a[1][5] = { { 1, 2, 3, 4, 5 } };
return a;
}
Basically, it's just your a replaced by f() (a function). Using a typedef it becomes more readable
typedef int inner_array[5];
inner_array *f() {
// like before ...
}
Notice that to denote the abstact type, without a name, you need to write int(*)[5]. That is, you just erase the name. (int*)[5] is not valid syntax.
You are right - you can't return int** because this means you have a pointer to a pointer. Accessing with f()[A][B] would read from the address the returned pointer gives, and then read again from the address given by that pointer in turn. But in fact, the array pointer you return points only to one memory block, so if you would make two indirections, you would try to reinterpret data as being pointers.
Contrary, if you return a int(*)[5] and do f()[A][B] you will not read any value from the address returned by the pointer. Instead, you merely add the offset A to the address, and adjust the type from int(*)[5] to int[5] to have an array that refers to memory at the adjusted address. The next index will then again adjust by B and since it operates on a int* then (after the array decayed), not anymore on an array pointer, it will then read the content stored at the adjusted address, to finally yield the int. This is an important difference of non-array pointers and array pointers.
You can experiment with this, if you want. Consider these two snippets. One will probably crash, but the other probably won't (but both yield undefined behavior, so this shouldn't be done in real programs)
int *pi = 0;
int(*pa)[5] = 0;
int i = *pi; // read int stored at null-pointer address!
int *a = *pa; // does not read any data from address, just adjusts the type!
struct thing {
int A[10][10];
};
typedef struct thing thing_t;
thing_t f1(void) {
thing_t t;
...
return t;
}
thing_t * f1(void) {
thing_t * tp;
...
return tp;
}
Though, you're really going about this the wrong way.

Resources