为什么我的C程序不等待扫描输入?

问题描述 投票:0回答:1

我是C语言新手,我用这个语句分配了内存。

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

然后我用这个来分配数据(这是函数的一部分)。

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");

一切都很顺利 除了在 "输入病人地址 "这一行之后 "行后,它直接打印出 "添加的病人 "行,而没有等待扫描地址,输出是这样的:

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.

我分配的内存有问题吗?

c pointers dynamic-memory-allocation
1个回答
2
投票

你很可能已经使用了 calloc 来分配一些内存,但检查这个片段。

char *patientptr;

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

第一行 影子 无论如何 patientptr 是用一个未初始化的指针,因此最后一行是未定义的行为 (patientptr 现在指向某个任意的地址)。) 此时,所有的赌注都被取消了。任何 是可以的。

修正后再试。


此外,它 样子 就像你相信的那样。

*(patientptr + 51) = agestr;

是将C字符串从一个地方复制到另一个地方的方法。实际上,这将试图把C字符串的 agestr 指针 的值转化为内存位置的单个字符 &(patientptr[51])我可能应该警告你这个问题

你需要看看 strcpy 为这一点,类似的东西。

strcpy(patientptr + 51, agestr);

但是,如果你想做用户输入, 通常是一个好主意,绕过限制的问题 scanf. 它 确实如此。 毕竟,站在 "扫描格式化 "的立场上,几乎没有什么是 较少 比用户输入的格式化。

我有一个最喜欢用的函数,如下图所示,以及修改你自己的代码来使用它(同时使用该函数的 并根据你的情况做了很多其他的验证)。)

#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;
}

下面是一个运行示例。

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                                    '
© www.soinside.com 2019 - 2024. All rights reserved.