How can I use pointers to structure elements? - c

I have the following "test code":
#include <stdlib.h>
#include <stdio.h>
...
struct data{
char *name;
void *value;
};
struct g_arg{
char *info1;
char *info2;
int info3;
};
int main()
{
char *some_info = "information to store in g";
struct g_arg g;
struct data d[] = {
{"info1=", &g.info1},
{"info2=", &g.info2},
{"info3=", &g.info3},
{NULL, NULL},
};
...
}
I want to insert a value in the g struct elements, passing through d struct. For instance, I'd like to make something like this:
d[0].value = some_info;
After the execution of this instruction, g.info1 should contains the string some_info.
This is only an example code. I have to make something similar in a complex program. I searched for other questions like this, but I don't find a solution.
Thank you to all of you guys. I make some progress, but the problem is not solved yet. I'll try to explain a little better.
Now, if I do this:
printf( "content of g.info1: %s", (char*)(d[0].value) );
I can read the content of g.info, by accessing to d structure. But I need to write inside g.info, by "writing" something in d[i].value.

your g_arg pointers info1 and info2 need to be tied to some memory to be able to assign to them latter.
Since those are pointers, you cannot assign one string to another, so use some thing like strcpy.
Also if you know the sizes, you can make info1 and info2 as char arrays instead of having to dynamically allocate memory for them.

Point 1. allocate memory to g.info1 using malloc() [or family].
Point 2 . use strcpy() to copy the data to d[0].value
Point 3. You don't need to use &g.info1, g.info1 will suffice.

In your code, g.info1 has type char *, so &g.info1 has type char **. You can certainly assign that to the void * element value of a struct data, but it is a pointer to a (maybe) string, not a string itself.
Moreover, the result is a pointer to a stack-allocated pointer. If this pointer value survives past the end of the function then it will cease to be valid, and any attempt to dereference it will produce undefined behavior.
If you want to copy string values into elements of array d instead of assigning pointers to them as you now do, then you must first have strings to copy. In that case, you can use strdup() to allocate space and copy the string in one step:
struct g_arg g = { "info 1", "info 2", 42 };
struct data d[] = {
{"info1=", NULL},
{"info2=", NULL},
{"info3=", NULL},
{NULL, NULL},
};
d[0].value = strdup(g.info1);
d[1].value = strdup(g.info2);
d[2].value = malloc(sizeof(int));
*((int *) d[2].value) = g.info3;
Note that in this case, all the resulting pointers recorded in the value members of elements of d refer to dynamically allocated memory. This allows them to remain valid past the function's exit, but it requires the program to later free() them to avoid leaking memory.

wrt to d[0].value = some_info; this would in theory work if some_info was already an object of type struct g_arg whose member info1 was already set to a string.
But it seems that you want some_info to be a string (char *, C style);
So you'll need to reference the info1 member of d[0].value. So you'll need to cast the void* to the appropriate data type (struct g_arg *)(d[0].value) and then access the member info1, like so: ((struct g_arg *)(d[0].value))->info1.
Since info1 is a char * you should use strdup() to copy the string into an appropriately allocated buffer or manually allocate the memory for the string before copying. You end up with this:
((struct g_arg *)(d[0].value))->info1 = strdup(some_info);
Remember to free() the memory when you're done.

Related

array of structure pointers

So I have 3 files: main.c,countries.h and countries.c
I declare pointer of the structure called "Country" in the countries.h
I have included the countries.h in countries.c and in main.c
and declared the structure its self in countries.c
countries.h
typedef struct Country* pCountry;
countries.c
struct Country {
char *name;
pCity cities;
int numCities;
pTerritory countryTerr;
};
now, I want to create array of pointers of the Country structure, using malloc
so I did that:
pCountry countries_array;
countries_array = (pCountry);
malloc(num_of_countries*sizeof(countries_array));
and to assign pointers to each pointer,even though the malloc, does seems to work I cant
assign pointers to the elements in the array using []:
countries_array[0]= new_pointer;
I get "invalid use of undefine struct country" and "derefrecing pointer to incomplete",
what is the problem with the code?
thanks
Looks good. Just assign it to something of the same type, struct Country. Also, as pointed out in the comments, it should be malloc num_of_countries * sizeof struct Country (not the pointer type), which is now correctly dereferenced below as sizeof (*countries_array) which also works.
pCountry countries_array;
countries_array = malloc(num_of_countries * sizeof (*countries_array));
struct Country Jefferson = {"Jefferson", 1,2,3 };
countries_array[0] = Jefferson;
// don't forget to free the memory when no longer needed.
free (countries_array);
If we must put a pointer into this array of structs, we can either dereference the pointer like countries_array[0] = *pointer, or... we could declare countries_array as an array of pointers, instead of an array of structs. Perhaps this is what you may want. Either way, the actual structures have to occupy memory somewhere...
pCountry *countries_array = malloc(num_of_countries*sizeof countries_array);
pCountry j = &Jefferson; // `&`, "address of" operator
countries_array[0] = j; // put a `pointer` into the array...

Initializing and accessing char array in struct

I cannot seem to find a way to initialize a struct without getting segmentation fault .
Here is the assignment `
int id = 5;
// scanf ("%10d", &id);
printf("Please give an name\n");
char *tmpName = (char*)malloc(MAXSTRING * sizeof(char));
fgets(tmpName,MAXSTRING,stdin);
student newStudent = (student){ .id = id , .name = tmpName };
printf("%d",newStudent.id);
printf("%s",newStudent.name);
`
And here is the struct itself
#define MAXSTRING 256
typedef struct{
char *name;
int id;
}student;
I can successfully initialize the struct , but I cannot get access to the name variable , any thoughts?
EDIT : Answers submitted at the time offered nothing , the problem was the way the struct was initialized
char tmpName[MAXSTRING] = {0};
scanf("%s",tmpName);
student newStudent = { .id = id };
strcpy(newStudent.name,tmpName );
This block fixed the issue , will close the topic.
You define a pointer
char *tmpName;
you do nothing to make it actually point to some useable space, especially there is no malloc() or similar.
The you have scanf() (if successful...) write to the pointer, but a string, not any meaningful address. I.e. if that string is not extremely short, you certainly write beyond.
scanf("%s",&tmpName);
Do not be surprised by segfaults, be surprised if there are none.
Later on you then read from where that weird non-pointer points to...
To solve, insert a malloc() after the pointer definition. Alternatively use fixed array of char as an input buffer.
Use the pointer itself, not its address, in scanf() to write the string into the malloced space. (Or the array identifier.)
The rest is the typical set of problems with having enough space, failing to scan, without checking return value etc. Here is a great set of basic hints for getting input right:
How to read / parse input in C? The FAQ
When you declare char name[MAXSTRING], you are telling your compiler that it will always have the exact length of MAXSTRING.
When the compiler hears that, he will most likely replace your string with a lot of static char members.
#define MAXSTRING 4
typedef struct{
char name[MAXSTRING];
int id;
}student;
Would be extended and compiled more like so :
#define MAXSTRING 4
typedef struct{
char name0;
char name1;
char name2;
char name3;
int id;
}student;
Although you would still need to access those using the syntax name[index], as you declared an array, the array pointer is in fact nowhere to be found. So you can't directly assign it.
This is basically what happens with any fixed-length array, they won't allow you to asign them since their content is directly stored in the stack or in the datastructure enclosing it.
You would need to declare.
typedef struct{
char *name;
int id;
}student;
To get a char array pointer of variable length that you can assignate.
That should answer your question, now, as stated by someone in your comment section, there are other things wrong in your code and even with the correct structure, you will probably be unnable to do what you want since scanf is probably returning an arror right now. ^^'
Try allocating the memory beforehand doing so :
char *yourstring = (char*)malloc(MAXSTRING * sizeof(char));
And of course, don't forget to free when you don't need either the string or your student structure :
free(yourstring);
Then again, there's another small issue with your assignement since you do something like this :
.name = *yourstring
While using pointers, prefixing them with * will access the value at the pointed address.
Supposing char *yourstring = "I love cats.";
Doing .name = *yourstring will result in .name being equal to 'I' character, which is first in the array pointed to by yourstring. (Most compiler would complain and ask you to cast.. do not do that.)
So what you really need to do is to assign the pointer to your .name array pointer.
.name = yourstring

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

A Simple Object System

I'm working my way through the learn c the hard way book and have run into a few issues on Exercise 19. The author said that ex19 was intended for the learners to get to know the macro in c. I have no problem in understanding the concept of that, but I just don't understand everything else. I can't understand how the object prototype is created.
Especilly,what does the following sentense mean?
Since C puts the Room.proto field first, that means the el pointer is
really only pointing at enough of the block of memory to see a full
Object struct. It has no idea that it's even called proto.
the relevant code is this:
// this seems weird, but we can make a struct of one size,
// then point a different pointer at it to "cast" it
Object *el = calloc(1, size);
*el = proto;
can anyone tell me how on earth malloc/calloc exactly works? As far as i know, it just allocate the required number of memory and return the first address. If so, how can the computer know the data struct of the allocated memory? like in the code, after Room *arena = NEW(Room, "The arena, with the minotaur");,you can do this directly arena->bad_guy = NEW(Monster, "The evil minotaur"); how does the computer know there is a bad_guy??
what on earth is the content of *el after the above two statements(Object *el = calloc(1, size); and *el = proto;)?
Any help will be appreciated!!
the link to the exercise: http://c.learncodethehardway.org/book/ex19.html
calloc has the additional feature that it fills the allocated memory with zero bytes, whereas using the equivalent malloc call would require an additional step if all or some of the allocation needs to be zero initially.
In the code
arena->bad_guy = NEW(Monster, "The evil minotaur");
the compiler knows the layout of the struct because the access is through the arena variable, which is declared as a pointer to Room, which is presumably a typedef of a struct.
For the other part, the guarantee of ordering within structs allows a limited form of inheritance in composite structs, or extended structs.
struct A {
int x;
};
struct B {
int foo;
double baloney;
};
struct B (or a pointer to it) can be cast to a (pointer to a) struct A because they both begin with an int. Of course, if you cast the other way, the struct A must have been originally a struct B or access to the baloney field will be undefined. In other words, struct B essentially begins with a struct A.
This may be easier to see if I rewrite my example like this:
struct A {
int x;
};
struct B {
struct A foo;
double baloney;
};
Now you can get a struct A out of struct B in different ways.
struct A a;
struct B b;
a = b.foo; // regular member variable access
struct A *ap = &a;
struct B *bp = &b;
ap = (struct A *)bp; // cast the pointer
ap = & b.foo; // take a pointer from the member variable
ap = & bp->foo; // take a pointer from the member variable via a pointer
All it does is to alloc 1*size bytes. There's nothing magic with malloc/calloc. He is passing the sizeof(T) to the function through that NEW macro and putting it in Object_new's size parameter. So all the function knows is the size in bytes.

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!

Resources