Reputation: 565
I'm really new to C programming and I'm still trying to understand the concept of using pointers and using typedef structs.
I have this code snippet below that I need to use in a program:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
I'm not exactly sure what this does - to me it seems similar as using interfaces in Objective-C, but I don't think that's the case.
And then I have this line
pStudentRecord* g_ppRecords;
I basically need to add several pStudentRecord
to g_ppRecords
based on a number. I understand how to create and allocate memory for an object of type pStudentRecord
, but I'm not sure how to actually add multiple objects to g_ppRecords
.
Upvotes: 2
Views: 238
Reputation: 5054
A struct is a compound data type, meaning that it's a variable which contains other variables. You're familiar with Objective C, so you might think of it as being a tiny bit like a 'data only' class; that is, a class with no methods. It's a way to store related information together that you can pass around as a single unit.
Typedef is a way for you to name your own data types as synonyms for the built-in types in C. It makes code more readable and allows the compiler to catch more errors (you're effectively teaching the compiler more about your program's intent.) The classic example is
typedef int BOOL;
(There's no built-in BOOL type in older ANSI C.)
This means you can now do things like:
BOOL state = 1;
and declare functions that take BOOL
parameters, then have the compiler make sure you're passing BOOL
s even though they're really just int
s:
void flipSwitch(BOOL isOn); /* function declaration */
...
int value = 0;
BOOL boolValue = 1;
flipSwitch(value); /* Compiler will error here */
flipSwitch(boolValue); /* But this is OK */
So your typedef above is creating a synonym for a student record struct, so you can pass around student records without having to call them struct StudentRecord
every time. It makes for cleaner and more readable code. Except that there's more to it here, in your example. What I've just described is:
typedef struct {
char * firstName;
char * lastName;
int id;
float mark;
} StudentRecord;
You can now do things like:
StudentRecord aStudent = { "Angus\n", "Young\n", 1, 4.0 };
or
void writeToParents(StudentRecord student) {
...
}
But you've got a *
after the typedef. That's because you want to typedef a data type which holds a pointer to a StudentRecord, not typedef the StudentRecord itself. Eh? Read on...
You need this pointer to StudentRecord because if you want to pass StudentRecords around and be able to modify their member variables, you need to pass around pointers to them, not the variables themselves. typedefs are great for this because, again, the compiler can catch subtle errors. Above we made writeToParents
which just reads the contents of the StudentRecord. Say we want to change their grade; we can't set up a function with a simple StudentRecord parameter because we can't change the members directly. So, we need a pointer:
void changeGrade(StudentRecord *student, float newGrade) {
student->mark = newGrade;
}
Easy to see that you might miss the *, so instead, typedef a pointer type for StudentRecord and the compiler will help:
typedef struct { /* as above */ } *PStudentRecord;
Now:
void changeGrade(PStudentRecord student, float newGrade) {
student->mark = newGrade;
}
It's more common to declare both at the same time:
typedef struct {
/* Members */
} StudentRecord, *PStudentRecord;
This gives you both the plain struct typedef and a pointer typedef too.
What's a pointer, then? A variable which holds the address in memory of another variable. Sounds simple; it is, on the face of it, but it gets very subtle and involved very quickly. Try this tutorial
Upvotes: 1
Reputation: 47001
The first declares an unnamed struct, and a type pStudentRecord
that is a pointer to it. The second declares g_ppRecords
to be a pointer to a pStudentRecord
. In other words, a pointer to a pointer to a struct.
It's probably easier to think of the second as an "array of pointers". As such, g_ppRecords[0]
may point to a pStudentRecord
and g_ppRecords[1]
to another one. (Which, in turn, point to a record struct.)
In order to add to it, you will need to know how it stores the pointers, that is, how one might tell how many pointers are stored in it. There either is a size somewhere, which for size N
, means at least N * sizeof(pStudentRecord*)
of memory is allocated, and g_ppRecords[0]
through g_ppRecords[N-1]
hold the N
items. Or, it's NULL terminated, which for size N
, means at least (N+1) * sizeof(pStudentRecord*)
of memory is allocated and g_ppRecords[0]
through g_ppRecords[N-1]
hold the N
items, and g_ppRecords[N]
holds NULL
, marking the end of the string.
After this, it should be straightforward to create or add to a g_ppRecords
.
Upvotes: 2
Reputation: 1866
defines a pointer to the struct described within the curly bracers, here is a simpler example
typedef struct {
int x;
int y;
}Point,* pPoint;
int main(void) {
Point point = {4,5};
pPoint point_ptr = &point;
printf("%d - %d\n",point.x,point_ptr->x);
pPoint second_point_ptr = malloc(sizeof(Point));
second_point_ptr->x = 5;
free(second_point_ptr);
}
Upvotes: 2
Reputation: 1786
This defines the name of a pointer to the structure but not a name for the structure itself. Try changing to:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
} StudentRecord;
StudentRecord foo;
StudentRecord *pfoo = &foo;
Upvotes: 0