-2

I have two structs and I have an array of 30 pointer StudentType. I have a problem with malloc(). When I compile it it's ok. But when I try to debug it, it shows "Segmentation Fault" in Dev c++.

In Eclipse, it shows up anything on console. I think that my mistakes are on these lines of code:

students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));

That's a part of my code.

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

typedef struct{
    float firstAssignment;
    float secondAssignment;
    float midterm;
    float final;
    float finalMark;
}StudentRecordType;

typedef struct{
    char *firstName;
    char *lastName;
    int idNumber;
    StudentRecordType marks;
}StudentType;
StudentType *students[30];
char firstName[30];
char lastName[30];

int ReadFromFile();
int PrintAll();
int NumOfStudents;
int i;

int main(void)
{
    ReadFromFile();
}

int ReadFromFile()
{
    FILE *fp;
    fp=fopen("project2-askhsh2.dat","r");
    if(fp==NULL)
    {
        printf("Error opening file.\n");
    }
    else
    {
        printf("Successful open of project2-askhsh2.dat\n");
    }
    fscanf(fp,"%d",&NumOfStudents);
    printf("%d\n",NumOfStudents);
    students[0]=(StudentType *)malloc(sizeof(StudentType)*NumOfStudents);
    (*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
    (*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));

    for(i=0;i<NumOfStudents;i++)
    {
        (*students[i]).idNumber=i;
        fscanf(fp,"%s %s", (*students[i]).firstName,(*students[i]).lastName);
        fscanf(fp,"%f %f %f %f",(*students[i]).marks.firstAssignment,(*students[i]).marks.secondAssignment,(*students[i]).marks.midterm,(*students[i]).marks.final);
        printf("%s",(*students[i]).firstName);//, students[i].lastName);
    }

}
Blastfurnace
  • 18,411
  • 56
  • 55
  • 70

4 Answers4

3

(*students[NumOfStudents]).firstName=(char)malloc(sizeof(char[30]));

First, the cast is just plain wrong. Casting to char loses information.
Second, in C don't cast the return value from malloc(). It is, at best, redundant, and may hide an error the compiler would have caught without the cast.

If you're going to cast anyway, cast to char*.

pmg
  • 106,608
  • 13
  • 126
  • 198
  • 2
    And the index [NumOfStudents] is one beyond the end of the array. – wildplasser Feb 04 '12 at 12:59
  • I get these errors when i try (students[NumOfStudents]).firstName=(char)malloc(sizeof(char[30])); request for member `firstName' in something not a structure or union [Warning] cast from pointer to integer of different size –  Feb 04 '12 at 13:02
  • `a->b` is a shorthand for `(*a).b`. – krlmlr Feb 04 '12 at 13:02
  • I had a copy/paste error ... `students[WHATEVER]` is a pointer, not a `StudentType`. You need to use `students[WHATEVER]->firstname` or `(*students[WHATEVER]).firstname`. – pmg Feb 04 '12 at 13:04
  • Initialize each `firstName` and `lastName` member for each `Student`; do `->firstName = ...` in the loop. – krlmlr Feb 04 '12 at 13:04
  • @user946850 I know that but I dont think thats the problem –  Feb 04 '12 at 13:05
  • It's not yet the problem, but it will become one when you fix according to @pmg's suggestions. – krlmlr Feb 04 '12 at 13:07
2

You seem to have an extra level of pointers that you don't need causing some confusion, when using the students pointer. You also access past the end of the array that you've allocated.

So instead of

StudentType *students[30];

Which gives you an array of 30 pointers to StudentType I guess you probably just wanted:

StudentType *students;

Which is just a plain pointer to StudentType and can be used as the base of your dynamically allocated array. Then when you do the allocations you'd do this:

students = malloc(sizeof(*students) * NumOfStudents);

And you'd have to initialise each of those StudentTypes before you use them.

for(i=0;i<NumOfStudents;i++)
{
    students[i].firstname = malloc(30);
    students[i].lastname = malloc(30);
}

Notice that each StudentType is now accessed directly as an element from the students array as student[i], rather than the *students[i] which you had that was wrong. You can expand this to the rest of your code. Remember that you can only access from index 0 to NumOfStudents-1, so do not use students[NumOfStudents].

The other problem you will have is that when you use fscanf() you need to pass the address of the variable to store the result in using the ampersand operator. Currently you are only passing the value, e.g. you should use &students[i].marks.firstAssignment instead of (*students[i]).marks.firstAssignment, assuming you also fix the pointer errors.

tinman
  • 6,348
  • 1
  • 30
  • 43
  • In this project it must exist "30 indicators in vector-type structures StudentType."(google translate) So i think the `StudentType *students[30];` should remain as it is. Can you help me now? –  Feb 04 '12 at 13:15
  • @Buxme: You should un-select my answer as the accepted one and choose [wildplasser's answer](http://stackoverflow.com/a/9141078/583044) as the accepted one. If I edit my answer it would become just a duplicate of what he already wrote. – tinman Feb 04 '12 at 15:41
1

These two statements are wrong:

(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));
(*students[NumOfStudents]).lastName=(char*)malloc(sizeof(char[30]));

C-arrays are zero-indexed, and so you are trying to dereference one past the size of the array. Assuming that you want to set the first and last name of the last element of students[], then you need to dereference index NumOfStudents - 1.

You don't need to cast the result of malloc() to char * (assuming you are writing a C application).

The sizeof(char) is 1, and so you just need to write malloc(30).

Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
0
(*students[NumOfStudents]).firstName=(char*)malloc(sizeof(char[30]));

I think you meant:

students[some_index]->firstName = malloc(30);

With some_index something below NumOfStudents.

So your loop becomes:

for(i=0; i < NumOfStudents ; i++)
    {
        /* students[] is an array of pointers
        ** students[i] is a pointer
        */
        students[ i ] = malloc(sizeof *students[ i ]);
        students[ i ]->idNumber=i;

        students[ i ]->firstName = malloc(30);
        students[ i ]->lastName= malloc(30);

        fscanf(fp,"%s %s"
            , students[i]->firstName
            , students[i]->lastName
            );
        fscanf(fp,"%f %f %f %f"
            , &students[i]->marks.firstAssignment
            , &students[i]->marks.secondAssignment
            , &students[i]->marks.midterm
            , &students[i]->marks.final
            );
        printf("%s",students[i]->firstName);//, students[i].lastName);
    }

And using a global index named "i" can be considered bad style.

wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • where 'some _index' is I enter the size of the array, in my case 30? –  Feb 04 '12 at 13:11
  • Yes. You could also allocate the students array via malloc(). The global array then needs to be a pointer to pointer to Student_type. And you lose the arbitrary constant size 30. Two more to go ... – wildplasser Feb 04 '12 at 13:18
  • Correction: no. It is an index, not the_number_of_elements. Being an index it may *never* be greater_then_or_equal_to the number of elements. – wildplasser Feb 04 '12 at 13:27