I have
the struct:
typedef struct Rental {
int nDays;
float kmsDriven;
char carLicensePlate[LICENSE_PLATE_LENGTH+1];
char *clientName;
char chargingCategory;
} Rental;
Different -Rental type- structs are stored and accessed via a dynamically allocated array of pointers (here is a part of the project):
int main (){
Rental *rentals;
int max_num;
printf("Give a number of rentals you would like to store and manage: ");
scanf("%d", &max_num);
rentals=(Rentals *)malloc(max_num * (sizeof(Rental)))
This is what I have thought of so far but I can't understand it completely...so:
I'm having trouble understanding how *rentals can be an array. I mean shouldn't I declare it at least this way: Rental *rentals[];? I know that if I compile the above code I will see an error...but why?
I've read numerous posts here in Stack Overflow about doing this with double pointers (Rental **rentals;) but the code other people have posted is often very hard for me to read (I don't know all the functions etc. etc.)
Let's say I have the object rentals[0] which will be a pointer towards rentals. If I wanted to pass the struct to a function, should I write:
variable=function(*arguments*... , Rental *rentals[0]);?
rentals is a pointer, not an array, but it is a pointer to the first (zeroth) element of a block of max_num structures, so it can be treated as an array in that you can use rentals[n] to refer to the nth element of the array.
This is not a question and hence it is unanswerable.
Let's say I have the object rentals[0] which will be a pointer towards rentals. If I wanted to pass the struct to a function, should I write: variable=function(*arguments*... , Rental *rentals[0]);?
rentals[0] is not a pointer; it is a struct Rental or Rental.
If you want to pass the structure to the function, you write:
variable = function(…args…, rentals[0]);
If you want to pass a pointer to the structure to the function, you write:
variable = function(…args…, &rentals[0]);
or:
variable = function(…args…, rentals);
These pass the same address to the function.
You should be error checking the call to scanf() to make sure you got a number, and you should error check the number you got (it should be strictly positive, not zero or negative), and you should error check the value returned by malloc().
When you declare an array (for example char buffer[10]; the variable is actually pointing to that array. Pointers and arrays are very close together. In fact when you have a pointer where you store an array of data (just like your case with malloc) you can do something like pointer[0] and pointer[1] to get the correct element.
With a pointer in order to access an element you'd normally use *(pointer +1) to get the element on position 1, this is exactly the same as pointer[1].
When you want to pass a struct in an array, you can either give it by value like this:
void function(struct mystruct var)
{
//...
}
int main()
{
struct mystruct var;
function(var);
}
Or by reference (passing the address instead of the data - this is ideal if your structs are big in size) :
void function(struct mystruct *var)
{
//...
}
int main()
{
struct mystruct var;
function(&var);
}
By using an array, you can do it like this (still by reference):
void function(struct mystruct *var)
{
//...
}
int main()
{
struct mystruct var[10];
function(&var[0]);
}
And using a pointer (to an array) :
void function(struct mystruct *var)
{
//...
}
int main()
{
struct mystruct *var;
var = malloc( sizeof(struct mystruct) *10 );
//This will pass the address of the whole array (from position 0)
function(&var);
//This will pass the address of the selected element
function(&var[0]);
}
As you can see, declaring an array or a pointer is almost the same, expect that you have to initialize the pointer-array yourself (with malloc) and as with anything created with malloc you have to free it yourself too.
Related
I've those two structs :
typedef struct
{
char* name;
int flightCount;
Flight** flightArr;
LIST dateList;
int flightsSorted;
}Airline;
typedef struct
{
Airport* airportsArr;
int airportsCount;
}AirportManager;
and I need to write a general printer for both arrays (one is struct array and the other is pointer array).
I know that general printer should look like that:
void generalArrayFunction(const void* pArr, const int size, int sizeOfElement, void(*printer)(const void*))
{
for(int i=0;i<size;i++)
printer((char*)pArr + i * sizeOfElement);
}
and it's work great with the regular array which I print with the following line:
generalArrayFunction(manager.airportsArr,manager.airportsCount,sizeof(manager.airportsArr[0]),printAirport);
but with the pointer array I can't use the same logic and I dont know what should I do.the following line prints one struct but the second one messed up.
generalArrayFunction(*pComp->flightArr, pComp->flightCount, sizeof(pComp->flightArr[0]), printFlight);
any suggestions ?
If i got your intention right, In this code:
generalArrayFunction(*pComp->flightArr, pComp->flightCount, sizeof(pComp->flightArr[0]), printFlight);
sizeOfElement will be the size of a pointer because it's an array of pointers, you need to make another dereference to reach the struct and get the size, that's why the first struct is printing ok and the subsequent are not.
Try this:
generalArrayFunction(*pComp->flightArr, pComp->flightCount, sizeof((*pComp->flightArr)[0]), printFlight)
I'm going to try and keep this as brief as possible.
So I have two structs:
typedef struct someStruct named;
struct someStruct {
void *key;
void *value;
};
typedef struct anotherStruct namedToo;
struct anotherStruct {
named **table;
unsigned int size;
};
Okay great, now ingore any possible mistakes above, this is uneditable code.
Now I have two methods:
namedToo *init(float ignoreThis) {
namedToo *temp;
temp = malloc(sizeof(namedToo)); //some memory for the second struct
temp->table = malloc(sizeof(named)*100); //lets say this 100 is for 100 buckets/cells/named elements
return temp;
Method 2:
int insert(namedToo *temp, void* key, void* value) {
temp->table[0]->key = key; //My problem, I need to access the value and key inside named from the pointer inside namedToo. How can I do this?
}
The comment has my problem :
My problem, I need to access the value and key inside named from the pointer inside namedToo. How can I do this? I would need to change and grab value/key on their own from time to time.
The declaration named **table; says table is pointer to a pointer to named, or alternately an array of pointer to named. The latter is you seem to intend.
This allocation:
temp->table = malloc(sizeof(named)*100);
Allocates space for 100 named, but what you need are 100 named *, and each of those must point to a named. Given the definition of named this is likely enough space, however at this point you have an array of uninitialized pointers. Attempting to access them results in undefined behavior, which in this case manifests as a core dump.
You need to allocate space for an array of pointers, then initialize each of those to a single dynamically allocated instance of named. So you should be allocating space like this:
int i;
temp->table = malloc(sizeof(named *)*100);
for (i=0; i<100; i++) {
temp->table[i] = malloc(sizeof(named));
}
Then your insert method should work properly.
I've got a function that takes as an argument a pointer to an array of structs:
void foo (int *StructArrayAddress)
Within the function, I then build a new struct that looks like this
struct
{
int a;
int b;
char c[10];
}myStruct;
What I would then like to do is copy that struct to my array of structs based on the pointer to that array that I received as an argument. Not having any luck with the syntax, or I'm missing something. Can anyone advise?
Thanks!
EDIT: I'm not sure I explained myself correctly, as I don't think the solution posted here is what I want to do. To clarify: there is some array of structs outside my function here. I receive the address of the correct struct element in an array of structs as an argument to my function. Assume the caller already took care of passing me the correct address; I don't have to index it up at all.
I then locally build a struct from some other data. I now want to copy this struct that I built locally to the struct at the location in the array that I received as an argument.
void foo (int *StructArrayAddress)
{
struct
{
int a;
int b;
char c[10];
}myStruct;
a = 5;
b = 10;
c = {1,2,3,4,5,6,7,8,9,10};
//Copy local struct myStruct to location StructArrayAddress here
StructArrayAddress = myStruct; //Something like this but I have the syntax wrong
}
I hope that makes more sense.
EDIT2: I may have just realized something that you guys have been trying to convey to me that I was missing: is a reference to my local struct needed in the argument somehow so that the format of the structure as I pass it back is known?
Your function definition should be like
void foo (myStruct *StructArrayAddress, int index)
{
myStruct x;
x.a = 1;
x.b = 2;
strncpy(x.c, "Test", 9);
/* Now copy this struct to the array of structs at index specified by second argument */
memcpy((StructArrayAddress + index), &x, sizeof(myStruct));
}
Code is as follows:
/* set.h */
struct setElement{
char *element;
setElement *next;
};
typedef struct setElement *Set; //Set is now the equivalent of setElement*
Set a;
setInit(&a);
/* setInit function declaration # setInit.c */
int setInit(Set *a){
(*a)->element = "asdf"; //results in a seg fault
}
Trying to malloc 'a' works, but if I try to access any member within the set 'a' doesn't work. I understand I'm passing a reference of the set from the main() function to setInit, so I believe the pointer contained within setInit is addressing the memory allocated by 'Set a' in the main() function, so a malloc wouldn't be required...
Iunno. Help is appreciated :)
The problem is that you have not allocated the setElement you are trying to assign to. In the main part of the code you are creating a Set, which is just a pointer to a setElement. This pointer is never set to point to anything sensible. I.e. you need something like
Set a = malloc(sizeof(setElement));
Alas, it is unclear where exactly your variables are defined. I assume your main.c is something like
#include "set.h"
Set a;
int main()
{
setInit(&a);
}
If so, your a, which is a pointer by itself, should point to somewhere.
If your framework wants malloc()ed data, you should do
int main()
{
a = malloc(sizeof(*a)); // *a is a struct setElement now, with 2 pointer-sized members.
setInit(&a); // Now seInit should be able to operate on the struct as wanted.
}
As #amaurea has mentioned, you'll need to make use of malloc() for your setElement structure. In addition to this, you need to do the same for the setElement struct's element member. A char* is merely a pointer to a char or char array and will not implicitly allocate anything.
int setInit(Set *a){
(*a)->element = "asdf"; //results in a seg fault
}
Could be re-written
int setInit(Set *a){
(*a)->element = malloc(sizeof("asdf"));
strcpy((*a)->element,"asdf");
}
Which the above could be rewritten to take a second parameter of the actual element contents.
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.
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);
}
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.
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 BOOLs even though they're really just ints:
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
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;