I am having a problem correctly dereferencing a pointer to an integer that resides in an array of structures. The relevant parts of the code are:
typedef struct hf_register_info {
int *p_id; /**< written to by register() function */
header_field_info hfinfo; /**< the field info to be registered */
} hf_register_info;
.
.
hf_register_info hf[MAX_HF_COUNT];
.
.
*(hf[i].p_id) = -1;
The final line of code above causes an exception. How do I correctly deference p_id?
Thanks and regards...Paul
You need to initialize your pointers. You pointers in your structs aren't pointing to anything at the moment you initialize your array.
So for every struct in your array you want to dereference your pointer and assign a value to, you'll need to allocate space in your memory first.
hf_register_info hf[MAX_HF_COUNT];
// some code here
hf[i].p_id = malloc(sizeof(int)); // or unsigned long or whatever
*(hf[i].p_id) = -1;
Related
I have a structure that contains a pointer to a 2d-array that will be allocated in an initialization function. It's also important to allocate this array in a contiguous block of memory.
I know to allocate a contiguous block of memory as a 2d-array like this:
double (*array)[cols] = malloc(rows* sizeof *array);
However I need to do this on an already declared variable. For example:
typedef struct {
double **data;
/* other members */
} MyType;
MyType* init_function(/* args */)
{
/* more initializing */
MyType* foo = malloc(sizeof(MyType));
double (*array)[3] = malloc(3 * sizeof(*array));
foo->data = array;
/* more initializing */
}
I would think this would work, but my program crashes as soon as it attempts to either read or write from foo->data. I've printed the pointer address to both array and foo->data and they are identical, and I'm also able to print the contents of array, however attempting to access foo->data[0][0] causes the program to crash. I'm unsure why this won't work, or how to allocate the memory in this fashion on foo->data which is already declared.
The type of data member must be the same as the allocated object. It must be a pointer to 3 element array of double.
typedef struct {
double (*data)[3];
/* other members */
} MyType;
I have a struct in my main function. I pass that pointer to another function which does some stuff and if conditions are met, it passes it to another function to get filled out. When returning to the main function the t struct contains none of the data mydata that was copied into it.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
void second(T *t) {
t = malloc(20);
memcpy(t, mydata, 20);
}
void first(T *t) {
second(t);
}
int main() {
T t;
first(t);
}
Do I need to be working with double pointers here? If the address of t was 0x1000 and I passed it to first() then wouldn't referencing t just be 0x1000? And same as if I pass the pointer to second()?
In this answer, I assume that, for reasons not shown, you do in fact need to make a dynamic memory allocation. If that is not the case, the only changes that need to be made are replacing first(t); with first(&t);, and removing t = malloc(20);.
The first problem to fix is that t in main should have the type T *, not T. You are making a dynamic memory allocation, and seem to want to store that pointer in t, so you would need: T *t;.
The second problem is that you want to manipulate the value of t in main, but are passing it by value to first. Instead, you need to pass a pointer to t into first: first(&t);.
Fixing both of these, you now pass a pointer to a pointer to T (the type of &t) into first and second, so you need to change their signatures to be, respectively, void first(T **t) and void second(T **t).
Applying both changes, as well as making some small style tweaks, we get:
typedef struct T {
int one;
int two;
int three;
int four;
} T;
void second(T **t_ptr) {
*t_ptr = malloc(20);
memcpy(*t_ptr, mydata, 20);
}
void first(T **t_ptr) {
second(t_ptr);
}
int main() {
T *t;
first(&t);
}
Another thing that's missing, and needs to be added, is checking for the success of malloc, but I haven't added that to the above code.
Also, what you've shown in the question shouldn't compile; you're passing a struct to a function that accepts a pointer.
Your problems are common to new C developers. And actually you have two of them.
The first problem is that you pass your structure by value.
The first function is declared to receive a pointer to T but you pass t and not &t (which is the address of t - and this is what you want when a function accepts a pointer).
However there is still another problem so that even if you change your code as suggested above it will still not work correctly. second allocates memory using malloc. The function receives T as a pointer T *t. You assign the output of malloc to t in effect overwriting what t points to (and if t was previously allocated you will leak memory here).
Bellow you can see a correct code for what you want.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
/* Make sure we have some data to initialize */
T mydata = {0};
/*
We take a pointer to a pointer and change what the external pointer points to. */
In our example when this function is called *ppt is NULL
and t is a pointer to t in main()
*/
void second(T **ppt) {
/*
We never calculate the size of structures by hand. It can change depending on
OS and architecture. Best let the compiler do the work.
*/
*ppt = (T*)malloc(sizeof(T));
memcpy(*ppt, &mydata, sizeof(T));
}
void first(T **ppt) {
/* Make sure we don't leave dangling pointers. */
if (NULL != *ppt)
free(*ppt);
second(ppt);
}
int main() {
T *t = NULL; /* A pointer to our data */
/*
We pass a pointer to our pointer so that the function can change the value it
holds
*/
first(&t);
/* Always do an explicit return if the type of the function is not void */
return 0;
}
How to understand what is going on:
First we declare t as a pointer to a memory holding a type T and we make sure we initialize the pointer to point to NULL (which is a convention meaning that the pointer is not initialized).
We have a function that will allocate the memory for us using malloc. malloc allocates memory from the heap and returns the address of that memory. (In reality a pointer is just a variable holding an address in memory). We want to place that address in t declared in main(). To do so we need to pass to the allocating function the address of t so it can be modified. To do this we use the address of operator - &. This is why we call the function like this first(&t).
Our allocating function accepts a pointer to a pointer. This is because we want to change the address t points to. So we declared the parameter as T **ppt. It holds the address of the pointer *t in main. In the function we dereference the pointer to the pointer to get the original pointer we want to assign the address malloc returns.
In C:
When a struct is sent (via a parameter) by value in to a function, a new struct is created, so changing the structure inside the function won't change the original structure.
When an array is sent (via a parameter) by value in to a function, a new pointer is created, so changing the array inside the function won't change the original array, but changing array values inside the function (since we have the pointer to the original array) will change the values in the original array.
When a struct with an array field is sent (via a parameter) by value in to a function, ????? is created, so that changing the array (pointer) inside the function won't change the original array and changing array values won't change the values in the original array.
Does the third point mean that an array field of a struct, when sent in to a function will be entirely cloned? Why isn't just the pointer used instead? What does the specification say about it?
A piece of code that I've played with:
typedef struct {
int value;
int array[3]; /* initialized to 0 by default */
} Struct_t;
void foo(Struct_t structure)
{
printf("-- %p\n", structure.array); /* Pointer to local array */
structure.value = 1;
*structure.array = 1; /* Won't change the original array */
*(structure.array + 1) = 1; /* Won't change the original array */
structure.array[2] = 1; /* Won't change the original array */
}
int main()
{
Struct_t s = { .value = 0 };
foo(s);
printf("-- %p\n", s.array); /* Pointer to original array */
printf("%d\n", s.value);
printf("%d\n", s.array[0]);
printf("%d\n", s.array[1]);
printf("%d\n", s.array[2]);
}
Output:
-- 0x7ffe8f17d194
-- 0x7ffe8f17d1b4
0
0
0
0
OP's "When an array is sent ..." needs clarification.
When an array is sent (via a parameter) by value in to a function, a new pointer is created, so changing the array inside the function won't change the original array, but changing array values inside the function (since we have the pointer to the original array) will change the values in the original array. (OP)
When an array, like s[] below, is passed to strcpy(char *s1, const char *s2), a conversion occurs first. The object s is converted to the address of the first element of the array. strcpy() does not receive s[] as the s1 parameter, instead it receives a copy of the value of of &s[0].
char s[6] = "Hello";
strcpy(s, "World");
Within strcpy(), s1 is not an array. s1 is a pointer to a char. strcpy() has no concept of "changing the array inside the function" as the function does not know s1 points to array memory, allocated memory or anything else. strcpy() understands s1 points to a char.
Does the third point mean that an array field of a struct, when sent in to a function will be entirely cloned?
Yes. When an object is passed to a function in C, it is potentially converted and then passed by value. It is much like any assignment. The contents of the object, after conversion is copied to the destination. It makes no difference, after conversion, if the object is a struct, union, int, double, void*, int(*)() etc or a struct containing an array.
int a;
double b;
a = 5; // 5 is copied to a
b = a; // a is converted to double and copied to b
char s[6] = "Hello";
char *e;
void *v;
e = s; // s is converted to the address on the first array element and then copied to e
v = e; // e is converted to a `void*` and then copied to v
Struct_t f = {0};
Struct_t g;
g = f; // f is copied to g
Does the third point mean that an array field of a struct, when sent in to a function will be entirely cloned?
Yes.
Why isn't just the pointer used instead?
Because there is no pointer. An array is not a pointer. (More on this here.)
In C everything is pass-by-value.
When we pass-by-value we are passing a copy of the variable to a function.
When we pass-by-reference we are passing an alias of the variable to a function.
It is copying the value of the pointer, the address, into the function.
If a struct is passed by value to a function the bytes of the
struct are copied as the function parameter. Anything done to that
struct within the function changes the copy, not the original
struct
A struct is a predefind structure of memory, that has a certain memory layout. By adding an array to the struct the actual memory of the array is located in the struct not a pointer. That is why it has to be copied with the rest of the struct.
Arrays are not pointers, an arrays has a specific unchangable memory location, while a pointer can point anywhere you want.
I have N statically allocated structures.
struct exemple{
...
}
struct exemple array[N];
struct exemple *test_ptr = 0x3; /* random address */
Can I check if test_prt points to a valid address? i.e. it points to one "struct example" allocated.
You can't. You have to know. It's not a problem if you manage your pointers correctly. A good habit is to always set pointers to 0 / NULL as soon as you destroy the object they point to. Then you can just test with if (ptr) or if (!ptr) (or, more verbose: if (ptr == NULL) / if (ptr != NULL)).
Note that your last assignment
struct exemple *test_ptr = 0x3; /* random address */
is invalid. you can't assign an integer to a pointer. but you can cast it to the pointer type;
struct exemple *test_ptr = (struct exemple *)0x3; /* random address */
The result will depend on your implementation / system.
You can only check if pointer is valid by doing pointer != NULL because anything except `NULL' is treated by valid pointer.
In your case, to check if your pointer points to any of your array entry, you can only do this:
size_t i = 0;
int isValid = 0;
for (i = 0; i < N; i++) {
if (test_ptr == &array[i]) {
isValid = 1;
break;
}
}
if (isValid) {
//Pointer points to one of your array entry
}
But in general, you cannot just test if pointer points to specific valid location for you. It is up to you to take care of where it points. It can also have NON-NULL value but points to invalid location, for example:
int* ptr = malloc(10); //Now points to allocated memory
*ptr = 10;
free(ptr); //Free memory
*ptr = 10; //Undefined behaviour, it still points to the same address but
//we don't know what will happen. Depends on implementation
In general, no, you can't test if a pointer is valid or not.
But, if you want to know if a pointer points to an element of an array, you can:
if(test_ptr >= &array[0] && test_ptr < &array[N]
&& ((intptr_t)test_ptr - (intptr_t)array)%((intptr_t)(&array[1]) - (intptr_t)array) == 0) {
// test_ptr points to an element of array
}
This works because arrays are allocated contiguously.
There is no language method but in some circumstances you can try to have some known values at the certain points of the structure. If the pointed memory location has those values you can assume it as valid - but of course you do not have any guarantee. But you need to write your own functions when you create the structure, and when you destroy it (by filling with zeros before freeing the memory). It is a very week workaround - but if you connect with another measures and accept the overhead it makes the probability of the incorrect program behaviour lower.
Sometimes it is called a security cookie.
it is possible of course to make it more complicated - at certain positions you have only offsets to those cookies. It makes less probable that the random position in the memory will have such a chain of data :)
I don't know if I get your question properly.
If you want to know if a pointer points to a struct of some type (cast my structs to void * and vice-versa, for example), I do the next way:
#include <assert.h>
struct my_struct {
#ifndef NDEBUG
#define MY_STRUCT_MAGIC 0x1234abcd
uint64_t magic;
#endif
int my_data;
};
void init_struct(struct my_struct *s, int t_data) {
#ifdef MY_STRUCT_MAGIC
s->magic = MY_STRUCT_MAGIC;
#endif
s->my_data = t_data;
}
my_struct *my_struct_cast(void *vs) {
my_struct *s = vs;
#ifdef MY_STRUCT_MAGIC
assert(MY_STRUCT_MAGIC == s->magic);
#endif
return s;
}
It has a little bit more code because of inclusion of const-casting, but I think you get the idea.
If you want to know if test_ptr points to a aray member, you have to check this way: test_ptr >= array && test_ptr < &array[sizeof(array)/sizeof(array[0])]). If the pointer comes from void, char, or some kind of dangerout ariyhmetic, you could also check for test_ptr % sizeof(array[0])
If you want to know if a pointer points to valid memory "ever allocated" by your program, you will have to intercept allocs functions, save returned chunks pointer & size, and compute like the previous example.
How can I pass an array of structures?
So far I have this which is global:
typedef struct _line
{
float val1;
int val2;
} line;
Then I read data from a file into this structure
struct _line* read_file()
{
typedef struct _line *Lines
Lines *array = malloc(num_lines * sizeof(Lines));
//read values into structures here
Then I fill up the structures in the array with values. If I do printf("%d", (*array[1]).val1); I get the right value here in this particular method
Then I return the array like so
return *array
But when I do so, only the 0th structure reads correctly in the method I returned to. Reading the 1st element just prints random values. What am I doing incorrectly?
You should not dereference the array when you return it1, it's actually of incompatible type with the function return type, just
return array;
also, check that array != NULL after malloc() before reading the values, and you don't really need the typedef it makes your code a bit confusing.
If your code compiled which I doubt, then you don't have warnings enabled in your compiler command, enable them so you can prevent this kind of issue.
(1) *array is equivalent to array[0].
Expanding on my comments, your code (as you describe and show it) you have undefined behavior:
This is because you allocate an array of pointers, but you apparently do not allocate the pointers in that array. So when you dereference a pointer (which you haven't allocated and whose value is indeterminate and so will point to a seemingly random location) you have this undefined behavior.
Instead of using a type-alias like Line use the structure name, like
struct _line *array = malloc(num_lines * sizeof(*array));
That will allocate num_lines structures (instead of pointers), then you use it like a normal array, without the pointer dereferencing
array[x].val1 = something;
And you of course return that pointer array as-is:
return array;