简体   繁体   中英

Why doesn't my C program wait to scan input?

I am new to C. I allocated memory with this statement:

patientptr = (char*) calloc (118, sizeof (char));

then I assign data using this (this is a part of the function):

char name[51];
int age;
char agestr[3];
char infectiondate [11];
char address[51];
char *patientptr;

printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;

printf("Enter the patient age: ");
scanf ("%d", &age);
sprintf (agestr, "%2d", age);
*(patientptr + 51) = agestr;

printf("Enter the patient date of infection (in form of dd/mm/year): ");
*(patientptr + 54) = scanf ("%10d", infectiondate);

printf("Enter the patient address (50 characters at maximum): ");
*(patientptr + 65) = scanf ("%50s", address);

*(ptrsptr+patientsnum-1) = patientptr;

printf ("\nPatient added.\n");

Everything goes fine except that after the "enter the patient address: " line, it prints the "patient added" line directly without waiting to scan the address. the output is like this:

Enter the patient name (50 characters at maximum): ahmed
Enter the patient age: 20
Enter the patient date of infection (in form of dd/mm/year): 10/10/2020
Enter the patient address (50 characters at maximum):
Patient added.

is the wrong with my allocated memory?

You may well have used calloc to allocate some memory but examine this snippet:

char *patientptr;

printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;

That first line shadows whatever patientptr was with an uninitialised pointer, hence the final line is undefined behaviour ( patientptr now points to some arbitrary address). All bets are off at this point, anything is possible.

Fix that and try again.


In addition, it looks like you believe that:

*(patientptr + 51) = agestr;

is a way to copy a C string from one place to another. In actual fact, this will attempt to place the agestr pointer value into the single character at the memory location &(patientptr[51]) , and possibly should have warned you about this.

You need to look into strcpy for this, something along the lines of:

strcpy(patientptr + 51, agestr);

But, if you're looking to do user input, it's often a good idea to work around the limits of scanf . It does, after all, stand for "scan formatted" and there's very little that's less formatted than user input.

I have a favourite function I use for this, which is shown below, along with the modifications to your own code to use it (using both that function and with quite a bit of other validation specific to your case):

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

// Bullet-proof line input function.

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

// Ensure a character array is non-empty and all digits.

int checkDigits(char *arr, size_t sz) {
    if (sz == 0) {
        return 0;
    }
    while (sz-- > 0) {
        if (! isdigit(*arr++)) {
            return 0;
        }
    }
    return 1;
}

// Get customer data line, return NULL if okay, error if not.
// Output record must be long enough for format string below
// and a one-character end-string marker.

static char *getPatientData(char *patientData) {
    // Keep this format string in sync with field sizes below.

    static char *fmtString = "%-50.50s" "%3d" "%-10.10s" "%-50.50s";
    char name[51];
    char ageStr[4];
    char infectionDate[11];
    char address[51];

    if (getLine("Patient name: ", name, sizeof(name)) != OK) {
        return "Error getting name.";
    }

    if (getLine("Patient age: ", ageStr, sizeof(ageStr)) != OK) {
        return "Error getting age.";
    }
    if (! checkDigits(ageStr, strlen(ageStr))) {
        return "Error, age contains non-digit data.";
    }
    int age = atoi(ageStr);
    // Further age sanity checking, if desired. Example: ensure <= 150.

    if (getLine("Infection date (dd/mm/yyyy): ", infectionDate, sizeof(infectionDate)) != OK) {
        return "Error getting infection date.";
    }
    if (
        strlen(infectionDate) != 10
        || infectionDate[2] != '/'
        || infectionDate[5] != '/'
        || ! checkDigits(infectionDate, 2)
        || ! checkDigits(infectionDate + 3, 2)
        || ! checkDigits(infectionDate + 6, 4)
    ) {
        return "Error, incorrect format.";
    }
    // Further checking if desired. Example: valid year/month/day combo.

    if (getLine("Patient address: ", address, sizeof(address)) != OK) {
        return "Error getting address.";
    }

    sprintf(patientData, fmtString, name, age, infectionDate, address);
    return NULL;
}

int main(void) {
    char *patientPtr = malloc (50 + 3 + 10 + 50 + 1);
    char *result = getPatientData(patientPtr);
    if (result != NULL) {
        printf("*** %s\n", result);
        return 1;
    }
    printf("Got '%s'\n", patientPtr);
    return 0;
}

A sample run follows:

Patient name: Pax Diablo
Patient age: 55
Infection date (dd/mm/yyyy): 25/05/2020
Patient address: No fixed abode
Got 'Pax Diablo                                         5525/05/2020No fixed abode                                    '

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM