struct counter{
long long counter;
}
struct instruction{
struct counter *counter
int repetitions;
void (*work_fn)(long long *);
};
int ncounter; //number of counters
struct counter *counter; //counter array
int nthreads; //number of threads
int *ninstructions; //number of instructions
struct instruction **instructions;
How does this actually works ? I am having trouble with ** pointers
A ** is just a pointer to a pointer. So where an instruction* contains the address of an instruction struct, an instruction** contains the address of an instruction* that contains the address of an instruction object.
To access the instruction pointed to by the pointer pointed to by an instruction**, you just use two asterisks instead of one, like (**p).repetitions or something similar.
You can visualize it like this:
instruction* ----> instruction
instruction** ----> instruction* ----> instruction
Remember, however, that simply declaring struct instruction** instructions; doesn't actually create an instruction struct. It just creates a pointer that holds a garbage value. You'll have to initialize it:
struct instruction inst;
// set members of inst...
*instructions = &inst;
...
(*instructions)->repetitions++; // or whatever
However, it looks like you're using an instruction** to point to an array of instruction*s. To initialize the array, you need a for loop:
instructions = malloc(sizeof(struct instruction*) * num_of_arrays);
for (i = 0; i < num_of_arrays; ++i)
instructions[i] = malloc(sizeof(struct instruction) * size_of_each_subarray);
And then you can access an element like instructions[i]->datamember.
struct instruction **instructions; // How does this actually works ? I am having trouble with ** pointers
I'm not sure what the real issue is, but I'll try to answer the question.
Double pointer is a pointer to pointer. It can be sued as array of pointers for example (if you allocate memory accordingly). For example:
instructions = malloc(5*sizeof(struct instruction*));
for (int i = 0; i < 5; i++)
instructions[i] = malloc(sizeof(struct instruction));
And you got yourself nice array of 5 pointers to struct instruction. Use it like this:
instructions[0]->repetitions = 0;
instructions is a pointer to a pointer to struct instruction.
This means that *instructions will give you a pointer to a struct instruction. This kind of construct is often used to create a dynamic array of pointers to some compound type.
Related
I have any error with execute bad access for this program.
Firstly, I have 3 structure.
struct format {
int initialCyclicShift;
int nrOfSymbols;
int startingSymbolIndex;
int formatID;
};
struct PUCCH_Resource {
//38.331 maxNrofPUCCH-Resources = 128
int pucch_ResourceId;
int startingPRB;
int intraSLotFrequencyHopping;
int secondHopPRB;
// 5 formats in PUCCH, 38.211. Also in 38.331
struct format (*formatList)[5]; //(*formatList) is a pointer that points to the whole array of size 5. The element of the array is a struct format
};
struct PUCCH_ResourceSet {
// 38.331 maxNrOfPUCCH-ResourceSet=4
int pucch_ResoureSetId;
// 38.331 maxNrofPUCCH-ResourcePerSet = 32; for Initial Access: maxNrofPUCCH-ResourcePerSet = 16. There could be repetition of pucch resource in different sets.
struct PUCCH_Resource (*ResourceList)[32];
};
Then I initialize the pointer, pointing to the parents structures PUCCH_ResourceSet , and children structures.
struct PUCCH_ResourceSet *pucch_ResourceSetPtr = (struct PUCCH_ResourceSet*) malloc (sizeof(struct PUCCH_ResourceSet));
pucch_ResourceSetPtr->ResourceList = malloc(sizeof(struct PUCCH_Resource));
for (int i = 0; i <32; i++){
for (int j = 0; j <5; j++)
pucch_ResourceSetPtr->ResourceList[i]->formatList[j]= malloc(sizeof(struct format));
}
(edit) I tried to initialize all the structs as suggested by member below, but still have the same issue.
and then try a get function that assign value to each member of the struct, for example:
pucch_ResourceSetPtr->ResourceList[0]->pucch_ResourceId=0;
pucch_ResourceSetPtr->ResourceList[0]->startingPRB = 0;
pucch_ResourceSetPtr->ResourceList[0]->formatList[0]->formatID=0; //this is where I have the error
The line of code above is the first to assign a value to a member of struct; this is where I have the error.
Upon the bugging, I see that when the PUCCH_ResourceSet, it see a memory block is assigned to the struct, its child struct, PUCCH_Resource, but not its grandchildren struct, format as show in the screenshot below.
I suspect it is the issue, but dont understand why no memory block is assigned to the format struct.
In addition, after some manipulating of code in order to allocated memory to member of structs, I have a build error at the format struct:
Does any one know the reason for this behavior and how I can resolve it?
First in a nested structure, I have to allocate memory to the structure.
There are multiple issues in structure, that cause issue with the way I allocate memory. For example, I used pointer to any array instead of array of pointers.
struct format (*formatList)[5]; //this is no array of pointer but a pointer to the beginning of an array.
I should just use:
`struct format *formatList[5];`
For such, I couldn't allocate memory as I wanted in step 1 properly.
The suitable code for the declared structs are as below.
struct PUCCH_ResourceSet *pucch_ResourceSetPtr = (struct PUCCH_ResourceSet*) malloc (sizeof(struct PUCCH_ResourceSet));
printf("%d", sizeof(struct PUCCH_Resource*));
for (int i = 0; i <32; i++){
pucch_ResourceSetPtr->ResourceList[i] = malloc(sizeof(struct PUCCH_Resource));
for (int j =0; j <5 ; j++)
{
pucch_ResourceSetPtr->ResourceList[i]->formatList[j] = malloc(sizeof(struct format));
}
}
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
I'm developing a driver in C for communication and the messages exchanged don't have a fixed size. The recommendation of communication bus is to use structs for multi-topics, which is also my case.
My 1st problem: I have to keep listening for new messages, and when I get one I have to process message data (it has a delay) and still listening for new messages.
1st solution: using thread when got new messages to process data.
My 2nd problem: Data in message can have multiple data of a struct, and my communicator requires using a struct to organize this multiple values.
2nd solution: using struct hack to allocate memory dynamic size of struct.
My current problem: when I'd pass my struct as argument to the thread, or any function, I'm loosing data structure and getting wrong values.
A short test which a made is:
typedef struct test{
int size;
int value[];
} test;
void allocation(test *v){
test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
int i;
aux->value[0] = 2;
aux->size = 3;
aux->value[1] = 1;
aux->value[2] = 5;
printf("Teste1 %d\n",aux->size);
for(i=0; i < aux->size; i++){
printf("%d\n", aux->value[i]);
}
*v = *aux;
}
void cleanup(test *v){
free(v);
}
int main(int argc, char *argv[]){
test v;
int i;
allocation(&v);
printf("Teste2 %d\n",v.size);
for(i=0; i < v.size; i++){
printf("%d\n", v.value[i]);
}
//cleanup(&v);
return 0;
}
In this test I got right values in first print and wrong values in second (only v.size is giving a right value).
And my struct is a little more complex than that in test. My struct is like:
typedef struct test1{
double v1;
double v2;
} test1;
typedef struct test2{
int size;
test1 values[];
} test2;
Do you know how to fix my memory struct in that function, once I have all elements necessary to fix? Please, keep in mind that is desirable (not required) that I could also allocate multiple test2 data.
The thing here is that you assign structs with incomplete member int value[]; Though it is in principle OK to copy two structs by value (and this is actually what happens if you write *v = *aux); However, as the compiler does not know which size member value[] will take on at runtime, the "sizeof" of v as well as the size of *aux is always 4, i.e. the known size of the one int member size. Hence, only this is copied, whereas the value[]-array simply gets not copied.
A way out out this situation would be require a pointer to a pointer (i.e. allocation(test **v), such that the memory reserved can be directly assigned to it, using a pointer to struct test in main, i.e. test *vptr, and call allocation(&vptr).
If you cannot avoid passing a reverence to the value (instead of a reference to a pointer to the value), I suppose you'll have to use memcpy to transfer the contents. But this does actually not make sense, because then the receiver must provide enough space to take on the value[]-array in advance (which is not the case if you simple declare a variable of the form test v). An then the malloc and the aux would make no sense; you could directly write into object v passed by reference.
You are declaring v as non-pointer, meaning that the memory is already allocated for v when you declare it in main. Sending the reference to your allocation only copies the size correctly since it is not dynamically allocated. Correct way to do this would be to:
Declare your v as pointer
Make your allocation return test* (test* allocation())
Assign it to v in main. i.e. something like v = allocate()
And use v like a pointer from then on
EDIT: Since OP wants this to work only as arguments, best way to go about it is using double pointer. Check the following code:
typedef struct test{
int size;
int value[];
} test;
void allocation(test **v){
test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
int i;
aux->value[0] = 2;
aux->size = 3;
aux->value[1] = 1;
aux->value[2] = 5;
printf("Teste1 %d\n",aux->size);
for(i=0; i < aux->size; i++){
printf("%d\n", aux->value[i]);
}
*v = aux;
}
void cleanup(test *v){
free(v);
}
int main(int argc, char *argv[]){
test **v;
v = malloc (sizeof (test*));
int i;
allocation(v);
printf("Teste2 %d\n",(*v)->size);
for(i=0; i < (*v)->size; i++){
printf("%d\n", (*v)->value[i]);
}
//cleanup(&v);
return 0;
}
Please note that your cleanup will change too after this.
i have the following structure:
typedef struct Course {
int course_id;
char* course_name;
int prior_course_id;
StudentTree* students;
} Course;
and the following function i need to implement:
void createReport(FILE* courses[], int numOfCourses, FILE* studentFile, char* reportFileName
as you can see i get an array of FILE*, each cell contains different file pointer.
my intention is to create an array that each cell is Course* type, and initialize each cell with a Course struct containing the data read from the courses files.
what is the correct way to declare it inside the function?
do i need to dynamically allocate memory for it, or it can be done in compilation?
i've tried
Course* course_array[numOfCourses] = {NULL};
Course* course_array[numOfCourses] = NULL;
but it won't compile.
thanks for your help
You declare an array of structs the same way you declare an array of ints or FILE *s:
Type variableName[numberOfElements];
Before C99 (and barring compiler specific extensions), creating an array with a variable number of elements on the stack wasn't supported. So make sure that you are targeting the correct standard. In your case, assuming C99 support, the following should work:
Course *course_array[numOfCourses];
Because you intend to initialize each of the elements in the array, there is no need to zero them out.
You would then access the elements like this:
course_array[0] = malloc(sizeof(Course))
course_array[0]->course_id = 2;
/* etc. */
Now if you can't assume C99 support, things get a bit more tricky but not much:
Course *course_array = malloc(sizeof(Course *) * numOfCourses);
After that you can access course_array with the same array notation:
course_array[0] = malloc(sizeof(Course))
course_array[0]->course_id = 42;
/* etc. */
Once you're doing with the array, you'll need to make sure that you free any of the memory that you allocated:
for (i = 0; i < numOfCourses; i++) {
free(course_array[i]);
}
/* If you malloc'd course_array, then you need this too */
free(course_array);
Course* course_array[numOfCourses] = {NULL};
This is good, but it creates array of Course *. So you need to allocate memory for each pointer in course_array before accessing it.
Something like
course_array[0] = malloc(sizeof(Course));
course_array[0]->course_id = someid;
When you define the array in the first place, you shouldn't need to allocate memory. You're defining the array on the stack, and the elements of the array are just pointers.
I think what you should do is first define the array, and then initialize each element with a malloc call. For example:
Course* course_array[numOfCourses];
for(int i = 0; i < numOfCourses, i++) {
course_array[i] = (Course*)malloc(sizeof(Course));
My favorite way:
typedef struct {
int a;
char b;
float c;
}DATA;
//then use typdef'ed DATA to create array (and a pointer to same)
DATA data[10], *pData;
//then, in function, you can initialize the pointer to first element of array this way:
int main(void)
{
pData = &data[0];
return 0;
}
Your example code would look like this:
typedef struct {
int course_id;
char* course_name;
int prior_course_id;
StudentTree* students;
} COURSE;
//then in function:
COURSE course[numOfCourses]
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!