Alex Alex - 1 month ago 16
C Question

Replacing gets() with fgets()

I've been testing this struct out and I get warning about using

gets
. Somebody mentioned to use
fgets
instead and replace the end with
'\0'
. Any recommendation how I can change my code to do that?

void regCars(Car reg[], int *pNrOfCars) {
char again[WORDLENGTH] = "yes", model[WORDLENGTH], tmp[WORDLENGTH];
int year, milage;

while (strcmp(again, "yes") == 0) {
printf("Enter model:");
gets(model);
printf("Enter Year:");
gets(tmp);
year = atoi(tmp);
printf("Enter milage:");
gets(tmp);
milage = atoi(tmp);
reg[*pNrOfCars] = createCar(model, year, milage);
(*pNrOfCars)++;
printf("Continue? (yes/no)");
gets(again);
}
}

Answer

You can write a utility function mygets() that takes 2 arguments: a pointer to the destination array and its size:

char *mygets(char *dest, size_t size) {
    /* read a line from standard input and strip the linefeed if any */
    if (fgets(dest, size, stdin)) {
        dest[strcspn(dest, "\n")] = '\0');
        return dest;
    }
    return NULL;
}

void regCars(Car reg[], int *pNrOfCars) {
    char model[WORDLENGTH], tmp[WORDLENGTH];
    int year, milage;

    for (;;) {
        printf("Enter model:");
        if (!mygets(model, sizeof mode))
            break;
        printf("Enter year:");
        if (!mygets(tmp, sizeof tmp))
            break;
        year = atoi(tmp);
        printf("Enter milage:");
        if (!mygets(tmp, sizeof tmp))
            break;
        milage = atoi(tmp);
        reg[*pNrOfCars] = createCar(model, year, milage); 
        (*pNrOfCars)++;
        printf("Continue? (yes/no)");
        if (!mygets(tmp, sizeof(tmp))
            break;
        if (strcmp(again, "yes") != 0)
            break;
    }
}

Note that you can factorize more code with a prompt() function that outputs the question and reads the response:

char *prompt(const char *message, char *dest, size_t size) {
    printf("%s ", message);
    fflush(stdout);
    /* read a line from standard input and strip the linefeed if any */
    if (fgets(dest, size, stdin)) {
        dest[strcspn(dest, "\n")] = '\0');
        return dest;
    }
    return NULL;
}

void regCars(Car reg[], int *pNrOfCars) {
    char model[WORDLENGTH], tmp[WORDLENGTH];
    int year, milage;

    for (;;) {
        if (!prompt("Enter model:", model, sizeof mode))
            break;
        if (!prompt("Enter year:", tmp, sizeof tmp))
            break;
        year = atoi(tmp);
        if (!prompt("Enter milage:", tmp, sizeof tmp))
            break;
        milage = atoi(tmp);
        reg[*pNrOfCars] = createCar(model, year, milage); 
        (*pNrOfCars)++;
        if (!prompt("Continue? (yes/no)", tmp, sizeof(tmp))
            break;
        if (strcmp(again, "yes") != 0)
            break;
    }
}

Also note that this function should take the size of the reg array to stop prompting for more input when it is full. As currently specified, it has the same shortcoming as gets(), unexpected input will cause undefined behavior.

Comments