jfa
jfa

Reputation: 1101

Invalid pointer in C

I apologize in advance, but this is kind of a long one.

In my program, I read in the student's information, but when I go to output it, it comes out scrambled, and then gets a pointer error.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct student{
        char *firstName;
        char *lastName;
        char id[10];
        char gender;
        int age;
        double gpa;
};

void main()
{
    int n;
    struct student *classroom;

    printf("How many students?");
    scanf("%d",&n);
    classroom = (struct student*) malloc(n*sizeof(struct student));

    if (classroom == NULL)
    exit(1);

readStudentsInformation(classroom,n);
outputStudents(classroom,n);
printf("The average age is %.2f.\n",averageAge(classroom,n));
printf("The average GPA is %.2f.\n",averageGpa(classroom,n));
sortByLastName(classroom,n);
outputStudents(classroom,n);
sortByID(classroom,n);
outputStudents(classroom,n);
sortByAge(classroom,n);
}

void outputStudents(struct student classroom[], int size)
{

    int i;
    for (i = 0; i < size; i++)
    {
        printf("%15s",classroom[i].firstName);
        printf("%15s:",classroom[i].lastName);
        printf("%14s,",classroom[i].id);
        printf("%3c",classroom[i].gender);
        printf("%5d",classroom[i].age);
        printf("%5.2f",classroom[i].gpa);
    }
}

Input: How many students?2 First Name?Thom Last Name?Arron ID?2 Gender?M Age?26 GPA?3.9 First Name?Frank Last Name?Roberts ID?1 Gender?F Age?24 GPA?3.4'

Output:

    Roberts        Roberts:             2,  M   26 3.90                              :             1,  F   24 3.40The average age is 25.00.

The average GPA is 3.65. * glibc detected * ./lab12: munmap_chunk(): invalid pointer: 0x00007fff30319a90 *

                       :             2,  M   26 3.90Aborted (core dumped)

The full code is here, but I didn't want to copy 200 lines to stack overflow: http://codepad.org/LYpS6t5z

Any idea what would cause this?

Upvotes: 0

Views: 545

Answers (3)

amdixon
amdixon

Reputation: 3833

Weirdness happening in readStudentsInformation, in particular lines like

classroom[i].lastName = temp;

are causing issues later on when you try to free this memory with

free(classroom[i].firstName);

Appropriate memory handling below:

void readStudentsInformation(struct student classroom[], int size)
{
  int i;
  char temp[50];

  for (i = 0; i < size; i++)
  {
    printf("First Name?");
    scanf("%s",temp);
    classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
    if (classroom[i].firstName == NULL)
      exit(1);
    /* after mallocing good memory can write in the data.. */
    strcpy(classroom[i].firstName, temp);
/*    classroom[i].firstName = temp; */
    printf("Last Name?");
    scanf("%s",temp);
    classroom[i].lastName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
    if (classroom[i].lastName == NULL)
      exit(1);
/*    classroom[i].lastName = temp; */
    strcpy(classroom[i].lastName, temp);
    printf("ID?");
    scanf("%s",classroom[i].id);
    fflush(stdin);
    __fpurge(stdin);
    printf("Gender?");
    scanf("%c",&classroom[i].gender);
    printf("Age?");
    scanf("%d",&classroom[i].age);
    printf("GPA?");
    scanf("%lf",&classroom[i].gpa);
  }
}

Upvotes: 1

Charlie Burns
Charlie Burns

Reputation: 7044

This is one conceptual error, you have it in a couple of places

classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
     exit(1);
classroom[i].firstName = temp;

What you want here instead is

classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
     exit(1);
strcpy(classroom[i].firstName, temp); // note this

Or, cleaned up a bit:

classroom[i].firstName = malloc(1+strlen(temp)); // note clean up here
if (classroom[i].firstName == NULL)
     exit(1);
strcpy(classroom[i].firstName, temp);

Or even just

classroom[i].firstName = strdup(temp); // this takes place of all the lines above

These errors explain why your free's are failing.

Nothing else jumps out at me.

Upvotes: 1

Kevin
Kevin

Reputation: 56059

classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
    exit(1);
classroom[i].firstName = temp;

Your second assignment here overwrites the address, leaking the mallocd memory and making the pointer invalid as soon as that for iteration finishes. The same buffer is reused (with the same error) for lastName, which is why you see Roberts Roberts instead of the actual first and last name. When you go to free them, they are (1) invalid and (2) not made by malloc, so you get the crash you see.

Just like other arrays, you can't copy them by assignment, you have to copy byte-by-byte:

size_t len = strlen(temp);
classroom[i].firstName = malloc(1+len);
if (classroom[i].firstName == NULL)
    exit(1);
strncpy(classroom[i].firstname, temp, len);
classroom[i].firstname[len] = '\0';

And don't cast the result of malloc.

Upvotes: 1

Related Questions