0

I have code to store data into this struct:

typedef struct sales{
    char *date;
    char *stockCode;
    int quantity;
} sales;

I do it via this function:

void storeSales(FILE *salesf){
    struct sales sale[40000];
    char str[255];
    // counter for array position
    int counter = 0;
    while (fgets(str, 255, salesf) != NULL){
        counter++;
        char *date = strtok(str, " ,");
        char *stockCode = strtok(NULL, " ,");

        // store the
        sale[counter].date = malloc(strlen(date)+1);
        strcpy(sale[counter].date, date);

        sale[counter].stockCode = malloc(strlen(stockCode)+1);
        strcpy(sale[counter].stockCode, stockCode);

        sale[counter].quantity = atoi(strtok(NULL, "\n"));
    }
}

But now the values are stored I want to use them. I could of course add this to the storeSales(FILE *salesf) function to print them:

   int count = 0;
     for(count =0; count <counter; count++){
        printf("%s %s %d \n", sale[count].date, sale[count].stockCode, sale[count].quantity);
    } 

But of course having a function to store the data which then prints them isn't quite what I want.

Within my main I wish to have access to this array of structs, I've read you cannot pass back an array of structs in a function.

Is there a way to return an array of pointers which are pointing to the structs?

It's all very new to me!

I'm trying to make my code as modular as possible.

  • C does not support _methods_, only _functions_. – too honest for this site Mar 22 '16 at 17:22
  • Yeah I'm sorry, I mean functions @Olaf –  Mar 22 '16 at 17:23
  • 1
    Either the calling function allocates the space and lets the called function know how much space it may use (it passes a pointer and an array size to the called function), or the called function allocates the space and the calling function passes a pointer to pointer and a pointer to size so that the called function can tell the calling function how much space it (the called function) allocated and where it is. – Jonathan Leffler Mar 22 '16 at 17:58
  • @JonathanLeffler: as third alternative, one can return the pointer as OP literally asks. – too honest for this site Mar 22 '16 at 18:33
  • 2
    @Olaf: yes, you can; you then have to worry about how do you know how big the array is. If you use a null pointer for the last entry, you can do so; otherwise, you can return it via a pointer to size argument. Or you can use a structure type that has a pointer and a size as elements and return that. Or … – Jonathan Leffler Mar 22 '16 at 18:52
  • @JonathanLeffler: That's where a `struct` with FAM comes in handy. Anyway, you are right, of course. There are multiple variants how to do that. – too honest for this site Mar 22 '16 at 18:58

2 Answers2

0

Change your function to: void storeSales(FILE *salesf, struct* sale, int* counter);

you then have to allocate your array in the main and call the function like this:

struct sales sale[40000];
int counter;
storeSales(salesf, sale, &counter);

and then you can acces your array from the main.

edit: In the storeSales function you have to pay attention not to leave the bounderies of your array! You could prevent this by storing the arraysize 40000 in the counter variable. And taking this in storeSales to check for stack overflow.

RomCoo
  • 1,868
  • 2
  • 23
  • 36
0

You have created a typedef of a struct:

typedef struct sales{
    char *date;
    char *stockCode;
    int quantity;
} SALES; //caps make this stand out better

Because you have created your struct with a typedef

 struct sales sale[40000];

should be created as

sales sale[40000];

or with SALES (caps)

SALES sale[40000]; //this is a lot of structs (may be problematic)   

But to answer your question, if you change your prototype to:

void storeSales(FILE *salesf, SALES *s){

You can call it and update it like this:

int main(void)
{
    FILE *fp = fopen("somefile", "r");

    sale[0].date = malloc(20);
    sale[0].stockCode = malloc(20);

    storeSales(fp, sale);
    printf("date: %s\n Stock code: %s\n Quantity: %d\n", 
                 sale[0].date, sale[0].stockCode, sale[0].quantity);
    free(sale[0].date);
    free(sale[0].stockCode);
    return 0;   
}

void storeSales(FILE *f, SALES *s)
{
    ...

    strcpy(s[0].date, "some date"); 
    strcpy(s[0].quantity, "some quantity"); 
    s[0].stockCode=12345678;
    ...
}

Please note that the example just addresses your question: is there a way to return an array of pointers which are pointing to the structs?, but there are some other questions you should ask. The array of 40000 struct may not be the best way to handle the data. Also, it would be better to create memory for all members before sending, the lines shown are just to illustrate the concept.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • One of the few commonly accepted naming conventions in C is to use all-uppercase names only for macros and enum-constants (i.e. the only symbolic constants you can use in C code). – too honest for this site Mar 22 '16 at 18:30
  • 1
    @Olaf - Your comment is helpful. It would be even more helpful if you would please make a suggestion on how to improve. I should note that we commonly use upper case in the industries I work (medical, aerospace) to distinguish typedefed structs in addition to the items you mentioned. It does not cause confusion as by context they are always distinguishable. – ryyker Mar 22 '16 at 18:35
  • Strange. I work in the same field sometimes, but never encountered such a requirement. Typically my customers use the same as I do: Camel case. Maybe your's is some legacy (see `FILE`). – too honest for this site Mar 22 '16 at 18:37
  • 1
    LOL, yes, I do maintain a lot of old code. CamelCase is used commonly in my variables, and function names. I have seen them (as well as upper case struct typedefs) since I started programming. I am careful not to use _StructName_t_, as I am aware there are sacred places this notation is used, but for this post I will be happy to change it if you think it will add clarity to the concept. Either way, It is not an argument for me. – ryyker Mar 22 '16 at 18:45
  • 1
    A comment does not necessarily mean you have to follow it. I'm actually quite surprised to hear it's really used that way. I'd call it (in conformance to my first comment) uncommon (the two industries are notoriously lagging behind modern development techniques). Feel free to do as you think. – too honest for this site Mar 22 '16 at 18:47
  • Thank you for your answer, I'm a little confused by your code, the main allocates space for the data, then prints it, the storeSales() function stores the data? am I correct in saying this? is this how it's generally done? Also what about many structs? Like by my example I have thousands of structs that need to be made, the number of structs is the number of lines in the text file –  Mar 22 '16 at 20:10
  • Also why haven't you used the code I had `sale[counter].stockCode = malloc(strlen(stockCode)+1); strcpy(sale[counter].stockCode, stockCode);` –  Mar 22 '16 at 20:26
  • @user3667111 - The way you have it (call to malloc) in your code is perfectly fine. I just shorted the example code in mine to focus on the purpose of my answer (simply to show how to pass struct pointer as argument). This is a fairly common way to pass a struct. The way your code is structured in general would _normally_ not be done exactly that way. Again, consider a way other than creating a large array of struct. – ryyker Mar 22 '16 at 20:40
  • What other ways are there to do it? rather than an array of structs? @ryyker –  Mar 22 '16 at 20:50
  • @user3667111 - Array of struct is fine, for reasonably size arrays. 40000 elements is excessive. Are you reading from a database, or a text file, or some other intermediate media? If so, read a record at a time, process it, write it back, then read another record. (for example) – ryyker Mar 22 '16 at 21:00
  • From a text file, thousands of lines of data @ryyker –  Mar 22 '16 at 21:01
  • @user3667111 - so a single record is likely represented on a single line if the text file? You can easily read a line in, parse it into your struct, pass the struct to the function that will modify the record (members) return it, then write the record back to the file (or a new file). This way, you could literally do what you need with a single instance of the struct, instead of the array – ryyker Mar 22 '16 at 21:58
  • Thank you, I'll put together a better approach –  Mar 23 '16 at 11:31