-2

So, I'm having a problem with my code. I was trying to use fgets() for strings and scanf() for ints, but I read that this is bad practice and conflictive. I then tried using fgets() + sscanf() to read and parse a string to int. Still, for the love of me, I can't figure out what's happening! This is the code:

void menuUtente(CentroVacinacao *c)
{
    Utente u;
    char temp[20];

    printf("Introduza o nome do utente: \n");
    fgets(u.nomeUtente, NOME, stdin);
    while (getchar() != '\n')
    {
    }
    u.nomeUtente[strlen(u.nomeUtente) - 1] = '\0';
    printf("Introduza o número do utente: \n");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.numeroUtente);
    printf("Introduza a idade do utente: \n");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.idade);
    printf("Introduza o contacto do utente: \n");
    fgets(u.contacto, 9, stdin);
    u.contacto[strlen(u.contacto) - 1] = '\0';
    printf("Introduza a vacina tomada: \n");
    fgets(u.vacinaTomada.designacaoVacina, DESIGNACAO, stdin);
    u.vacinaTomada.designacaoVacina[strlen(u.vacinaTomada.designacaoVacina) - 1] = '\0';
    printf("Introduza as doses administradas: \n");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.dosesAdministradas);
    printf("Introduza a data da última dose (DD/MM/AAAA): \n");
    fgets(u.dataUltimaDose, 10, stdin);
    u.dataUltimaDose[strlen(u.dataUltimaDose) - 1] = '\0';

    acrescentaUtente(c, u);
}

And this is the output:

Can someone tell me what's happening? It's literally ignoring my first input and putting to inputs in the same line. Thanks in advance, been trying to figure this out for a while.

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

typedef struct sVaccine
{
    int vacID;
    char vacName[25];
    int numDoses;
    int monthsBetweenDoses;
} Vaccine;
typedef struct sPatient
{
    int patientNumber;
    char patientName[100];
    int age;
    char phoneNo[11];
    Vaccine vacTaken;
    int doses;
    char lastDoseDate[10];
} Patient;
typedef struct sVaccinationCenter
{
    int centerCode;
    char centerName[100];
    char address[20];
    Patient vaccinatedPatient[3000];
    Vaccine vaccineUsed;
    int numberOfPatients;
} VaccinationCenter;
VaccinationCenter init()
{
    VaccinationCenter c;
    c.numberOfPatients = 0;
    return c;
}
int addPatient(VaccinationCenter *c, Patient u)
{
    if (c->numberOfPatients == 3000)
    {
        return -1; // O centro está cheio
    }

    c->vaccinatedPatient[c->numberOfPatients] = u;
    c->numberOfPatients++;
    return 0;
}
void menuPatient(VaccinationCenter *c)
{
    Patient u;
    char temp[20];

    printf("Patient Name: ");
    fgets(u.patientName, 100, stdin);
    u.patientName[strlen(u.patientName) - 1] = '\0';
    printf("Patient Number: ");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.patientNumber);
    printf("Patient Age: ");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.age);
    printf("Patient Contact: ");
    fgets(u.phoneNo, 11, stdin);
    u.phoneNo[strlen(u.phoneNo) - 1] = '\0';
    printf("Vaccine Used: ");
    fgets(u.vacTaken.vacName, 25, stdin);
    u.vacTaken.vacName[strlen(u.vacTaken.vacName) - 1] = '\0';
    printf("Doses Taken: ");
    fgets(temp, sizeof(temp) - 1, stdin);
    sscanf(temp, "%d", &u.doses);
    printf("Last Dose Taken (DDMMAAAA): ");
    fgets(u.lastDoseDate, 10, stdin);
    u.lastDoseDate[strlen(u.lastDoseDate) - 1] = '\0';

    addPatient(c, u);
}
void listCenter(VaccinationCenter c)
{
    for (int i = 0; i < c.numberOfPatients; i++)
    {
        printf("Patient Name: %s\n", c.vaccinatedPatient[i].patientName);
        printf("Patient Number: %d\n", c.vaccinatedPatient[i].patientNumber);
        printf("Patient Age: %d\n", c.vaccinatedPatient[i].age);
        printf("Patient Contact: %s\n", c.vaccinatedPatient[i].phoneNo);
        printf("Vaccine Used: %s\n", c.vaccinatedPatient[i].vacTaken.vacName);
        printf("Doses Taken: %d\n", c.vaccinatedPatient[i].doses);
        printf("Last Dose Taken: %s\n", c.vaccinatedPatient[i].lastDoseDate);
    }
}
int main(int argc, char const *argv[])
{
    VaccinationCenter c = init();
    int opcao = -1;

    //menuUtente(&c);
    c.numberOfPatients = 0;

    while (opcao != 0)
    {
        printf("1 - Insert patient;\n");
        printf("2 - List patients;\n");
        printf("0 - Leave;\n");
        printf("Enter your choice -> ");
        scanf("%d", &opcao);
        switch (opcao)
        {
        case 1:
            menuPatient(&c);
            break;
        case 2:
            listCenter(c);
            break;
        case 0:
            break;
        default:
            printf("Invalid Option!\n");
            break;
        }
    }
    return 0;
}
khr0nyx
  • 3
  • 2
  • What is that extra `while (getchar() != '\n')` loop for? I'd get rid of it. – Steve Summit Jan 21 '21 at 00:59
  • @SteveSummit if I get rid of that line, it just skips asking for my first input. [without getchar](https://imgur.com/eTZX4KO) as you can see, I just can't input anything for "Introduza o nome do utente: ". – khr0nyx Jan 21 '21 at 01:03
  • The output you are sharing does not correspond to the code you share, or more accurately, the problematic part of the output is not coming from this part of the code. – Zois Tasoulas Jan 21 '21 at 01:04
  • @zois here is the full code: [full code](https://imgur.com/yVEv5Ca) EDIT: I noticed in the printf i missed a \n. That part is sorted. It still doesn't print the name tho. – khr0nyx Jan 21 '21 at 01:06
  • The line `printf("Vacina Utente: %s", . . .) ` is missing a `\n` (the dots are my addition, could not copy the whole line and did not spent time typing it) – Zois Tasoulas Jan 21 '21 at 01:08
  • 1
    Yes, I noticed it too. But the problem still remains, it doesn't print the first line to the terminal. – khr0nyx Jan 21 '21 at 01:10
  • What is the value of `NOME`? – Zois Tasoulas Jan 21 '21 at 01:11
  • #define NOME 100 – khr0nyx Jan 21 '21 at 01:12
  • Try printing `u.nomeUtente` immediately after you read the value. Also I think `u.nomeUtente[strlen(u.nomeUtente) - 1] = '\0';` is not necessary, the string should be null terminated – Zois Tasoulas Jan 21 '21 at 01:20
  • It prints correctly if I do the printf() right after the fgets(). – khr0nyx Jan 21 '21 at 01:26
  • I would suggest sharing an example that we can exacute and see, some parts are missing at the moment, e.g., `acresentaUtente` – Zois Tasoulas Jan 21 '21 at 01:27
  • What would be the best way for me to share the full program? It's linked with makefiles, there's multiple files. – khr0nyx Jan 21 '21 at 01:36
  • Read about how to create an MCVE ([Minimal, Complete, Verifiable Example](https://stackoverflow.com/help/mcve) — or MRE or whatever name SO now uses) or an SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) — the same idea by a different name. A single file should be enough — no makefile needed. And it shouldn't be huge — I'd be surprised if it needed to be 100 lines. – Jonathan Leffler Jan 21 '21 at 01:40
  • 1
    edited the original post with a MCVE. – khr0nyx Jan 21 '21 at 02:02
  • 1
    @khr0nyx check this posting https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer the issue is that when you first enter the option number, the enter key is kept in the input buffer, thus the name gets that character, without waiting for a new input – Zois Tasoulas Jan 21 '21 at 02:18
  • I just tried it, and it compiled for me, in a mac and in a Windows pc. – khr0nyx Jan 21 '21 at 02:18
  • compiles for me as well, with gcc – Zois Tasoulas Jan 21 '21 at 02:19
  • 1
    @khr0nyx what doesn't compile is the `menuUtente`. If this function isn't supposed to be in the program then why do you leave its code in the question? – vmp Jan 21 '21 at 02:23
  • 1
    Subtracting 1 not needed: `fgets(temp, sizeof(temp) - 1, stdin);` --> `fgets(temp, sizeof temp, stdin);` – chux - Reinstate Monica Jan 21 '21 at 03:48
  • Avoid using `fgets()` and `scanf()` together. Avoid `scanf()`. – chux - Reinstate Monica Jan 21 '21 at 11:49

1 Answers1

0

Try adding this getchar():

printf("Enter your choice -> ");
scanf("%d", &opcao);
getchar();

This seemed to make the second part of code you pasted work. It doesn't skip anymore and it lists the registered patients. The thing is: I couldn't understand if thats the issue you are trying to solve.

vmp
  • 2,370
  • 1
  • 13
  • 17
  • It would probably be better to use `int c; while ((c = getchar()) != EOF && c != '\n') ;` in place of a single `getchar()`, but the problem that `scanf()` leaves the newline in the input is the initial source of trouble. The difference matters if the user types a blank or some other character after the number and before the newline. Not a common problem, but a real one nonetheless. – Jonathan Leffler Jan 21 '21 at 14:29
  • A general critique of the code in the question is that it does not test that the input operations succeed but it should. You have to test that the inputs worked. People are notoriously bad at typing accurately. I've put this here as there is a lot of clutter in the comments after the question. – Jonathan Leffler Jan 21 '21 at 14:31