0

I've got the following struct

struct JugadorStruct_t {
int fichas, manos_ganadas, manos_perdidas;
char* nombre;
int* fichas_partidas;
};

I want to initialize this struct with some values in a txt file, so I do the following:

int initJugador(JugadorPtr_t jugador) {
    FILE* fp = 
fopen("/home/norhther/CLionProjects/blackjack/jugador.txt","r");

if (fp == NULL) {
    printf("El archivo del jugador no existe\n");
    fclose(fp);
    return 1;
}
else {
    char* line = NULL;
    size_t len = 0;

    getline(&line, &len, fp);
    jugador->nombre = strdup(line);

    getline(&line, &len, fp);
    jugador->fichas = atoi(line);

    getline(&line, &len, fp);
    jugador->manos_ganadas = atoi(line);

    getline(&line, &len, fp);
    jugador->manos_perdidas = atoi(line);


    while (getline(&line, &len, fp) != -1) {
        printf("%s", line);
    }
}

fclose(fp);
return 0;
}

(the pre is that the file has at least 4 lines)

I don't know how many lines there is left in the file, but in each remaining line there is a number. I wish to allocate memory and add each value to fichas_partidas.

Is there a nice way to achieve this?

Norhther
  • 545
  • 3
  • 15
  • 35
  • Why did you initialize `size_t len = 0`? Do you want to read 0 bytes from the buffer? –  Aug 12 '18 at 20:18
  • And you should use `strcpy` to assign a string to another, so `jugador->numbre = strdup(line); ` also seems buggy. –  Aug 12 '18 at 20:21
  • 2
    @adem: That's standard operating procedure with POSIX [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html). The function allocates memory as needed — passing a null pointer and zero length is a good way to get started. (The code should free `line` after all the input is complete, but that's not a part of the current issue.) Similarly, [`strdup()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html) is a POSIX function which allocates the correct space for a copy of the string and copies it. – Jonathan Leffler Aug 12 '18 at 20:21
  • @adem the call is correct – 0___________ Aug 12 '18 at 20:21
  • Generally you'd use a dynamic array (such as ArrayList in Java, std::vector in C++) to store arbitrarily long list of integers. In C, you can roll your own (not many lines of code) or find a suitable library. – hyde Aug 12 '18 at 20:29
  • The process of allocating an array dynamically has been shown many times on SO. The simplest form keeps track of the current size of the array and the number of used entries (plus the pointer to the array). When there isn't room for a new entry, double the size of the array. You can do it all with `realloc()` if the pointer is initially null – but remember that `2 * 0 == 0` (so I use `2 * current_size + 2` for the new size). This avoids linearly adding a single entry each time you read a line which ends up being slow. – Jonathan Leffler Aug 12 '18 at 20:35

1 Answers1

0

Here's an adaptation of your code that does what you need. Note that the file name is specified in the main() program (without an absolute path) and passed to the initialization function. Also note the discussion in Is it a good idea to typedef pointers? — the short answer is "No".

The code adds two fields to the structure to record the maximum number of entries that could be stored in the fichas_perdidas array, and the actual number of entries that are stored. The allocation code exploits the zero-initialization in main() and the fact that when passed a null pointer, realloc() behaves like malloc(). The allocation code reports the error to standard error; the name stderr indicates that is intended for error messages.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct JugadorStruct_t
{
    int fichas, manos_ganadas, manos_perdidas;
    char *nombre;
    int *fichas_partidas;
    int max_fichas;
    int num_fichas;
};

typedef struct JugadorStruct_t *JugadorPtr_t;   // Don't do this!

static
int initJugador(JugadorPtr_t jugador, const char *file)
{
    FILE *fp = fopen(file, "r");

    if (fp == NULL)
    {
        printf("El archivo del jugador no existe\n");
        fclose(fp);
        return 1;
    }

    char *line = NULL;
    size_t len = 0;

    getline(&line, &len, fp);
    jugador->nombre = strdup(line);

    getline(&line, &len, fp);
    jugador->fichas = atoi(line);

    getline(&line, &len, fp);
    jugador->manos_ganadas = atoi(line);

    getline(&line, &len, fp);
    jugador->manos_perdidas = atoi(line);

    while (getline(&line, &len, fp) != -1)
    {
        int x = strtol(line, 0, 0); /* Extremely sloppy */
        if (jugador->num_fichas >= jugador->max_fichas)
        {
            size_t new_number = 2 * jugador->max_fichas + 2;
            size_t new_buflen = new_number * sizeof(*jugador);
            void *new_buffer = realloc(jugador->fichas_partidas, new_buflen);
            if (new_buffer == NULL)
            {
                fprintf(stderr, "Out of memory (requesting %zu bytes)\n",
                        new_buflen);
                free(jugador->nombre);
                free(jugador->fichas_partidas);
                fclose(fp);
                return -1;
            }
            jugador->fichas_partidas = new_buffer;
            jugador->max_fichas = new_number;
        }
        jugador->fichas_partidas[jugador->num_fichas++] = x;
    }

    fclose(fp);
    return 0;
}

static void printJugador(const char *tag, struct JugadorStruct_t *jp)
{
    printf("%s (%p):\n", tag, (void *)jp);
    printf("Nombre:        [%s]\n", jp->nombre);
    printf("Fichas:         %d\n", jp->fichas);
    printf("Manos Ganadas:  %d\n", jp->manos_ganadas);
    printf("Manos Perdidas: %d\n", jp->manos_perdidas);
    printf("Num Fichas:     %d\n", jp->num_fichas);
    printf("Max Fichas:     %d\n", jp->max_fichas);
    for (int i = 0; i < jp->num_fichas; i++)
        printf("%2d: %d\n", i + 1, jp->fichas_partidas[i]);
}

int main(void)
{
    struct JugadorStruct_t j = { 0 };
    initJugador(&j, "jugador.txt");
    printJugador("After reading", &j);
    return 0;
}

Sample data file:

Line for nombre
32
27
19
12345
23456
34567
45678
56789
67890
99999999

Output from program:

After reading (0x7ffee84ee400):
Nombre:        [Line for nombre
]
Fichas:         32
Manos Ganadas:  27
Manos Perdidas: 19
Num Fichas:     7
Max Fichas:     14
 1: 12345
 2: 23456
 3: 34567
 4: 45678
 5: 56789
 6: 67890
 7: 99999999
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278