0

I am learning to work with structures and this doubt come to me when doing one exercise with C. I have this code:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>

#define MAX_STRING 256
#define MAX_CHILD 2000
#define MAX_GIFTS 20
#define MAX_LINE 1024

typedef char String[MAX_STRING];
typedef char Line[MAX_LINE];

typedef struct {    
    String child_name;  
    int grade;               //integer between 0 and 5
    String gift_name;   
    int price;              //price of the gift
} Data;

typedef struct { 
    String name;        
    int price;          
    bool received;      //true if the child will get this gift

} Gift;

typedef Gift Gifts[MAX_CHILD];

typedef struct{ 
    String name;            
    int grade;      
    Gifts asked;         //gifts the child asked for
    int n_asked;        
} Child;

typedef Child Children[MAX_CHILD];

Data make_data (String line){
    Data d;
    sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
    return d;
}

Child make_child(Data d) {
    Child c;
    strcpy(c.name, d.child_name);
    c.grade = d.grade;
    c.n_asked = 0;
    return c;
}

Gift make_gift(Data d){
    Gift g;
    strcpy(g.name, d.gift_name);
    g.price = d.price;
    g.received = false;
    return g;
}

int process(char file_name[]){
    Line line;
    FILE *f = fopen(file_name, "r");
    while(fgets(line, MAX_LINE, f) != NULL){
        make_data(line);  
    }
    int fclose (FILE *f);
}

int main(){
    process("data.txt");
    return 0;
}

So this program receives a file text of this format:

John 4 Bike 200
Alice 3 Computer 800
Alice 3 Candy 10
Mike 5 Skate 100

and constructs the data in the function process.

The problem is, I want to store all the children in the array Children[ ] and to print it( print all the array or just something similar to Children[0], Children[1],etc). I have tried some ways but no success...as the array is of type Children and not char*. Even when I just do Children cs; I get segmentation fault. Is there a way I can accomplish this?

And my second question is, initially I had #define MAX_CHILD 20000 and when I tried to compile I got an error saying "size of array ‘Children’ is too large". Why does this happen? I see it doesn't happen to Gifts, but happens to Children because the struct Child has a Gifts type as on the members, which means it requires more space.

Any help appreciated.

echelon
  • 5
  • 1
  • 2
  • 1
    Regarding 'too large' error, see: http://stackoverflow.com/questions/18371584/size-limit-of-an-array-in-gcc – TonyB Dec 12 '14 at 00:44
  • OP can eliminate the 'too large' problem by declaring the data in file space rather than on the stack. – user3629249 Dec 12 '14 at 02:17
  • the function: process() will cause the compiler to raise a warning about a function with a non-void return missing the actual return statement. (why post code that you know does not compile?) You are enabling all warnings? Warning are not be be ignored. – user3629249 Dec 12 '14 at 03:01
  • this is not pascal programming. So use function prototypes and 'open the ball' with the main() function. Good programing practices and good habits will stand by you when working on applications that contain thousands of files and millions of lines of code – user3629249 Dec 12 '14 at 03:07
  • @user3629249 This code does compile. All the structures was given to me(as I mentioned, it is an exercise) and I only had to build the process() function, and the only thing missing is to build the Children array, as I said. – echelon Dec 13 '14 at 16:17

2 Answers2

0
the use of the typedef's (and so on) 
instead of just writing the code out where it is needed
is unneeded (and distracting) and mis-leading and 
makes the code much more difficult to follow.

This function:

Data make_data (String line)
{
    Data d;
    sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
    return d;
}

has several problems:
1) the parameter list will cause the compiler to 'set aside' enough room
   for the String struct,
   invoke a memcpy() to copy the String struct
   to that 'set aside' memory from the callers' memory
   Then copy the 'set aside' memory to the called functions' stack
   That 'set aside' memory will never be used for anything else
   The stack will be cluttered with the contents of the String struct
   until the function returns
   such activity is a real 'bear' to debug
2) the returned value from sscanf() needs to be checked
   to assure that all 4 conversion operations were successful
3) the function return is a instance of the Data struct.
   This will cause the compiler to 'set aside' enough room
   for the Data struct.
   that 'set aside' memory will never be used for anything else
   invoke a memcpy() to copy the Data struct from the stack
   to the 'set aside' memory
   then perform the return from the function
   then the compiler will cause the caller to 
   invoke memcpy() to copy the Data struct
   from the 'set aside' memory to the caller's Data struct area.
   such activity is a real 'bear' to debug.

The function should be written more like this:

int make_data (String *pLine, Data* pData)
{
    int returnValue = 1; // initialize to indicate function successful

    if( 4 != sscanf(pLine," %s %d %s %d", 
                    pData->child_name, 
                   &pData->grade, 
                    pData->gift_name, 
                   &pData->price) )
    { // then sscanf failed
        perror( "sscanf failed for Line" );
        returnValue = 0; // indicate to caller that function failed
    } //  end if

    return( returnValue );
} // end function: make_data

and the caller(s) of this function should be adjusted accordingly

the make_gift() function has the same passed parameter
and returned parameter problems.
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thanks for the help but the function `Data make_data`, as all the others except `process()`, was given to me. I don't want to correct it, I just need to build the Children array. – echelon Dec 13 '14 at 16:19
0

The problem is, I want to store all the children in the array Children[ ] and to print it( print all the array or just something similar to Children[0], Children[1],etc).

to store:

    static Children cs;
    size_t nc = 0;  // number of children
    while (fgets(line, MAX_LINE, f))
    {
        #include <search.h>
        Data d = make_data(line);  
        Child c = make_child(d);
        Child *cp = lsearch(&c, cs, &nc, sizeof c, (int (*)())strcmp);
        cp->asked[cp->n_asked++] = make_gift(d);
    }

to print:

    int i, j;
    for (i = 0; i < nc; ++i)
    {
        printf("%s (grade %d) asked for %d:\n",
               cs[i].name, cs[i].grade, cs[i].n_asked);
        for (j = 0; j < cs[i].n_asked; ++j)
            printf("\t%s\t%d\n", cs[i].asked[j].name, cs[i].asked[j].price);
    }

(We cannot simply print an aggregate type object - we have to print the individual elements.)

Armali
  • 18,255
  • 14
  • 57
  • 171