Karampistis Dimitrios
Karampistis Dimitrios

Reputation: 99

Pure C - Passing the reference of a pointer of a struct

I have created a program that is loading a database with student information from the keyboard, after that I am trying to create an option to add a new registration of a student to that database

the struct consists of

typedef struct {
    long unsigned int aem;
    char name[64];
    short unsigned int lessonsToPass;
} Registration;

I have created a pointer of it on the main function

int i, sizeOfDatabase;
Registration *database
scanf("%d", &sizeOfDatabase);
database = (Registration*) malloc(sizeOfDatabase * sizeof(Registration));
for(i = 0; i < sizeOfDatabase; ++i){
    scanf("%lu%63s%hu", &(database+i)->aem, (database+i)->name, &(database+i)->lessonsToPass);
    for(tmp = (database+i)->name; (*tmp=toupper(*tmp)); ++tmp);
}

So basically I am getting the database from the keyboard and making the name to uppercase

after that I am calling a function to add a new registration

void add(char *aem, char *name, char *lessonsToPass, int currentDatabaseSize, Registration **database){
    char *tmp;
    int newSize = currentDatabaseSize + 1;
    *database = (Registration*) realloc(*database, newSize * sizeof(Registration));
    for(tmp = name; (*tmp=toupper(*tmp)); ++tmp);
    (*database + newSize)->aem = atoi(aem);
    strcpy((*database + newSize)->name, name);
    (*database + newSize)->lessonsToPass = atoi(lessonsToPass);
}

the char *name is never bigger than 64 and I am still getting compilation error malloc(): corrupted top size

What am I missing?

Upvotes: 1

Views: 102

Answers (2)

Gene
Gene

Reputation: 46970

You've chosen some unusual idioms to represent what you're trying to do. Here's code that's more understandable and fixes the problem. Note I'm assuming you have a modern C compiler. The style of your code is C89. That's 1989. If it's an option, you should be using newer C language features.

First make a string uppercase method to prevent duplicate code:

void strtoupper(char *s) {
  for (char *p = s; *p; ++p) *p = toupper(*p);
}

Now the rest:

int sizeOfDatabase;
Registration *database;

scanf("%d", &sizeOfDatabase);
database = malloc(sizeOfDatabase * sizeof *database); // NO CAST HERE!
for (int i = 0; i < sizeOfDatabase; ++i){
  Registration *r = database + i;
  scanf("%lu%63s%hu", &r->aem, r->name, &r->lessonsToPass);
  strtouper(r->name);
}

You should pass a pointer to the database size so the add method can update it. While calling realloc the way you do is correct, it's inefficient because every call requires time proportional to the entire database size. If it ever got big, you'd regret this. But that's a fine point we'll ignore.

void add(char *aem, char *name, char *lessonsToPass,
  Registration **database, int *dbSize) {
  int i = (*dbSize)++; // Increase db size by 1 and get new element's index.
  Registration *db = *database = realloc(*database, *dbSize * sizeof **database);
  Registration *r = db + i;
  strcpy(r->name, name);  // DON'T MODIFY THE INPUT.
  strtoupper(r->name);
  r->aem = atoi(aem);
  r->lessonsToPass = atoi(lessonsToPass);
}

I hope this makes sense.

Upvotes: 0

Joshua
Joshua

Reputation: 43298

(*database + newSize)->aem = atoi(aem);

Just wrote off the allocated block because newSize contains the number of allocated records including the one being created now. Correct code:

(*database + newSize - 1)->aem = atoi(aem);
strcpy((*database + newSize - 1)->name, name);
(*database + newSize - 1)->lessonsToPass = atoi(lessonsToPass);

Upvotes: 2

Related Questions