Malloc'ing a double pointer structure inside a struct? - c

C noob here. I'm trying to initialize a simple struct as follows:
typedef struct person_s {
char *fname; ///< first name of the person
char *lname; ///< last name of the person
char *handle; ///< handle of the person
struct person_s **friends; ///< dynamic collection of friends
size_t friend_count; ///< current number of friends
size_t max_friends; ///< current limit on friends
} person_t;
I think I understand using malloc for every single member in this struct, except for the double pointer friends struct in it. How do I allocate memory for this double pointer?
Here's my malloc for the other data members:
person_t *newperson(char *fn, char *ln, char *han){
person_t *p = NULL;
p = malloc(sizeof(person_t));
p->fname = malloc(strlen(fn) +1);
strcpy(p->fname, fn);
p->lname = malloc(strlen(ln) +1);
strcpy(p->lname, ln);
p->handle = malloc(strlen(han) +1);
strcpy(p->handle, han);
p->*friends = malloc(sizeof(*friends));
p->friend_count = malloc(2*sizeof(friend_count));
p->friend_count = 0;
p->max_friends = malloc(2*sizeof(max_friends));
p->friend_count = 0;
}
Edit: my bad, I forgot to include that this is inside a function that initializes this struct.
Edit1: In response to the comments, what I'm trying to achieve here is to make a dynamic "array" of friends that is pointed by the p->friends data member. Additionally, I have a dynamic hash table, would it be a good idea to use it as a collection for putting all the friends linked to this person? The concept of pointers and dynamic allocation is still somewhat confusing to me so sorry for misunderstanding.

Single pointer is enough for dynamic collection:
struct person_s *friends;
...
p->friends = malloc(max_friends * sizeof(struct person_s));

First of all keep the syntax simple, let us assume you have typedefed struct person_s as person.
A pointer to pointer is the same thing as a pointer to an array of pointers.
So, first you need to allocate the array, then you need to allocate individual elements within the array.
This will allocate the array:
friends = malloc(max_friends * sizeof(*friends));
This works, because friends is of type **person, so *friends must be of type *person.
Then, you will need a for loop in which you allocate each person:
friends[i] = malloc(sizeof(**friends)); //or sizeof(person), same thing.
(I typed the above immediately after the question was posted, only to find out that the question was closed before I had the chance to answer. Then later the question was opened, but I was never notified. I am posting it because I would hate to just throw it away now.)

Related

How can I access items in a dynamically allocated array of structs?

I'm in a class right now that works with C and one of my assignments requires that I work with a struct that my professor wrote for us. It's actually two structs, with one struct basically containing an array of the first struct.
Here's what they look like:
typedef struct cityStruct
{
unsigned int zip;
char *town
} city;
typedef struct zipTownsStruct
{
int *towns;
city **zips;
city *cities
} zipTowns;
And here's my function for allocating memory for the zipTowns structure:
void getArrs(zipTowns *arrs, int size)
{
arrs->towns = malloc(sizeof(int) * size);
arrs->zips = malloc(sizeof(city **) * size);
arrs->cities = malloc(sizeof(city *) * size);
}
From what I understand, what I'm doing here is allocating space in memory for a certain number of ints, city pointers, and city structures, based on the size variable. I understand that this is basically what an array is.
I'm having trouble with understanding how I can access these arrays and manipulate items in it. Writing this gives me an error:
strcpy(arrs.cities[0]->town, "testTown\0");
You can see what I'm trying to do here. I want to access each "City" in the zipTowns struct by index and insert a value.
How can I access the items in these dynamically allocated array of structures?
Think of x->y as (*x).y.
arrs is not a structure, it's a pointer to a structure, and cities is not a pointer to a pointer to a structure, it's just a pointer to a structure.
Use arrs->cities[0].town instead of arrs.cities[0]->town.
However, you're still not allocating enough room for these structures. This should make it clearer what you're doing with the allocations, and should also give you enough room for your data:
arrs->towns = malloc(sizeof(*arrs->towns) * size);
arrs->zips = malloc(sizeof(*arrs->zips) * size);
arrs->cities = malloc(sizeof(*arrs->cities) * size);
With the second and third, you were only allocating enough room for a pointer to be stored instead of the actual data type.
With this approach, you will be able to access from arrs->cities[0] to arrs->cities[9] and you also will be able to access the members of each city by doing arrs->cities[<number>].<member>.
You also do not need to intentionally null-terminate your strings. This is already done for you. Therefore, you can replace "testTown\0" with "testTown".

Subscripted value is neither array nor pointer nor vector at array index

(Homework question)
I'm just learning C, and I'm making a program that reads data from a file, creates routers of that data, and puts pointers to the routers in an array of size 255, but I keep getting the title error on the line where I'm trying to add them to the array
#define ARRAY_SIZE 255
struct router routers[ARRAY_SIZE] = {0};
int main(int argc, char *argv[]){
unsigned char id;
char name[32];
struct router *new_router;
if(argc == 2){
//reads file with fread
//setting id and name which prints out as expected
new_router = make_router(id, name); //initialising method that returns a router pointer
routers[new_router->id] = new_router;
//error occurs here, at [new_router->id]. Have also tried just using id
}
}
I've searched a lot of threads with the same error message, but they're all either someone who didn't declare an array, or were suggested to try it with unsigned char as index number, which is what I'm already using. Would love some insight into this.
struct router{
unsigned char id;
char name[32];
}
struct router* make_router(unsigned char id, char* name){
struct router *r = malloc(sizeof(struct router));
r->id = id;
r->name = name;
return r;
}
Assuming make_router allocates a struct dynamically, then
routers[new_router->id] = *new_router; // note *
solves the compiler error.
However, you cannot copy structs like this if they have pointer members. You say that "Router is just a basic struct with an unsigned char for id, and a char* for name" so this is the case. But with an assignment like this, you won't get a hard copy of the pointed-at data.
Pointers are not data. They do not contain data. They point at data allocated elsewhere.
So probably what you are actually looking for is an array of pointers, as suggested in another answer. If so, you have to re-write this program.
This:
struct router routers[ARRAY_SIZE] = {0};
means routers is an array of ARRAY_SIZE structures. Not pointers to structures, which is what this:
routers[new_router->id] = new_router;
is trying to assign into one of the elements.
If make_router() is dynamically allocating the memory, the fix is probably to change the array declaration into an array of pointers:
struct router * routers[ARRAY_SIZE];
^
|
way
important
EDIT: Of course, I assumed that there was an actual declaration of struct router somewhere that you just omitted. Might be a good idea to include it, just for completeness' sake.

Expand an array with realloc inside of a function - Pointers?

I'm sure that the answer to this is me not understanding Pointers and References properly!
So at the start of my C file I define a struct for people:
typedef struct {
char id[4];
int age;
char name[128];
} people;
Then inside of main() I create an array of 10 people structs called record.
people* record = (people*)malloc(sizeof(people)* 10);
In main() we start and then dive off into a function with
MyFunction(record);
(This function is prototyped at the beginning of the C file before main() with
int MyFunction(people *record);
Inside of MyFunction() we do various stuff, including wanting to increase the record array size so that it can hold more people structs.
I'm attempting to increase the record array size with
struct people *tmp = realloc(record, 20 * sizeof (people));
if (tmp)
{
record = tmp;
}
But this doesn't work and I get memory corruption if I attempt to use the newly added structs in the array.
As I said, I'm sure that this is due to me not understating Pointers and References properly.
Note that I can't have MyFunction() give an expanded record array as its return type because I'm already using its return int for something else (and I'm not sure I'd get that to work properly either!) - I need it to be using the main record array.
Can anyone point me in the right direction please?
int MyFunction(people **record);// MyFunction(&record);//call at main
...
struct people *tmp = realloc(*record, 20 * sizeof (people));
if (tmp)
{
*record = tmp;
}

dynamically allocate memory for pointer to array of structure

hi i have this structure
typedef struct STUDENT
{
char studName[20];
int timeEnter;
int timeUpdate;
}STUDENT;
and the local pointer to array of structure
STUDENT *studArr[100];
I'm trying to allocate memory for the structure by doing reading in the first line of the file then use it to allocate memory for the structure.
fscanf(fp, "%s", &first);
**studArr = (STUDENT**) malloc(sizeof(STUDENT*)*first);
I got an error saying that no operator "=" matches these operands on the allocation line
why am I gettting the error, what did i do wrong here?
thank in advance
I think you're confusing things, it looks like you're declaring an array of pointers, when all you need is a single pointer. Note that as long as you're indexing properly, a pointer to "one" struct is the same as a pointer to a hundred.
You should probably have:
STUDENT *studArr;
then, once you know how many you need (I'm assuming first is the number of students to allocate room for):
studArr = malloc(first * sizeof *studArr);
Also note that no casting is needed.
If you want to allocate an array of 100 students, you have two choices:
struct STUDENT
{
char studName[20];
int timeEnter;
int timeUpdate;
};
struct STUDENT studArr1[100];
... OR ...
struct STUDENT *studArr2 = (struct STUDENT *)malloc (sizeof (struct STUDENT) * 100);
If you just want a pointer, you can say:
struct STUDENT *p = studArr1;
PS:
I deliberately left the "typedef" stuff out so as not to confuse the basic issue (struct vs. array of struct vs pointer to array of struct).
You have defined an array of pointers to struct, not a pointer to an array of struct. The memory for the array is already allocated, as a global array.
The type of **studArr is STUDENT, and hence is not compatible with the expression to the right of the assignment operator, which is casted to (STUDENT**).
You probably meant:
STUDENT **studArr;
[...]
fscanf(fp, "%s", &first);
studArr = (STUDENT**) malloc(sizeof(STUDENT*)*first);
As you are using STUDENT *studArr[100]; then it means you have allocated the memory for 100 pointers for STUDENT structure type.
so for allocating the memory you should try.
studArr =malloc(sizeof(struct STUDENT)*first);
then you can access all the allocated members as studArr[i] ....so on.
You're not exactly clear on what your overall goal is.
First of all, you want to use %d if you want to read in an integer:
int count;
if (fscanf(fp, "%d", &count) != 1) { // error... }
Next, don't use STUDENT as both the struct name and the typdef. Just leave the struct name out:
typedef struct
{
char studName[20];
int timeEnter;
int timeUpdate;
} student_t;
Now, you're going to want just a pointer to an array of student_ts:
student_t* student_array = NULL;
Finally, allocate that array:
student_array = malloc(count * sizeof(student_t));
Now you can use it, like:
strncpy(student_array[0].studName, "Bobby", 20);
Or get a pointer to an individual student:
student_t* bob = &student_array[1];
bob->timeEnter = 42;

Dynamic memory allocation for an array and an array of structures within a struct

I am a newbie in C..I am trying to make some sense of how dynamic memory allocation works in case of structures and arrays..So like for example I have a code like..
struct Person
{
int id;
char *name;
char *place;
};
struct Database
{
struct Person *data_rows;
};
I want to dynamically allocate memory for both the character arrays name and place..and the array of struct data_rows..take their size as input..So what should ideally be the order of allocations and the proper syntax for the same? Thanks.
Well, "obviously" you need to get "struct Database" filled in first:
struct Database MyDatabase;
MyDatabase.data_rows=malloc(sizeof(MyDatabase.data_rows[0])*NumberOfPeople);
Ignoring the fact that I didn't check the malloc() for failure, this will give you an array of "struct Person", all uninitialized. So, most likely, you'll want to initialize them:
int i;
for (i=0; i<NumberOfPeople; i++)
{
struct Person* MyPerson;
MyPerson=&MyDatabase.data_rows[i];
MyPerson->id=i;
MyPerson->name=malloc(...);
/* Do something to store the name in MyPerson->name */
MyPerson->place=malloc(...);
/* Do something to store the place in MyPerson->name */
}
Now, the problem here is the "..." I put on the malloc. It's easy if you use a fixed size, but then you could have just declared your struct to be something like
struct Person
{
int id;
char name[100];
char place[200];
};
Basically, I just can't tell what the length of the names should be, hence I just typed it as "...".
Also, I just guessed what the "id" might be. Using the array index is actually somewhat pointless :-)
Of course, you don't have to do it all now. You could just set the name and place pointers to NULL and fill them in later, like when you're reading the data from a file, or whatever you're planning to do. Or you could just not initialize it here at all, if you're confident that your code always "knows" which fields are initialized and which ones are not.
I would highly recommend to write a functions person_new and person_free that would take care of structure memory management:
struct Person* person_new(char *name, char* place) {
struct Person* person = malloc(sizeof(struct Person));
person->name = strdup(name);
person->place = strdup(place);
return person;
}
void person_free(struct Person* person) {
free(person->name);
free(person->place);
free(person);
}
The best thing would be to convert your structs to classes, the following works also for structs...
You define a constructor and destructor in Database and in Person as following:
struct Person
{
Person(){
name = new char[256];
place = new char[256];
};
~Person(){
delete name;
delete place;
}
int id;
char *name;
char *place;
};
struct Database
{
Database(int nPersons){
data_rows = new Person[nPersons];
};
~Database(){
delete data_rows;
};
struct Person *data_rows;
};
or you can do this without a constructor and destructor and allocate all the stuff sequentially in your code, which is a very ugly way to do this!
as:
Database myData;
myData.data_rows = new Persons[40];
for(int i=0; i < 40; i++){
myData.data_rows[i].name = new char[256];
myData.data_rows[i].place = new char[256];
}
Note that data_rows[i] is nothing more than -> *(data_rows + i) which shifts the address of the pointer i times and then dereferences it!

Resources