-2

First of all sorry for any english error. So, I have this data in a .txt file

Codigo,Produto,StockMinimo,StockAtual
1,Couro,300,1000
2,Tecido,250,2000
...

I want to skip the first line and read only the integers to a struct

I'm using the bellow function to count the line of the file:

int nrLinhasFicheiro(char *filename){
    char ch;
    FILE *file;
    file = fopen(filename, "r");
    int linhas = 0;
    if (file != NULL) {
         for (ch = getc(file); ch != EOF; ch = getc(file)) 
        if (ch == '\n')  
            linhas = linhas + 1; 
    }
    fclose(file);
    return linhas - 1;
}

and this one to read the file to the struct "Stock" :

void carregarStock(Stock *stock, char *nomeFicheiro){
    int i = 0;
    int codigo; //stores "codigo" values
    char stringFake[40], *storeProduto; //variables to store first line and "Produto" string
    int minimo, quantidade;
    
    FILE *fp = fopen(nomeFicheiro, "r");
    
    int numeroLinhas = nrLinhasFicheiro(nomeFicheiro);
    
    if (fp != NULL){
       
        if(numeroLinhas >0){
            fscanf(fp, "%s",stringFake);//skip first line
            
            while(i< numeroLinhas){
                fscanf(fp, "%d,%s ,%d,%d", &codigo, storeProduto, &minimo, &quantidade);
                //fscanf(fp, "%d,%s %d,%d", &codigo, storeProduto, &minimo, &quantidade);  also tried this and don't work
                
                if(codigo==1){
                    stock->minStockCouro = minimo;
                    stock->couroStock = quantidade;
                }else if(codigo==2){
                    stock->minStockTecido = minimo;
                    stock->tecidoStock = quantidade;
                }else if(codigo==3){
                    stock->minStockBorracha = minimo;
                    stock->borrachaStock = quantidade;
                }else if(codigo==4){
                    stock->minStockCordoes = minimo;
                    stock->cordoesStock = quantidade;
                }else if(codigo==5){
                    stock->minStockPalmilhas = minimo;
                    stock->palmilhasStock = quantidade;
                }   
                i++;
            }
            
        }else{
            puts("Error");          
        }      
    }else{
        puts(MSG_ERRO_LER_FICHEIRO);
    }
    fclose(fp);
}

Function to print the struct:

void mostrarStock(Stock stock){
    puts("==============  Stock : =============\n");
    puts("Codigo | Produto | Stock Minimo | Stock Atual\n");
    printf("1\tCouro\t\t%d\t\t%d\n", stock.minStockCouro, stock.couroStock);
    printf("2\tTecido\t\t%d\t\t%d\n", stock.minStockTecido, stock.tecidoStock);
    printf("3\tBorracha\t%d\t\t%d\n", stock.minStockBorracha, stock.borrachaStock);
    printf("4\tCordões\t\t%d\t\t%d\n", stock.minStockCordoes, stock.cordoesStock);
    printf("5\tPalmilhas\t%d\t\t%d\n", stock.minStockPalmilhas, stock.palmilhasStock);

}   

This is how i call the function in main:

int main(int argc, char** argv) {
    
    char *nomeFicheiro1 = "tabela_stocks.txt";
    Stock stock;
    carregarStock(&stock, nomeFicheiro1);
    mostrarStock(stock);
    
    return (EXIT_SUCCESS);
}

The function to print the struct doesn't print. I guess the error is in

fscanf(fp, "%d,%s ,%d,%d", &codigo, storeProduto, &minimo, &quantidade);

What am I doing wrong?

  • Please provide a [mre]. – Yunnosch Feb 12 '22 at 11:59
  • I do not get what you mean by "I run the project it appears "Run Successful" but either the info is read to the structs either prints the printf's tests.". Please rephrase. – Yunnosch Feb 12 '22 at 12:02
  • @Yunnosch i edited the post so I hope that now it is better. About your second comment, when I run the project it appears "Run Succesfull" (i'm using netbeans) but the info isn't stored in the struct because when I can the function to print the struct, nothing is printed. In the "carregarStock" function the printf's that I have to test if it was read to the struct variables don't print anything either. – Luís Oliveira Feb 12 '22 at 12:10
  • 1
    Please provide a [mre]. The context of how you call the shown functions is important. And you should do all the explaining within the question. So better [edit] it instead of adding infos in comments which belong into the question body. – Yunnosch Feb 12 '22 at 12:13
  • Please read [mre] (...again). I get the impression that you are missing some essential parts of the concept. – Yunnosch Feb 12 '22 at 12:26
  • Note that 'char ch;' cannot hold EOF. Use int. – Martin James Feb 12 '22 at 13:52

1 Answers1

3

You could create a helper function to read out the two integers from one line.

bool get_two(FILE *stream, int* a, int* b) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", a, b) == 2;
}

You then just need to call that 5 times.

Example:

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

typedef struct {
    int couroStock;
    int minStockCouro;
    int tecidoStock;
    int minStockTecido;
    int borrachaStock;
    int minStockBorracha;
    int cordoesStock;
    int minStockCordoes;
    int palmilhasStock;
    int minStockPalmilhas;
} Stock;

bool get_two(FILE *stream, int* a, int* b) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", a, b) == 2;
}

int main() {
    FILE *fp = fopen("tabela_stocks.txt", "r");
    if(fp) {
        Stock s;
        fscanf(fp, "%*[^\n]"); // skip first line

        if(get_two(fp, &s.couroStock, &s.minStockCouro) &&
           get_two(fp, &s.tecidoStock, &s.minStockTecido) &&
           get_two(fp, &s.borrachaStock, &s.minStockBorracha) &&
           get_two(fp, &s.cordoesStock, &s.minStockCordoes) &&
           get_two(fp, &s.palmilhasStock, &s.minStockPalmilhas))
        {
            printf("%d %d\n", s.couroStock, s.minStockCouro);
            printf("%d %d\n", s.tecidoStock, s.minStockTecido);
            printf("%d %d\n", s.borrachaStock, s.minStockBorracha);
            printf("%d %d\n", s.cordoesStock, s.minStockCordoes);
            printf("%d %d\n", s.couroStock, s.minStockCouro);
        }
        fclose(fp);
    }
}

If tabela_stocks.txt contains

Codigo,Produto,StockMinimo,StockAtual
1,Couro,300,1000
2,Tecido,250,2000
3,Borracha,200,500
4,Cordões,500,2000
5,Palmilhas,500,1000

Then the output will be

300 1000
250 2000
200 500
500 2000
300 1000

Since there are so many similarities between the different stocks in your Stock struct, you could break it down into smaller pieces and make a struct only holding information about one stock:

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

typedef struct {
    int stock;
    int min_stock;
} Stock;

bool Stock_read(FILE *stream, Stock *s) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", &s->stock, &s->min_stock) == 2;
}

void Stock_print(const Stock *s) {
    printf("%d %d\n", s->stock, s->min_stock);
}

With that you could create a Stocks type like this:

typedef struct {
    Stock Couro;
    Stock Tecido;
    Stock Borracha;
    Stock Cordoes;
    Stock Palmilhas;
} Stocks;

bool Stocks_read(FILE *stream, Stocks *s) {
    return
        Stock_read(stream, &s->Couro) &&
        Stock_read(stream, &s->Tecido) &&
        Stock_read(stream, &s->Borracha) &&
        Stock_read(stream, &s->Cordoes) &&
        Stock_read(stream, &s->Palmilhas);
}

void Stocks_print(const Stocks *s) {
    Stock_print(&s->Couro);
    Stock_print(&s->Tecido);
    Stock_print(&s->Borracha);
    Stock_print(&s->Cordoes);
    Stock_print(&s->Palmilhas);
}

and reading and printing would become simpler:

int main() {
    FILE *fp = fopen("tabela_stocks.txt", "r");
    if(fp) {
        Stocks s;
        fscanf(fp, "%*[^\n]"); // skip first line

        if(Stocks_read(fp, &s)) {
            Stocks_print(&s);
        }
        fclose(fp);
    }
}

Looking closer at the Stocks struct you may want to consider using an array instead:

typedef struct {
    Stock stocks[5];
} Stocks;

which would also simplify the rest of the code since you could loop over that array to read and print each Stock.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thank you very much for your reply. After reading your code, I redo my code replacing : `fscanf(fp, "%d,%s ,%d,%d", &codigo, storeProduto, &minimo, &quantidade);` for `fscanf(fp, "%d, %*[^,],%d,%d", &codigo, &minimo, &quantidade);` So the use of `%*[^,]` solve it Can you explain me what `%*[^,]` does? – Luís Oliveira Feb 12 '22 at 12:32
  • 1
    @LuísOliveira You're welcome! `%*[^,]` is a non-capturing scan until a `,` is found. So it just skips ahead until `,`. – Ted Lyngmo Feb 12 '22 at 12:43
  • again, thank you for your explanation. All the best to you. – Luís Oliveira Feb 12 '22 at 12:47
  • 1
    @LuísOliveira Glad it helped! You're welcome! – Ted Lyngmo Feb 12 '22 at 12:48