-1

I have this code and after the first write in the array(successful data write ) then we get null as message and I don't know why. I have tried many things, please help me. my code is:

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

struct course {
int marks;
char *subject;
};



int main(int argc, char *argv[])
{
    struct course *ptr;
    int i, noOfRecords;

    printf("Enter the number of records: ");
    scanf("%d", &noOfRecords);

    //Memory allocation for noOfRecords structures
    ptr = (struct course *)malloc(noOfRecords * sizeof(struct course));
    ptr->subject=(char*)malloc(20*sizeof(char));

    for (i = 0; i < noOfRecords; ++i) {
        printf("Enter the name of the subject and marks respectively:\n");
        scanf("%s %d", (ptr + i)->subject, &(ptr + i)->marks);
    }

    printf("Displaying Information:\n");
    for (i = 0; i < noOfRecords; ++i){
       printf("%s\t%d\n", (ptr + i)->subject, (ptr + i)->marks);

    }
      return 0;
}
  • 5
    `ptr->subject=(char*)malloc(20*sizeof(char));` only allocates memory for the member of the *first* `struct` element in the array. You need to do that inside the loop, for every element. – Weather Vane Nov 07 '20 at 13:36
  • OT: regarding: `int main(int argc, char *argv[])` Since those parameters are not used, the compiler outputs two warning messages about unused parameters. This can be fixed by either using the alternate valid signature for `main()` `int main( void )` or the first couple of statements in the body of `main` be: `(void)argc;` and `(void)argv;` – user3629249 Nov 07 '20 at 19:31
  • OT: regarding statements like: `ptr = (struct course *)malloc(noOfRecords * sizeof(struct course));` and `ptr->subject=(char*)malloc(20*sizeof(char));` 1) the returned type is `void*` which can be assigned to any pointer. Casting just clutters the code (and is error prone) 2) always check (!=NULL) the returned value to assure the operation was successful. If not successful (==NULL) then call `perror( "malloc for ... failed" ) to output to `stderr` both your error message and the text reason the system thinks the error occurred – user3629249 Nov 07 '20 at 19:35
  • OT: regarding: `scanf("%d", &noOfRecords);` when calling any of the `scanf()` family of functions, always check the returned value (not the parameter values) to assure the operation was successful. Note: those functions return the number of successful 'input format conversion specifers' (or EOF). Suggest: `if( scanf("%d", &noOfRecords) != 1 ) { fprintf( stderr, "scanf for number of records failed\n" );` This is not recoverable with the current code logic, so the next statement should be: `exit( EXIT_FAILURE );` – user3629249 Nov 07 '20 at 19:37
  • @MariaXentoulis You should pick an answer as correct... – emi Nov 29 '20 at 10:06

1 Answers1

0

As stated in question comments, you need to allocate memory for ALL subject members, not just the first:

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

struct course {
    int marks;
    char *subject;
};

int main(int argc, char *argv[])
{
    struct course *ptr;
    int i, noOfRecords;

    printf("Enter the number of records: "); 
    scanf("%d", &noOfRecords);

    //Memory allocation for noOfRecords structures
    ptr = (struct course *)malloc(noOfRecords * sizeof(struct course));

    for (i = 0; i < noOfRecords; ++i) {
        printf("Enter the name of the subject and marks respectively:\n");
        (ptr + i)->subject = (char*) malloc(20*sizeof(char));
        scanf("%s %d", (ptr + i)->subject, &((ptr + i)->marks));
    }

    printf("Displaying Information:\n");
    for (i = 0; i < noOfRecords; ++i) {
       printf("%s\t%d\n", (ptr + i)->subject, (ptr + i)->marks);
    }

    return 0;
}

Also, I suggest you to:

  • Use a #define for subject max length
  • Always check user input or limit it (truncate or force to retype). You might get unexpected behaviors if user inserts more than 19 chars plus \0 for subject.
  • Use typedef struct {...} course;. It will be much easier to handle arrays.
  • Remember to free the memory you claimed.

As a result:

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

// From https://stackoverflow.com/a/17387990/2928168
#define MAX_SUBJECT "20"

typedef struct {
    int marks;
    char *subject;
} Course;

int main(int argc, char *argv[])
{
    Course *courses;
    int i, noOfRecords;

    printf("Enter the number of records: "); 
    scanf("%d", &noOfRecords);

    // Memory allocation for noOfRecords structures
    courses = (Course *) malloc(noOfRecords * sizeof(Course));

    for (i = 0; i < noOfRecords; ++i) {
        printf("Enter the name of the subject and marks respectively:\n");
        courses[i].subject = (char*) malloc(atoi(MAX_SUBJECT)*sizeof(char));
        scanf("%" MAX_SUBJECT "s %d", courses[i].subject, &(courses[i].marks));
        //fgets(courses[i].subject, sizeof(buf), stdin);
    }

    printf("Displaying Information:\n");
    for (i = 0; i < noOfRecords; ++i) {
       printf("%s\t%d\n", courses[i].subject, courses[i].marks);
       free(courses[i].subject);
    }

    free(courses);

    return 0;
}

Edit

You can even use the trick from https://stackoverflow.com/a/6671729/2928168 to increase performance:

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

#define MAX_SUBJECT 20
#define Q(x) #x
#define QUOTE(x) Q(x)
#define MAX_SUBJECT_STR QUOTE(MAX_SUBJECT)

typedef struct {
    int marks;
    char *subject;
} Course;

int main(int argc, char *argv[])
{
    Course *courses;
    int i, noOfRecords;

    printf("Enter the number of records: "); 
    scanf("%d", &noOfRecords);

    // Memory allocation for noOfRecords structures
    courses = (Course *) malloc(noOfRecords * sizeof(Course));

    for (i = 0; i < noOfRecords; ++i) {
        printf("Enter the name of the subject and marks respectively:\n");
        courses[i].subject = (char*) malloc(MAX_SUBJECT*sizeof(char));
        scanf("%" MAX_SUBJECT_STR "s %d", courses[i].subject, &(courses[i].marks));
        //fgets(courses[i].subject, sizeof(buf), stdin);
    }

    printf("Displaying Information:\n");
    for (i = 0; i < noOfRecords; ++i) {
       printf("%s\t%d\n", courses[i].subject, courses[i].marks);
       free(courses[i].subject);
    }

    free(courses);

    return 0;
}
emi
  • 2,786
  • 1
  • 16
  • 24