Search code examples
arrayscfunctionpointersstructure

How to return structure value?


I'm trying to return the values and print them into the a file...I declared the structure and read the file get the values and save them to the pointer, but I couldn't manage to return them to function...

Can you please help me with that? I could only return one variable and then it gives me (null) and I can't return the other variables like .age .efternamn.

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10000
int elever = 1;

struct likaprogramms {
  char civilekonom[50];
  char högskoleingenjör[50];
  char civilingenjör[50];
  char systemutvecklare[50];
};

struct student {
  char personnummer[32];
  char förnamn[32];
  char efternamn[32];
  char gender[32];
  char programmdife[32];
  char age[32];
  char email[32];
  struct likaprogramms *likaprogramm;
};

struct student *personer;

struct programms {
  char namnen;
  char mcode;
  char responsible;
  char email;
};

void (*display[5])();

void* base(char *display[5]) {
  //char fileA[MAX];
  char tal;
  int columns;
  FILE *f;
  f = fopen("elever.txt", "r");
  personer = (struct student*) malloc(elever * sizeof(struct student));
  personer->likaprogramm = malloc(sizeof(struct likaprogramms) * elever);
  display = malloc(sizeof *display);
  for (elever = 0; !feof(f);) {
    tal = fgetc(f);
    if (tal == '\n')
      printf("\n");
    {
      elever++;
      columns = 0;
      if (tal == ' ') {
        columns++;
      }

      if (columns == 0) {
        fscanf(f, " %s", &personer[elever].personnummer);
        //printf("%s",personer[elever].personnummer);
        // return (personer[elever].personnummer);  
        //columns++;                       
      }
      columns++;
      if (columns == 1) {
        fscanf(f, " %s", &personer[elever].förnamn);
        //  return (personer[elever].förnamn); 
      }
      columns++;
      if (columns == 2) {
        fscanf(f, " %s", &personer[elever].efternamn);
        //return (personer[elever].efternamn);                      
      }
      columns++;
      if (columns == 3) {
        fscanf(f, " %s", &personer[elever].gender);
        // return( personer[elever].gender);
      }
      columns++;
      if (columns == 4) {
        fscanf(f, " %s ", &personer[elever].programmdife);
        // return( personer[elever].programmdife);
      }
      columns++;
      if (columns == 5) {
        fscanf(f, " %s", &personer[elever].age);
        // return(personer[elever].age);
      }
      columns++;
      if (columns == 6) {
        fscanf(f, " %s", &personer[elever].email);
        // return(personer[elever].email);                   
      }
      return &personer[elever];
    }
    //free(personer);
  }
  // return 0;
  //fclose("elever.txt");     
}

int i;
int main() {
  display[i] = base(*display[i]);

  FILE *h;
  h = fopen("Filedatabase.txt", "w");
  if (h == NULL) {
    printf("Could not write the file!\n");
    exit(1);
  } else {
    for (int i = 0; i < 7;) {
      fprintf(h, "%s\n", display[i]);

      printf("\n");
      i++;
    }

    printf("open the file");
  }
  fclose(h);
  free(display);

  return 0;
}

Solution

  • you have a big mesh in your code, I'll try to decode a bit of it, showing you the errors:

    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <stdlib.h>
    #define MAX 10000
    int elever = 1;
    
    struct likaprogramms {
      char civilekonom[50];
      char högskoleingenjör[50];
      char civilingenjör[50];
      char systemutvecklare[50];
    };
    
    struct student {
      char personnummer[32];
      char förnamn[32];
      char efternamn[32];
      char gender[32];
      char programmdife[32];
      char age[32];
      char email[32];
      struct likaprogramms *likaprogramm;
    };
    
    struct student *personer;
    
    struct programms {
      char namnen;
      char mcode;
      char responsible;
      char email;
    };
    
    void (*display[5])();
    

    display is an array of 5 pointers to void functions that take an undetermined number of arguments (an incomplete type definition, as the argument types and number of the functions to be stored in is not specified in the definition) This is maintained in C for legacy code compatibility, but not recommended today. While it is not an error, I cannot see why have you devised a so complex declaration for an array.

    
    void* base(char *display[5]) {
    

    here, display is an array of 5 pointers to char (or strings if they are to be '\0' terminated) The problem is that you have named the display local variable with the same name of a global array (also of 5 pointers to functions instead) so the only thing I can say at this point is that you will run into trouble later.

      //char fileA[MAX];
      char tal;
      int columns;
      FILE *f;
      f = fopen("elever.txt", "r");
      personer = (struct student*) malloc(elever * sizeof(struct student));
      personer->likaprogramm = malloc(sizeof(struct likaprogramms) * elever);
      display = malloc(sizeof *display);
      for (elever = 0; !feof(f);) {
    

    feof(f) returns a valid value only after you have tried to read the file, not before, as you check. While this is not a problem, you will add to your array a record of garbage with this for loop, as it will return you EOF only when you have already tried to read something incomplete (but you have added it already to the database).

        tal = fgetc(f);
    

    You could have used a while ((tal = fgetc(f)) != EOF) instead, before (as you are reading chars one by one). But tal must be declared as int (not char) for that purpose, as EOF is an integer constant outside of any posible character value you can store in a char variable. You can operate on an int variable in the followind code anyway, but this way, it allows you to detect the end of file condition before you process any invalid data.

        if (tal == '\n')
          printf("\n");
        {
          elever++;
          columns = 0;
          if (tal == ' ') {
            columns++;
          }
    
          if (columns == 0) {
            fscanf(f, " %s", &personer[elever].personnummer);
            //printf("%s",personer[elever].personnummer);
            // return (personer[elever].personnummer);  
            //columns++;                       
          }
          columns++;
          if (columns == 1) {
            fscanf(f, " %s", &personer[elever].förnamn);
            //  return (personer[elever].förnamn); 
          }
          columns++;
          if (columns == 2) {
            fscanf(f, " %s", &personer[elever].efternamn);
            //return (personer[elever].efternamn);                      
          }
          columns++;
          if (columns == 3) {
            fscanf(f, " %s", &personer[elever].gender);
            // return( personer[elever].gender);
          }
          columns++;
          if (columns == 4) {
            fscanf(f, " %s ", &personer[elever].programmdife);
            // return( personer[elever].programmdife);
          }
          columns++;
          if (columns == 5) {
            fscanf(f, " %s", &personer[elever].age);
            // return(personer[elever].age);
          }
          columns++;
          if (columns == 6) {
            fscanf(f, " %s", &personer[elever].email);
            // return(personer[elever].email);                   
          }
          return &personer[elever];
        }
        //free(personer);
      }
      // return 0;
      //fclose("elever.txt");     
    }
    
    int i;
    int main() {
      display[i] = base(*display[i]);
    

    why do you confound the reader assigning to display[i] with an uninitialized i variable (which, as global, is zero) instead of saying display[0] = base(*display[0]);

    More important, why you assing a function pointer cell de result of base() which should be a structure. The only thing you can do to a function pointer is to assign it and to execute the function it points to. But you are assigning a pointer to a structure (that information is hidden under the fact that you have defined it as returning void * which I don't know where have you learned about, but is not worth being used here) If your function is to dynamically allocate memory for the array, the array should have been defined as struct student * display[5]; or better struct student **display; (as because the dynamic nature of the memory allocation you can handle a variable number of structures in the array.

    
      FILE *h;
      h = fopen("Filedatabase.txt", "w");
      if (h == NULL) {
        printf("Could not write the file!\n");
        exit(1);
      } else {
        for (int i = 0; i < 7;) {
    

    why you go up to seven here if you have written everything for an array of five entries? The use of constants in the code is important so you never fail on this error.

          fprintf(h, "%s\n", display[i]);
    
          printf("\n");
          i++;
        }
    
        printf("open the file");
      }
      fclose(h);
      free(display);
    
      return 0;
    }
    

    If you want to learn to return a full structure, there is a sample code that will do what I guess you want to do, returning a structure and copying it back to the proper place in an assignment (but no malloc is used in this case, and so, no dynamic content in the program, you'll have always space for 5 students ---or the value of the constant--- and a proper array of struct student already allocated for you) This is a simpler example than yours, based on your code to illustrate structure return in C functions (I think it will be easier to understand and better to use in your code):

    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <errno.h>
    #include <stdlib.h>
    
    /* the two macros below allow pretty printing of error,
     * including the file and the line where the error
     * was detected. */
    #define F(_fmt) "%s:%d:"_fmt,__FILE__,__LINE__
    #define ERR(_cod, _fmt, ...) do{ \
                fprintf(stderr, F(_fmt),##__VA_ARGS__); \
                if(_cod) \
                    exit(_cod); \
            }while(0)
    
    struct student {
      char personnummer[32];
      char förnamn[32];
      char efternamn[32];
      char gender[32];
      char programmdife[32];
      char age[32];
      char email[32];
      struct likaprogramms *likaprogramm; /* I don;t use this field in my code */
    };
    
    /* use a constant, so if you want to change it later,
     *  you need only to change it here. */
    #define N_STUDENTS      (5)
    #define MAX_LINE        1000
    
    /* static allocation done by the compiler */
    struct student display[N_STUDENTS]; 
    
    /* the function now reads a single student from the already
     * open FILE descriptor f, and returns a struct student,
     * filled with the read data, ready for assignment in the
     * proper place. */
    struct student base(FILE *f)
    {
        //char fileA[MAX];
        int tal;
        int columns;
    
        /* use a local structure that will be copied back to
         * the proper place in the return statement */
        struct student return_value = {0};
    
        char line[MAX_LINE];
        char *p = fgets(line, sizeof line, f);
        if (!p) { /* EOF */
            return return_value; /* return it as it is to
                                  * indicate nothing was
                                  * returned */
        }
        /* process the fields */
        p = strtok(p, " \t\n");
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.personnummer, p,
                sizeof return_value.personnummer);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.förnamn, p,
                sizeof return_value.förnamn);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.efternamn, p,
                sizeof return_value.efternamn);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.gender, p,
                sizeof return_value.gender);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.programmdife, p,
                sizeof return_value.programmdife);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.age, p,
                sizeof return_value.age);
        p = strtok(NULL, " \t\n"); /* next field */
        if (!p) { /* no more fields */
            return return_value; /* same as above */
        }
        strncpy(return_value.email, p,
                sizeof return_value.email);
        /* the full reading process for each field could have
         * been condensed in a macro call for each field, as it
         * is done in the macro definition below to print entries.
         * I preferred to shorten one and not the other to show
         * the better readability of the macro code. */
        return return_value;
    }
    
    void print_entry(struct student *entry, FILE *out)
    {
    /* print the result for field _fn of entry variable */
    #define PR(_fn) fprintf(out, #_fn ": %s\n", entry->_fn)
        PR(personnummer);
        PR(förnamn);
        PR(efternamn);
        PR(gender);
        PR(programmdife);
        PR(age);
        PR(email);
    #undef PR /* not needed anymore */
    }
    
    int main()
    {
        int i;
        char *students_filename = "elever.txt";
        FILE *in = fopen(students_filename, "r");
        if (!in) {
            ERR(1, "Cannot open %s: %s (errno = %d)\n",
                students_filename, strerror(errno), errno);
            /* NOTREACHED */
        }
        for (i = 0; i < N_STUDENTS; i++) {
            display[i] = base(in); /* assign to display[i] the read
                                   * data from next student in in
                                   * FILE descriptor */
        }
        fclose(in); /* close file */
    
        char *database_filename = "Filedatabase.txt";
        FILE *out = fopen(database_filename, "w");
        if (!out) {
            ERR(1, "Cannot create %s: %s (errno = %d)\n",
                database_filename, strerror(errno), errno);
            /* NOTREACHED */
        }
    
        for (i = 0; i < N_STUDENTS; i++) {
            print_entry(&display[i], out); /* we pass it by
                                            * reference to
                                            * minimice copying
                                            */
        }
        fclose(out); /* again, flush buffer and close file */
        return 0;
    }