0

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;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Karim13
  • 23
  • 5
  • you can only return pointer to structure. – RbMm Jan 01 '22 at 17:22
  • Please read https://stackoverflow.com/help/how-to-ask, learn how to format your code so it's readable, and show an https://stackoverflow.com/help/mcve – Employed Russian Jan 01 '22 at 17:40
  • @RbMm ok but how to print it into a file? – Karim13 Jan 01 '22 at 17:41
  • 3
    To me it's unclear what you are asking... but you can return a struct just like you return an int, a double or.... No problem – Support Ukraine Jan 01 '22 at 17:41
  • 3
    @RbMm It's not a problem to return a struct by value – Support Ukraine Jan 01 '22 at 17:42
  • @4386427 I want to return the values of my structur to the main() function and then to print it to a file... like I want to get the values of personer[elever].age personer[elever].förnamn personer[elever].efternamn.. etc and return them with the function display[i] and the print them into a file – Karim13 Jan 01 '22 at 17:46
  • @Karim13 Then simply return the relevant struct... – Support Ukraine Jan 01 '22 at 17:48
  • @4386427 - in general case this is impossible. only if structure small enough to fit 1 or 2 general registers. when you "return" structure by value - caller function allocate memory for structure and pass pointer to allocated memory as hidden parameter to function. function copy structure to this memory. when no optimization, frequently more than one copy done – RbMm Jan 01 '22 at 17:56
  • 5
    @RbMm Returning a `struct` is possible in C even if structure not "small enough to fit 1 or 2 general registers". That size concern is an implementation issue, not a language one. Asserting (incorrectly) "you can only return pointer to structure" diverts from OP real issue. – chux - Reinstate Monica Jan 01 '22 at 18:51
  • @chux-ReinstateMonica - internal this is always implemented by passing hiden pointer to function and frequently even with optimization - not best code (more copy than need). always better explisit control details and pass pointer to caller by self – RbMm Jan 01 '22 at 18:54
  • 1
    @RbMm Disagree with "always implemented by ..." and "always better". Yet we are trending to OT. – chux - Reinstate Monica Jan 01 '22 at 18:57
  • @chux-ReinstateMonica and how else structure can be returned (if it can not fit to 1,2 registers) ? – RbMm Jan 01 '22 at 18:58
  • `Could not write the file!` implies that there was an error with `fwrite`. It is not an appropriate error message to give upon failure to open the file. The system tells you why the `fopen` failed, and you should include that information in the error message. eg `if( (h=fopen("Filedatabase.txt", "w")) == NULL ){ perror("Filedatabase.txt");}` – William Pursell Jan 01 '22 at 19:03
  • Karim13, code has many problems in reading as code like `fscanf(f, " %s", ...` leads to undefined behavior when input longer than expected. The various `fscanf()` do not check the return value of `fscanf()`, further questioning how successful the read was. I recommend update the code to check return values, limit input into `"%s"` with a _width_ like `"%31s"`, review [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/q/5431941/2410359), compile will all warnings on until warning free and re-post - with sample input data. – chux - Reinstate Monica Jan 01 '22 at 19:13
  • 1
    @RbMm, how it is passed back is irrelevant to functionality. Consider the non-`struct` case of `complex long double foo()`, that can well return 32 bytes. Whether passed on the stack, in regs, in a co-processor, in global memory, it does not affect functionality - something I've seen various compilers do. IAC, C allows returning large objects. As to if that is a good design is a worthy consideration - yet that is separate from possibility. – chux - Reinstate Monica Jan 01 '22 at 19:27
  • @chux-ReinstateMonica despite *c/c++* allow return object, in most case compiler generated code for this not optimal. especially in c++ if object have constructor/destructor. i think need always understand how this internally implemented in concrete platform and i personally prefer avoid this. explicit control where object will be allocated, avoid copy, etc – RbMm Jan 01 '22 at 19:46
  • 1
    @RbMm So for this C question, you still maintain [you can only return pointer to structure](https://stackoverflow.com/questions/70550511/how-to-return-structure-value?noredirect=1#comment124713657_70550511) is accurate enough to remain? – chux - Reinstate Monica Jan 01 '22 at 20:04
  • @chux-ReinstateMonica - by implementation - yes, even in case you write src code which return structure by value, compiler transform this code for return via pointer. if you write `somestruct foo(type t,...)` compiler transorm this to something like `void foo(somestruct* p, type t, ...)` – RbMm Jan 01 '22 at 21:05
  • Karim13, I look forward to your improved question. – chux - Reinstate Monica Jan 01 '22 at 22:47
  • @chux-reinstate-monica thanks for your answers....its seems that I had wrong code and I have to make it better by reading the file in better way. thanks again and I will surley ask for help again. – Karim13 Jan 01 '22 at 23:42
  • Please note that all those `if (column == ...` are either *all* true or *all* false, depending on the first `if ( tal == ' ' )`. You'd better check the values returned from all those scanf instead. – Bob__ Jan 02 '22 at 00:02
  • @Bob__ well, my idea was to save every value from the file who start after the space and ends by space into structure and it worked if I print it at the same time I scan it.. But if I reprint it with array in other function then I will get strange behaviour. – Karim13 Jan 02 '22 at 00:08
  • When I compile your code I get over 10 warnings... start by fixing all warnings – Support Ukraine Jan 02 '22 at 08:20
  • Can you explain what you want this to do: `display[i] = base(*display[i]);` – Support Ukraine Jan 02 '22 at 08:22
  • What type do you expect `display` to be here: `void (*display[5])();` – Support Ukraine Jan 02 '22 at 08:24

1 Answers1

1

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;
}
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • thank u so much man, I loved ur answer and found what I wanted. I'm so thankfull, u was right I understand much better and I really found what I was looking for. – Karim13 Jan 04 '22 at 21:25