typedef, arrays and pointers in C - c

I am studying a code written in C language.
The following part isn't clear for me:
typedef uint8_t data_t[4][4];
typedef struct {
data_t *data;
...
} my_struct;
The thing that I don't understand is, what is the type of data?
Plus, I want to assign values to this variable.
For example, in the code there is:
my_struct st;
st.data = (int8_t *)array
where array is defined as int8_t *array.
I don't understand how this assignation works, could someone explain it clearly?
To finish, is it possible to assign values to my data_t variable without declaring it as a pointer in my structure?

The thing that I don't understand is, what is the type of data?
The type of data is a pointer to a two-dimensional array. That is uint8_t(*data)[4][4].
See C right-left rule for deciphering C declarations.
Plus, I want to assign values to this variable st.data = (int8_t *)array.
In this case array must have the same layout as uint8_t[4][4] array. Since arrays are contiguous in C, that array must have at least 4 * 4 elements of type int8_t.
The fact that you have to cast the array with (uint8_t*) first implies that array has a different type and that may cause trouble.
Note that this is a pointer assignment only, not an element-wise copy of array.
is it possible to assign values to my data_t variable without declaring it as a pointer in my structure?
It is possible if data is not a pointer, i.e. declare it as data_t data;. And then copy into it using memcpy.

This declaration
typedef uint8_t data_t[4][4];
declares name data_t as an alias for type uint8_t [4][4].
Thus in the structure definition
typedef struct {
data_t *data;
...
} my_struct;
member data is a pointer of type data_t * that is the same as uint8_t ( * )[4][4].
So it is a pointer to a two-dimensional array of pointers to objects of type `uint8_t
Arrays do not have the assignment operator. You have to copy elements of one array into another.
If for example you have another one-dimensional array of pointers like
uint8_t *array[4];
you could write
my_struct st;
st.data = malloc( sizeof( data_t ) );
memcpy( st.( *data )[0], array, 4 * sizeof( uint8_t * ) );
Take into account that as the data is a pointer you have at first to allocate memory where you are going to copy objects of type uint8_t *.

Related

Assigning Arrays inside a Struct to a new Struct with Arrays

So I have a struct with arrays inside it like so:
struct struct1 {
unsigned char data1[32];
unsigned char data2[32];
char *id;
};
and a second struct defined as
typedef struct
{
uint8_t id;
uint8_t data1[32];
uint8_t data2[32];
} struct2;
Struct1 with data already inside it is passed to me via a function like so:
bool func1(struct struct1 * const struct1)
and I need to create a NEW struct2 and pass all the data from struct1 into it.
I thought I could just assign the pointers like so
struct2 *new_struct;
new_struct->id = struct1->id;
new_struct->data1 = struct1->data1;
new_struct->data2 = struct1->data2;
but I guess array pointers in C cannot be changed (or at least that's what I got from reading up on it).
So how do I create a new struct2 and pass the data I need into it from struct1?
array pointers in C cannot be changed
There is no such thing as an "array pointer". Either you have an array, or you have a pointer.
In your case data1 and data2 are arrays, so there is no pointer you could have reassigned. Your only choice is to copy the data stored in the arrays from one struct to the other.
You can use simple assignment (=) between struct variables of the same type, but in your case you have different types, so you need to copy each member separately. The easiest way to do that is to use memcpy (from <string.h>).
#include <string.h>
// ...
struct2 new_struct;
new_struct.id = *struct1->id;
memcpy(new_struct.data1, struct1->data1, sizeof new_struct.data1);
memcpy(new_struct.data2, struct1->data2, sizeof new_struct.data2);
Notes:
new_struct is not a pointer here. In your example you dereference an uninitialized pointer, which has undefined behavior.
I dereferenced struct1->id because struct2.id is a single char, not a pointer. I assume this is what you want to happen.

C structure pointer to a structure array, from a structure

I need some help with the pointer syntax. I have an array of structures, and I'm trying to create a pointer to it, from inside another structure, contained in an array.
struct foo array* = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;
I have read through this question: c pointer to array of structs. While it did clear up some of the confusion, I'm still left with a few errors to solve.
I have defined my structure like this:
struct bar{
...
struct foo (*foo_ptr)[];
...
}
It seems that I am able to add new structures to the array, as the following returns no errors:
(*bar_arr[i]->foo_ptr)[j] = new_struct;
However, if I attempt to create a new pointer to a struct inside of the struct array like this:
struct foo* one_ptr = (*bar_arr[i]->foo_ptr)[j];
or this:
struct foo* one_ptr = bar_arr[i]->foo_ptr[j];
the compiler will give me errors. Either one for invalid use of an array with unspecified bounds, or that one_ptr and foo_ptr[j] have incompatible types (in this case: one is of type foo and the other is struct foo *).
Is it simply not possible to create a pointer to one of the elements of the structure array? Any help would be appreciated.
EDIT: BETTER CODE EXAMPLE
I am currently working with a linearly linked list for use as a shared memory stack, for use with pthreads. The array of structures is a shared pool of nodes. Whenever a node is removed from the stack, it is put into the shared pool. If a thread attempts to add a new item to the stack, it checks whether or not the element to be added exists in the pool, to avoid having to allocate new memory every time it needs to add another element to the stack.
Each thread needs a pointer to the shared pool of nodes as an argument. That's why i'm trying to create a pointer to it from the argument structure. I was hoping that the question would have a simple answer.
typedef struct node{...} node_t;
struct thread_args
{
...
node_t (*pool)[];
...
}
node_t shared_pool = malloc(sizeof(node_t)*10);
arg[index]->pool = &shared_pool;
I am trying to access the pool inside one of the functions that the thread is executing.
node_t *item;
item = stack->root;
//remove item from stack
(*args->pool)[index] = item;
//...later
node_t *item2;
item2 = (*args->pool)[index];
Hopefully this provides some more information.
Also, the exact error i get from attempting to use:
node_t *pool;
args[index]->pool = shared_pool;
is as follows: error: incompatible types when assigning to type ‘struct node_t *’ from type ‘node_t’.
For starters this declaration (not mentioning the omitted semicolon after the closing brace)
struct bar{
...
struct foo (*foo_ptr)[];
^^^
...
}
is invalid. You have to specify the size of the array. Otherwise the pointer will point to an object of an incompete type.
Taking into account how you are trying to use the array this declaration does not make sense. You could declare the data member like
struct bar{
...
struct foo *foo_ptr;
...
};
and then
struct foo *array = malloc(sizeof(struct foo)*10);
bar_arr[i]->foo_ptr = array;
In this case you could write
bar_arr[i]->foo_ptr[j] = new_struct;
and
struct foo* one_ptr = bar_arr[i]->foo_ptr + j;
or
struct foo* one_ptr = &bar_arr[i]->foo_ptr[j];
This is wrong:
struct foo array* = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;
Assuming you mean
struct foo *array = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;
you are storing the address of the actual array variable into your structure's foo_ptr variable. From the code snippet you posted, that's likely a local variable for the function, so it's not only the wrong type, it ceases to exist once your function returns.
Given struct foo, this will allocate a pointer to an array of struct foo:
struct foo *array = malloc( nelem * sizeof( *array ) );
and this will assign that
bar_arr[i]->foo_ptr = array;
Or, more directly:
bar_arr[i]->foo_ptr = malloc( nelem * sizeof( *( bar_arr[i]->foo_ptr ) ) );
Note that I use a dereference to the pointer the malloc() result is being assigned to as the argument to sizeof(). That's a simple way to ensure that the pointer and the memory allocation done always refer to the same type.
The call to malloc() will allocate nelem contiguous copies of struct foo (which will contain unknown, unspecified data...). Those copies can be accessed via
array[ n ]
as long as n >= 0 and n < nelem.
Is it simply not possible to create a pointer to one of the elements of the structure array?
You're making your code too complex. To create a pointer to the nth element:
struct foo *nthElement = array + n;
You simply add n to the address of the first element, and the resulting pointer will refer to the nth element, assuming n is within the proper range.
Short answer
The declaration of foo_ptr in struct bar is not right. Change it into struct foo *foo_ptr. And change your assigning statement to the follows
struct foo *array = malloc(sizeof(struct foo)*10);
bar_arr[i]->foo_ptr = array;
Then you can read or write the element of the array like below
// read from array
struct foo one_struct = bar_arr[i]->foo_ptr[j];
// write to array
struct foo new_struct = { ... }
bar_arr[i]->foo_ptr[j] = new_struct;
(NOTE: the both read and write operation are copy of all fields of the struct foo).
Explanation of the changes
Think about an easy example. How do you make an array of 10 char.
char *a = malloc(sizeof(char)*10)
a is a pointer of char, it points to a space that contains 10 char. So we can use it as an array. a[4] means the 5th char of the array of 10 char.
What if you want to assign this array to another variable?
char *b = a;
Now b is an array too (not a copy of the original array, b and a point to one array). You can refer to the element via b now, just like what you do with a. E.g., b[4].
Nobody will declare b as char (*b)[] right?
More explanation of your mistakes
Still start with an simple example. When we see such a declaration -- char (*x)[10] -- what would we say about x? We may say x is a pointer to an array of 10 char.
Let's look at your declaration, struct foo (*foo_ptr)[]. Likewise, we may say, foo_ptr is a pointer to an array of ... length-unspecified struct foo. (Notice the difference in the length of array. Actually it is wrong not to specify the length, I'll talk about it soon)
Based on this declaration of yours, let's talk about the errors you encountered when using it.
Statement 1 that throws error
struct foo* one_ptr = (*bar_arr[i]->foo_ptr)[j];
To simplify and make it clear, I'm going to remove the part of bar_arr[i]-> in following discussion.
In this statement, *foo_ptr is an array of length-unspecified struct foo, we can call it this way, *foo_ptr is an array of struct foo []. So (*foo_ptr)[j] means the jth element of the array of struct foo []. Everything seems good here. BUT your array has no length defined, even though you assigned a malloc'ed array to it, but in compile-time, gcc has no idea about it. That is why it throws an error about "unspecified bounds".
Statement 2 that throws error
struct foo* one_ptr = bar_arr[i]->foo_ptr[j];
As I said above, foo_ptr is a pointer to an array of struct foo []. Let's pay attention to the fact that foo_ptr is a pointer first. So in this statement, foo_ptr[j] is kinda like *foo_ptr. Other than the index j, they have same type. Since we already know *foo_ptr is an array of struct foo [], foo_ptr[j] is also an array of struct foo []. It's an array, not an object of struct foo. To put it precisely, you need to imagine there is a big array, of which each element is still array (array of struct foo []). foo_ptr[j] is just the jth element, or say jth array, in this big array.
So the practice you assign foo_ptr[j] to one_ptr is more or less like the following example
typedef char char_array_of_4_t[4];
char_array_of_4_t array1;
char *p = array1; //ERROR: incompatible types
To make it easy to understand, I show you another exmaple below.
char array2[4];
char *p = array2;
In the second example, there is no error. In perspective of human being, array1 and array2 are both array of 4 char, however, in mind of gcc, array1 is a type of array, while array2 is a type of pointer.
In this declaration ...
struct bar{
// ...
struct foo (*foo_ptr)[];
// ...
};
... member foo_ptr of struct bar is declared as a pointer to an unknown-length array of struct foo. This is allowed, but it is unusual. One would ordinarily just declare a pointer to the first element of the array, as this plays out more naturally in C, and it's simpler, too:
struct bar{
// ...
struct foo *foo_ptr;
// ...
};
You can assign to the members of the pointed-to array via this form:
bar_arr[i]->foo_ptr[j] = new_struct;
(provided of course, that the pointed-to array has at least j + 1 elements. To get a pointer to such an element, you would do either
struct foo *struct_ptr = &bar_arr[i]->foo_ptr[j];
or, equivalently,
struct foo *struct_ptr = bar_arr[i]->foo_ptr + j;
You can do the same with your original struct declaration, but the form would need to be slightly different. For example:
struct foo *struct_ptr = &(*bar_arr[i]->foo_ptr)[j];
But really, make it easier on everybody, yourself included, and don't do that.

How to allocate memory dynamically for a struct [duplicate]

I have looked around but have been unable to find a solution to what must be a well asked question.
Here is the code I have:
#include <stdlib.h>
struct my_struct {
int n;
char s[]
};
int main()
{
struct my_struct ms;
ms.s = malloc(sizeof(char*)*50);
}
and here is the error gcc gives me:
error: invalid use of flexible array member
I can get it to compile if i declare the declaration of s inside the struct to be
char* s
and this is probably a superior implementation (pointer arithmetic is faster than arrays, yes?)
but I thought in c a declaration of
char s[]
is the same as
char* s
The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". The reason you're getting an error (probably anyway) is that it needs to be followed by a semicolon:
#include <stdlib.h>
struct my_struct {
int n;
char s[];
};
When you allocate space for this, you want to allocate the size of the struct plus the amount of space you want for the array:
struct my_struct *s = malloc(sizeof(struct my_struct) + 50);
In this case, the flexible array member is an array of char, and sizeof(char)==1, so you don't need to multiply by its size, but just like any other malloc you'd need to if it was an array of some other type:
struct dyn_array {
int size;
int data[];
};
struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));
Edit: This gives a different result from changing the member to a pointer. In that case, you (normally) need two separate allocations, one for the struct itself, and one for the "extra" data to be pointed to by the pointer. Using a flexible array member you can allocate all the data in a single block.
You need to decide what it is you are trying to do first.
If you want to have a struct with a pointer to an [independent] array inside, you have to declare it as
struct my_struct {
int n;
char *s;
};
In this case you can create the actual struct object in any way you please (like an automatic variable, for example)
struct my_struct ms;
and then allocate the memory for the array independently
ms.s = malloc(50 * sizeof *ms.s);
In fact, there's no general need to allocate the array memory dynamically
struct my_struct ms;
char s[50];
ms.s = s;
It all depends on what kind of lifetime you need from these objects. If your struct is automatic, then in most cases the array would also be automatic. If the struct object owns the array memory, there's simply no point in doing otherwise. If the struct itself is dynamic, then the array should also normally be dynamic.
Note that in this case you have two independent memory blocks: the struct and the array.
A completely different approach would be to use the "struct hack" idiom. In this case the array becomes an integral part of the struct. Both reside in a single block of memory. In C99 the struct would be declared as
struct my_struct {
int n;
char s[];
};
and to create an object you'd have to allocate the whole thing dynamically
struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);
The size of memory block in this case is calculated to accommodate the struct members and the trailing array of run-time size.
Note that in this case you have no option to create such struct objects as static or automatic objects. Structs with flexible array members at the end can only be allocated dynamically in C.
Your assumption about pointer aritmetics being faster then arrays is absolutely incorrect. Arrays work through pointer arithmetics by definition, so they are basically the same. Moreover, a genuine array (not decayed to a pointer) is generally a bit faster than a pointer object. Pointer value has to be read from memory, while the array's location in memory is "known" (or "calculated") from the array object itself.
The use of an array of unspecified size is only allowed at the end of a structure, and only works in some compilers. It is a non-standard compiler extension. (Although I think I remember C++0x will be allowing this.)
The array will not be a separate allocation for from the structure though. So you need to allocate all of my_struct, not just the array part.
What I do is simply give the array a small but non-zero size. Usually 4 for character arrays and 2 for wchar_t arrays to preserve 32 bit alignment.
Then you can take the declared size of the array into account, when you do the allocating. I often don't on the theory that the slop is smaller than the granularity that the heap manager works in in any case.
Also, I think you should not be using sizeof(char*) in your allocation.
This is what I would do.
struct my_struct {
int nAllocated;
char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};
int main()
{
struct my_struct * pms;
int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
pms = (struct my_struct*) malloc(cb);
pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}
I suspect the compiler doesn't know how much space it will need to allocate for s[], should you choose to declare an automatic variable with it.
I concur with what Ben said, declare your struct
struct my_struct {
int n;
char s[1];
};
Also, to clarify his comment about storage, declaring char *s won't put the struct on the stack (since it is dynamically allocated) and allocate s in the heap, what it will do is interpret the first sizeof(char *) bytes of your array as a pointer, so you won't be operating on the data you think you are, and probably will be fatal.
It is vital to remember that although the operations on pointers and arrays may be implemented the same way, they are not the same thing.
Arrays will resolve to pointers, and here you must define s as char *s. The struct basically is a container, and must (IIRC) be fixed size, so having a dynamically sized array inside of it simply isn't possible. Since you're mallocing the memory anyway, this shouldn't make any difference in what you're after.
Basically you're saying, s will indicate a memory location. Note that you can still access this later using notation like s[0].
pointer arithmetic is faster than arrays, yes?
Not at all - they're actually the same. arrays translate to pointer arithmetics at compile-time.
char test[100];
test[40] = 12;
// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;
Working code of storing array inside a structure in a c, and how to store value in the array elements Please leave comment if you have any doubts, i will clarify at my best
Structure Define:
struct process{
int process_id;
int tau;
double alpha;
int* process_time;
};
Memory Allocation for process structure:
struct process* process_mem_aloc = (struct process*) malloc(temp_number_of_process * sizeof(struct process));
Looping through multiple process and for each process updating process_time dyanamic array
int process_count = 0;
int tick_count = 0;
while(process_count < number_of_process){
//Memory allocation for each array of the process, will be containting size equal to number_of_ticks: can hold any value
(process_mem_aloc + process_count)->process_time = (int*) malloc(number_of_ticks* sizeof(int));
reading data from line by line from a file, storing into process_time array and then printing it from the stored value, next while loop is inside the process while loop
while(tick_count < number_of_ticks){
fgets(line, LINE_LENGTH, file);
*((process_mem_aloc + process_count)->process_time + tick_count) = convertToInteger(line);;
printf("tick_count : %d , number_of_ticks %d\n",tick_count,*((process_mem_aloc + process_count)->process_time + tick_count));
tick_count++;
}
tick_count = 0;
the code generated will be identical (array and ptr). Apart from the fact that the array one wont compile that is
and BTW - do it c++ and use vector

Dynamic array of pointers to structs

I have to use the following block of code for a school assignment, STRICTLY WITHOUT ANY MODIFICATIONS.
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
pStudentRecord* g_ppRecords;
int g_numRecords =0;
Here g_ppRecords is supposed to be an array of pointers to structs. What I am completely failing to understand is that how can the statement pStudentRecords *g_ppRecords; mean g_ppRecords to be an array because an array should be defined as
type arrayname[size];
I tried allocating memory to g_ppRecords dynamically, but that's not helping.
g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord*)*(g_numRecords+1));
EDIT: updated the "BIG MISTAKE" section.
A quick lesson on C-style (different from C++!) typedefs, and why it is how it is, and how to use it.
Firstly, a basic typedef trick.
typedef int* int_pointer;
int_pointer ip1;
int *ip2;
int a; // Just a variable
ip1 = &a; // Sets the pointer to a
ip2 = &a; // Sets the pointer to a
*ip1 = 4; // Sets a to 4
*ip2 = 4; // Sets a to 4
ip1 and ip2 are the same type: a pointer-to-type-int, even though you didn't put a * in the declaration of ip1. That * was instead in the declaration.
Switching topics.
You speak of declaring arrays as
int array1[4];
To do this dynamically at runtime, you might do:
int *array2 = malloc(sizeof(int) * 4);
int a = 4;
array1[0] = a;
array2[0] = a; // The [] implicitly dereferences the pointer
Now, what if we want an array of pointers? It would look like this:
int *array1[4];
int a;
array1[0] = &a; // Sets array[0] to point to variable a
*array1[0] = 4; // Sets a to 4
Let's allocate that array dynamically.
int **array2 = malloc(sizeof(int *) * 4);
array2[0] = &a; // [] implicitly dereferences
*array2[0] = 4; // Sets a to 4
Notice the int **. That means pointer-to pointer-to-int. We can, if we choose, use a pointer typedef.
typedef int* array_of_ints;
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
array3[0] = &a; // [] implicitly dereferences
*array3[0] = 4; // Sets a to 4
See how there's only one * in that last declaration? That's because ONE of them is "in the typedef." With that last declaration, you now have an array of size 4 that consists of 4 pointers to ints (int *).
It's important to point out OPERATOR PRECEDENCE here. The dereference operator[] takes preference over the * one. SO to be absolutely clear, what we're doing is this:
*(array3[0]) = 4;
Now, let's change topics to structs and typedefs.
struct foo { int a; }; // Declares a struct named foo
typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar'
Why would you ever typedef an anonymous struct? Well, for readability!
struct foo a; // Declares a variable a of type struct foo
bar b; // Notice how you don't have to put 'struct' first
Declaring a function...
funca(struct foo* arg1, bar *arg2);
See how we didn't have to put 'struct' in front of arg2?
Now, we see that the code you have to use defines a structure IN THIS MANNER:
typedef struct { } * foo_pointers;
That is analogous to how we did an array of pointers before:
typedef int* array_of_ints;
Compare side-by-side
typedef struct { } * foo_pointers;
typedef int* array_of_ints;
The only difference is that one is to a struct {} and the other is to int.
With our foo_pointers, we can declare an array of pointers to foo as such:
foo_pointers fooptrs[4];
Now we have an array that stores 4 pointers to an anonymous structure that we can't access.
TOPIC SWITCH!
UNFORTUNATELY FOR YOU, your teacher made a mistake. If one looks at the sizeof() of the type foo_pointers above, one will find it returns the size of a pointer to that structure, NOT the size of the structure. This is 4 bytes for 32-bit platform or 8 bytes for 64-bit platform. This is because we typedef'd a POINTER TO A STRUCT, not a struct itself. sizeof(pStudentRecord) will return 4.
So you can't allocate space for the structures themselves in an obvious fashion! However, compilers allow for this stupidity. pStudentRecord is not a name/type you can use to validly allocate memory, it is a pointer to an anonymous "conceptual" structure, but we can feed the size of that to the compiler.
pStudnetRecord g_ppRecords[2];
pStudentRecord *record = malloc(sizeof(*g_ppRecords[1]));
A better practice is to do this:
typedef struct { ... } StudentRecord; // Struct
typedef StudentRecord* pStudentRecord; // Pointer-to struct
We'd now have the ability to make struct StudentRecord's, as well as pointers to them with pStudentRecord's, in a clear manner.
Although the method you're forced to use is very bad practice, it's not exactly a problem at the moment. Let's go back to our simplified example using ints.
What if I want to be make a typedef to complicate my life but explain the concept going on here? Let's go back to the old int code.
typedef int* array_of_ints;
int *array1[4];
int **array2 = malloc(sizeof(int *) * 4); // Equivalent-ish to the line above
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
int a, b, c, d;
*array1[0] = &a; *array1[1] = &b; *array1[2] = &c; *array1[3] = &d;
*array2[0] = &a; *array2[1] = &b; *array2[2] = &c; *array2[3] = &d;
*array3[0] = &a; *array3[1] = &b; *array3[2] = &c; *array3[3] = &d;
As you can see, we can use this with our pStudentRecord:
pStudentRecord array1[4];
pStudentRecord *array2 = malloc(sizeof(pStudentRecord) * 4);
Put everything together, and it follows logically that:
array1[0]->firstName = "Christopher";
*array2[0]->firstName = "Christopher";
Are equivalent. (Note: do not do exactly as I did above; assigning a char* pointer at runtime to a string is only OK if you know you have enough space allocated already).
This only really brings up one last bit. What do we do with all this memory we malloc'd? How do we free it?
free(array1);
free(array2);
And there is a the end of a late-night lesson on pointers, typedefs of anonymous structs, and other stuff.
Observe that pStudentRecord is typedef'd as a pointer to a structure. Pointers in C simply point to the start of a memory block, whether that block contains 1 element (a normal "scalar" pointer) or 10 elements (an "array" pointer). So, for example, the following
char c = 'x';
char *pc = &c;
makes pc point to a piece of memory that starts with the character 'x', while the following
char *s = "abcd";
makes s point to a piece of memory that starts with "abcd" (and followed by a null byte). The types are the same, but they might be used for different purposes.
Therefore, once allocated, I could access the elements of g_ppRecords by doing e.g. g_ppRecords[1]->firstName.
Now, to allocate this array: you want to use g_ppRecords = malloc(sizeof(pStudentRecord)*(g_numRecords+1)); (though note that sizeof(pStudentRecord*) and sizeof(pStudentRecord) are equal since both are pointer types). This makes an uninitialized array of structure pointers. For each structure pointer in the array, you'd need to give it a value by allocating a new structure. The crux of the problem is how you might allocate a single structure, i.e.
g_ppRecords[1] = malloc(/* what goes here? */);
Luckily, you can actually dereference pointers in sizeof:
g_ppRecords[1] = malloc(sizeof(*g_ppRecords[1]));
Note that sizeof is a compiler construct. Even if g_ppRecords[1] is not a valid pointer, the type is still valid, and so the compiler will compute the correct size.
An array is often referred to with a pointer to its first element. If you malloc enough space for 10 student records and then store a pointer to the start of that space in g_ppRecords, g_ppRecords[9] will count 9 record-pointer-lengths forward and dereference what's there. If you've managed your space correctly, what's there will be the last record in your array, because you reserved enough room for 10.
In short, you've allocated the space, and you can treat it however you want if it's the right length, including as an array.
I'm not sure why you're allocating space for g_numRecords + 1 records. Unless g_numRecords is confusingly named, that's space for one more in your array than you need.
Here g_ppRecords is supposed to be an array of pointers to structs. What I am completely failing to understand is that how can the statement *pStudentRecords g_ppRecords; mean g_ppRecords to be an array. as an array should be defined as
type arrayname[size];
umm type arrayname[size]; is one way of many ways to define an array in C.
this statically defines an array, with most of the values being stored on the stack depending the location of it definition, the size of the array must be known at compile time, though this may no longer be the case in some modern compilers.
another way would be to dynamically create an array at runtime, so we don't have to know the size at compile time, this is where pointers come in, they are variables who store the address of dynamically allocated chunks of memory.
a simple example would be something like this type *array = malloc(sizeof(type) * number_of_items); malloc returns a memory address which is stored in array, note we don't typecast the return type for safety reasons.
Going back to the problem at hand.
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
pStudentRecord* g_ppRecords;
int g_numRecords = 0;
this typedef is a bit different from most note the }* basically its a pointer to a struct so this:
pStudentRecord* g_ppRecords;
is actually:
struct
{
char* firstName;
char* lastName;
int id;
float mark;
}** pStudentRecord;
its a pointer to a pointer, as to why they would define the typedef in this way, its beyond me, and I personally don't recommend it, why?
well one problem woud be how can we get the size of the struct through its name? simple we can't! if we use sizeof(pStudentRecord) we'll get 4 or 8 depending on the underlying architecture, because thats a pointer, without knowing the size of the structure we can't really dynamically allocated it using its typedef name, so what can we do, declare a second struct such as this:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
} StudentRecord;
g_ppRecords = malloc(sizeof(StudentRecord) * g_numRecords);
Either way you really need to contact the person who original created this code or the people maintaining and raise your concerns.
g_ppRecords=(pStudentRecord) malloc( (sizeof(char*) +
sizeof(char*) +
sizeof(int) +
sizeof(float)) *(g_numRecords+1));
this may seem like one possible way, unfortunately, there are no guarantees about structs, so they can actually containg padding in between the members so the total size of the struct can be actually larger then its combined members, not to mention there address would probably differ.
EDIT
Apparently we can get the size of the struct by simply inferring its type
so:
pStudentRecord g_ppRecords = malloc(sizeof(*g_ppRecords) * g_numRecords);
works fine!

Pointer to Two Dimensional Structure Array

I have a Structure say MyStruct:-
#define SEC_DIMENSION 2
struct MyStruct
{
char cChar;
float fFloat;
int iInt;
};
struct MyStruct StructArray[SEC_DIMENSION][20]; //Two Dimensional Array of Structures.
Now I want to access this with Pointer.
struct MyStruct *StructPtr[SEC_DIMENSION];
I did assignment as follows:-
StructPtr[0] = &StructArray[0][0];
Now, I want to access Members of Structure StructArray[0][1] i.e. StructArray[0][1].cChar or StructArray[0][1].fFloat
How can I access them by using StructPtr?
I tried using StuctPtr[0][1]->cChar then ((StructPtr[0])[1])->cChar
Both returned an error.
With StructPtr[0]->cChar build was successful. But this is not what I want.
"Now I want to access this with Pointer" is not very descriptive. What you have in your example will not work. What you declared is not a pointer to an array but rather an array of pointers. Is that what you need? I don't know.
If you really need a pointer to an array, you can declare your pointer it as
struct MyStruct (*StructPtr)[20];
and then make it point to your array as
StructPtr = StructArray;
From this point on you can access the original array through this pointer as StructPtr[i][j]
StructPtr[i][j].cChar = 'a';
Alternatively, you can declare the pointer as
struct MyStruct (*StructPtr)[SEC_DIMENSION][20];
and then make it point to your array as
StructPtr = &StructArray;
From this point on you can access the original array through this pointer as (*StructPtr)[i][j]
(*StructPtr)[i][j].cChar = 'a';
I think you need a "pointer to an array of dimension [SEC_DIMENSION][20] of structures of type struct MyStruct":
struct MyStruct (*StructPtr)[SEC_DIMENSION][20];
StructPtr = StructArray;
StructPtr[i][j]->cChar;

Resources