How to allocate memory to pointers - c

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
struct date {
int year;
int month;
int day;
};
struct person{
char name[64];
struct date birthday;
};
struct aop {
int max;
struct person **data;
};
struct aop *create_aop(int max) {
struct aop *new = malloc(sizeof(struct aop));
new->data = malloc(max*sizeof(struct person));
for (int i=0; i<max; i++) {
new->data[i] = NULL;
}
new->max = max;
return new;}
void destroy_aop(struct aop *a) {
free(a->data);
free(a);
}
int add_person(struct aop *a, char *name, struct date birthday) {
if (a->data[a->max-1] != NULL) {
return -1;
}
struct person *new_person = malloc(sizeof(struct person));
strcpy(new_person->name, name);
new_person->birthday = birthday;
for (int i=0; i<a->max; i++) {
if (a->data[i] == NULL) {
a->data[i] = new_person;
break;
}
}
free(new_person);
return 0;
}
I have some questions about the code I wrote. First, do I need to add extra codes into create_aop to initialize name and birthday inside of person? And I found that after the free(new_person) in add_person, I cannot reach a->data[0]->name. How can I change the of a->data[i] without using another pointer?
struct aop *birthdays(const struct aop *a, int month) {
int m = a->max;
struct aop *n = create_aop(m);
int j = 0;
for (int i=0; i<m; i++) {
if (a->data[i] != NULL) {
if (a->data[i]->birthday.month == month) {
n->data[j] = a->data[i];
j++;
}
} else {
break;
}
}
if (j == 0) {
return NULL;
}
return n;
}
Every time I run the function above, there are some errors memory. I have been thinking about it for hours but have no idea what is wrong in this one.

There are two big mistakes in this code. First, the allocation of your data array in struct aop is flawed.
new->data = malloc(max*sizeof(struct person));
You don't want it to point to memory of size max times length of a person struct, do you? Since it is a pointer to pointers, it's size only has to be max times length of a pointer, i.e.
new->data = malloc(max*sizeof(struct person*));
You could also let data directly point to struct person. Then the first line would be correct and you don't have to allocate memory each time you create a new person. Instead, you would just use the memory that data points to:
(aop->data[i]).name = ...
and so on.
Secondly, you are freeing your person struct right after creation.
free(new_person);
Now aop->data[i] is a dangling pointer, because the address it points to could be overwritten any time (because it's not locked by malloc anymore). Instead, you have to free it in your destroy function. It might look something like this:
void destroy_aop(struct aop *a) {
int i;
for(i = 0; i < a->max; i++)
{
if(a->data[i] != NULL) {
free(a->data[i]);
}
}
free(a->data);
free(a);
}

Related

How can I advance in a copy of a linked list without changing the original

So my question is, how can I advance in a copy of a linked list without changing the original list.
I kinda understand why this happens I just don't know a way to make it not happen.
This is what I've done and when I call another function that uses these lists they don't exist.
typedef struct _edgeList
{
int target;
char* tCity;
char* country;
int population;
float weight;
struct _edgeList *next;
} EdgeList;
typedef struct _collisionList
{
int id;
char *city;
char* country;
int population;
EdgeList *edges;
struct _collisionList *next;
} CollList;
void CityWithMostTargets(CollList** hash)
{
CollList** aux = hash;
int i = 0;
int edges = 0;
int major = 0;
char* city;
for(i = 0; i < HASH_SIZE; i++)
{
while(aux[i])
{
if(aux[i]->edges)
{
edges = CountEdges(hash[i]->edges);
}
if(edges > major)
{
major = edges;
city = strdup(hash[i]->city);
}
if(!aux[i]->next)
break;
aux[i] = aux[i]->next;
}
}
aux = hash;
printf("City: %s\nNumber of edges: %d", city, major);
getchar();
}
You can define another variable to hold the value of aux[i] that you want to work with.
for(i = 0; i < HASH_SIZE; i++)
{
CollList* a = aux[i];
while (a)
{
// etc.
and replace the other uses of aux[i] within that loop to use a.

Malloc large space of struct and accessing it like arrays in c

I'm dealing with implementing a hash table. My understanding of a hashtable is that is that to have an array like table where you're able to access the elements quickly by getting the hash value and modding it by the table size. So my initial thought was declaring
Node *hTable [100];
where
typedef struct node {
char *s;
int value;
} Node;
and going to the index of the array and malloc a new element that belongs there. But, the problem is that I need to grow my table.
So, my question is, how would I make a dynamic table, but access it like an array? (e.g table[i]).
I know that you need to call something like
Node *table = (Node*)malloc(sizeof(Node)*size);
which lets you access it like a table table[i] =... but if I did that, I can't declare a new Node in the index of the table
table[i]=(Node*)malloc(sizeof(Node));
Here's a code that I've been testing with (getting seg fault) to better give a view of the problem:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 typedef struct node {
5 int data;
6 struct node *next;
7 } Node;
8
9
10 void main() {
11 Node **list;
12 *list = (Node*)malloc(sizeof(Node)*10);
13 for (int i = 0; i < 10; i++) {
14 list[i] = (Node*)malloc(sizeof(Node)); //problem here?
15 list[i]->data = i;
16 list[i]->next = NULL;
17 }
18 printf("printing...\n");
19 for (int i = 0; i < 10; i++) {
20 printf("%d ", list[i]->data);
21 }
22 }
Your problem is how you allocate space for list. list is uninitialized and does not point to valid memory, you must allocate space for it first, and then allocate space for each element:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} Node;
int main() //return type of main is int
{
Node **list;
list = malloc(10 * sizeof *list); //allocate memory for list not *list, also no need to cast return value of malloc.
for (int i = 0; i < 10; i++)
{
list[i] = malloc(sizeof *list[i]); //allocate space for each element.
list[i]->data = i;
list[i]->next = NULL;
}
printf("printing...\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", list[i]->data);
}
return 0;
}
It doesn't need to be an array of pointers, you can simply make an array of nodes, with:
Node *list = malloc(sizeof *list * count);
Then you can access list[i].s and list[i].value.
When you want to grow the table, you use realloc():
new_list = realloc(list, sizeof *list * new_count);
if (new_list) {
list = new_list;
} else {
// report allocation failure
}
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} Node;
int main() {
// just initialize it this way ( previous was undefined behavior, dereferencing an initialize pointer)
Node **list= malloc(sizeof(Node*)*10);
for (int i = 0; i < 10; i++) {
list[i] = malloc(sizeof(Node*)); //problem here?
list[i]->data = i;
list[i]->next = NULL;
}
printf("printing...\n");
for (int i = 0; i < 10; i++) {
printf("%d ", list[i]->data);
}
}

Can't pass/return a struct pointer successfully

I'm trying to pass a pointer to a struct to a function and then return an edited version of said pointer.
These are the declarations of the structs:
struct HshTble;
typedef struct HshTble *HashTable;
enum EntryStatus { Occupied, Empty, Deleted };
struct HashEntry {
int Element;
enum EntryStatus Info;
};
typedef struct HashEntry Entry;
struct HshTble{
int TableSize;
Entry *Array;
};
So as you can see there is a pointer to a struct within the other struct.
My issue is when it comes to trying to do something with these things... I'll put my code so far, hopefully it's clear what's supposed to be happening but I'll add notes too.
void main(){
HashTable *table;
int size;
table = (HashTable*) malloc (sizeof(HashTable));
table = createTable(table, &size);
In this next bit is where the issues have risen, the idea is I want to edit the values inside table:
HashTable createTable(HashTable table, int *size){
int x, y, ch;
*size = 0;
fopen_s(&fp, DATA_FILENAME, "r");
while (EOF != fscanf_s(fp, DATA_FILENAME, &ch))
{
y = x = f(ch);
++*size;
if (table->Array[x].Info != Occupied)
{
table->Array[x].Element = ch;
table->Array[x].Info = Occupied;
}
else if (table->Array[x].Info == Occupied)
{
while (table->Array[y].Info == Occupied)
{
if (y > HASH_TABLE_SIZE)
{
y = 0;
table->Array[y].Element = ch;
table->Array[y].Info = Occupied;
}
else
{
table->Array[y + 1].Element = ch;
table->Array[y + 1].Info = Occupied;
}
y++;
}
}
return table;
}
}
It doesn't seem to like my function have the type of one of my structures among other things but I feel this is my main issue at the moment. Any help would be great.
Try
void createTable(HashTable &table, int *size){
Just modify the object passed as a parameter. You don't need a return then.
For C do
void createTable(HashTable *table, int *size){

How to write/read data to/from structure array using write/fread?

I have spent quite a lot time attempting to find a solution how to write and read structure to/from file and completely get stuck.
The code should be very simple, but I think I've missed quite important details about fwrite/fread. I think write is working but I am not completely sure. Once I try to read into array I get segmentation fault error on the k=1.
I would be ultimately happy if someone could guide me in what direction should I move further.
#include <stdio.h>
struct Student {
char matrikl[6];
char shortName[6];
int value1;
int value2;
int value3;
int value4;
int money;
}xStudent;
int calcMoney(int,int,int,int);
int main(void)
{
int i=0;
printf("How much students to insert!\n");
scanf("%i",&i);
struct Student S[i];
for (int var = 0; var < i; ++var) {
printf("insert student data\n");
printf("Matriklinumber\n");
scanf("%s", S[var].matrikl);
printf("Student name\n");
scanf("%s", S[var].shortName);
printf("Insert values!\n");
scanf("%i%i%i%i",&S[var].value1,&S[var].value2,&S[var].value3,&S[var].value4);
S[var].money=calcMoney(S[var].value1,S[var].value2,S[var].value3,S[var].value4);;
}
FILE*sourcefile;
sourcefile=fopen("text.txt","ab+");
for (int var = 0; var < i; ++var) {
fwrite(&S[var],sizeof(struct Student),1,sourcefile);
}
fclose(sourcefile);
sourcefile=fopen("text.txt","rb+");
struct Student A[i];
if (sourcefile==NULL) perror ("Error opening file");
else
{
int k=0;
while (fgetc(sourcefile) != EOF) {
fread(&A[k],sizeof(struct Student),1,sourcefile);
k++;
}
}
fclose(sourcefile);
return 0;
}
int calcMoney(int xvalue1, int xvalue2, int xvalue3, int xvalue4)
{
int Sum = xvalue1+xvalue2+xvalue3+xvalue4;
if(Sum==20)
return 100;
else
if(Sum>=16 && Sum<20)
return 75;
else return 0;
}
You have the right idea, but this should fix your problem.
for (int var = 0; var < i; ++var) {
fwrite(&S[i], sizeof(struct Student), 1, sourcefile);
}
The argument 1 in fwrite after the sizeof statement indicates you only want to add one Student at a time.
Please see the doc for fwrite: http://www.cplusplus.com/reference/cstdio/fwrite/
And also:
while (fgetc(sourcefile) != EOF) {
fread(&A[k], sizeof(struct Student), 1, sourcefile);
k++;
}
Please see the doc for fread: http://www.cplusplus.com/reference/cstdio/fread/
I know it's the cplusplus website, but it's the only place I could find good docs on the functions.
Also, the below array initializes to 0 elements:
struct Student A[k];
You may want to try managing a linked list for this instead.
Might end up looking something like:
struct StudentList {
struct Student* student;
struct StudentList* next;
};
struct StudentList* students = NULL;
while(!feof(sourcefile)) {
struct StudentList* newlink = malloc(sizeof(struct StudentList));
newlink->student = malloc(sizeof(struct Student));
newlink->next = NULL;
fread(newlink->student, sizeof(struct Student), 1, sourcefile);
if(NULL != students) {
struct StudentList* iter;
for(iter=students;
NULL != iter->next;
iter = iter->next); // iterate to last link
iter->next = newlink; // add new link to the end
} else students = newlink; // add new link to the beginning
}
Then to free your list, just use something like:
struct StudentList* iter, *head;
for(iter=students;
NULL != iter;)
{
head = iter;
free(iter->student);
free(iter);
iter = head;
}
the error is in the declaration of array A.
struct Student A[k];
k=0; so you are getting error since A[1] or so the array is not defined.
change the declaration to
struct Student A[i];
then it should run if rest of code and syntax is fine.
Fix fwrite line to:
fwrite(&S[i], sizeof(struct Student), 1, sourcefile);

C dynamic array problem

I wrote a piece of code to handle dynamic arrays. Idea was to use array of struct pointers, where the last member of array is NULL. Slight variation of code I wrote is below (using integers and not structures).
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
void list_add(int **list, int* value) {
for(int i = 0; true; i++) {
if(list[i] == NULL) {
list = realloc(list, (i+2) * sizeof(int*));
list[i] = value;
list[i+1] = NULL;
break;
}
}
}
void list_init(int **list) {
int* x;
for(int i = 0; i < 100; i++) {
x = malloc(sizeof(int));
*x = i;
list_add(list, x);
}
}
int main() {
int** l = malloc(sizeof(int*));
l[0] = NULL;
list_init(l);
}
While debugging, I discovered that only first 3 integers are added to the list. I can't seem to figure out why is this happening. Any ideas?
The problem is that the call to realloc() in list_add() potentially frees the memory block *list and allocates another. list_add updates its list pointer, but it does not return the updated pointer to the caller, list_init(); list_init()'s list pointer is potentially a pointer to the recently-freed memory block.
To fix this code, list_add() and list_init() need to be able to "return" the updated list pointer:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
void list_add(int ***p_list, int *value) {
int **list = *p_list;
int i;
for(i = 0; true; i++) {
if(list[i] == NULL) {
list = realloc(list, (i+2) * sizeof(int*));
list[i] = value;
list[i+1] = NULL;
break;
}
}
*p_list = list;
}
void list_init(int ***p_list) {
int **list = *p_list;
int *x;
int i;
for(i = 0; i < 100; i++) {
x = malloc(sizeof(int));
*x = i;
list_add(&list, x);
}
*p_list = list;
}
int main() {
int **list = malloc(sizeof(int*));
list[0] = NULL;
list_init(&list);
int **l = list;
for (; *l != NULL; ++l) {
printf("%d\n", **l);
}
}
http://codepad.org/iGcSaJOR
EDIT
In this case of dynamic arrays the way you have told will not make anything better, the code will complicate only. For each addition of integer you have used realloc trying aggressively to save memory, but this will take more time while execution. Why not allocate a block of memory reserved for the array and to reflect the dynamic character put the array inside a struct with the last index, and when you add something add it on the last location and increment the counter. When this block is filled, you can chain another block to point to another one.
typedef struct _dyna_arr
{
my_type data_arr[MAX_LEN];
int n;
struct _dyna_arr *next block;
};
Therefore you maintain a linked list of multiple arrays. The size of MAX_LEN can be fixed which is appropriate for an application which will help decrease internal fragmentation.
*old answer removed *

Resources