使用while循环导致奇怪行为的数组声明

时间:2017-09-30 21:07:40

标签: c arrays segmentation-fault scanf infinite-loop

我最近在c程序中遇到了非常奇怪的行为。我掏出了大部分代码只是为了找出问题发生在你们身上的地方。

程序在当前状态下的目的是从txt文件中读取作业并将内容打印到屏幕上。这是:

#include <stdio.h>

int main(){
    char* user;
    char process;
    int arrival;
    int duration;

    scanf("%*[^\n]"); //skipping header in the file.

    while(!feof(stdin))
    {
        scanf("%s\t%c\t%d\t%d\n", user, &process, &arrival, &duration);
        printf("%s\t%c\t%d\t%d\n", user, process, arrival, duration);
    }

    int x[5]; //<----- Causing the weird behaviour
}

我输入的文件是:

User    Process Arrival Duration
Jim     A       2       5
Mary    B       2       3
Sue     D       5       5
Mary    C       6       2

我遇到的问题是每当我声明int x数组时,无论它是在我的代码的底部还是顶部,while循环进入无限循环或程序seg出错。

它将进入无限循环或seg错误,具体取决于我声明数组的大小。例如,如果我将数组声明为大小为5,则会进入无限循环。但是,如果我将数组声明为大小为2,则会出现故障。

我正在通过运行来编译我的程序:

gcc -o myprog myprog.c

我正在通过运行来管道文件:

cat jobs.txt | ./myprog

值得注意的是,如果没有int x数组声明,程序运行正常。

我完全不知道可能是什么问题,任何想法?

2 个答案:

答案 0 :(得分:2)

由于指针@import url("./fonts.css"); 未初始化,因此您的行为未定义。 main.css必须指向能够存储所需内容的内存区域(例如,请参阅user)。

答案 1 :(得分:1)

正如您从其他答案中找到的那样,您的初始问题是char *user;声明字符指针 未初始化(例如,它没有指向到任何有效的内存块)。虽然您可以使用malloccallocrealloc进行动态分配,但这可能会导致您的情况过于复杂。

您真正需要的是声明一个足以容纳用户名的字符数组。 16字符在这里绰绰有余。

下一个while (!feof(fp))几乎总是错的。 (参见我的评论中的链接)。 scanf可以返回发生的有效转化次数。在您的情况下,使用"%s..%c..%d..%d"(4个转换说明符),返回4将表示没有发生匹配输入失败。因此,不要使用feof检查,只需使用scanf返回,例如

    scanf("%*[^\n]"); //skipping header in the file.

    while (scanf ("%15s %15s %d %d", user, process, &arrival, &duration) == 4)
        printf ("%s\t%c\t%d\t%d\n", user, *process, arrival, duration);

注意:表示简化的scanf格式字符串"%15s %15s %d %d"arrival被声明为字符数组(见下文)并读作 string (利用领先的空白空间跳过)然后使用*arrival来挑选字符。这样就可以在输入<<1}时提供更健壮的方式来读取输入em>空格分隔而不是* tab分隔)

为避免在代码中使用幻数(例如16),如果您需要一个常数,则声明一个常量,例如:

#define MAXC 16

int main (void) {
    char user[MAXC] = "", process[MAXC] = "";

注意:可能看起来"%15s %15s %d %d"违反了此规则,但遗憾的是,无法在scanf 字段宽度中包含常量变量说明符可防止读取超过15个字符的数组 - 请记住,您必须为最终字符留出空间 - nul-terminatedating 字符。

完全放弃,您可以执行以下操作:

#include <stdio.h>

#define MAXC 16

int main (void) {
    char user[MAXC] = "", process[MAXC] = "";
    int arrival, duration;

    scanf("%*[^\n]"); //skipping header in the file.

    while (scanf ("%15s %15s %d %d", user, process, &arrival, &duration) == 4)
        printf ("%s\t%c\t%d\t%d\n", user, *process, arrival, duration);

    return 0;
}

示例使用/输出

$ ./bin/scanf_usr_arriv <dat/userprocarriv.txt
Jim     A       2       5
Mary    B       2       3
Sue     D       5       5
Mary    C       6       2

您可能还想考虑阅读所有&#34;输入行&#34;使用面向行的输入函数,如fgets,然后在生成的缓冲区上调用sscanf来解析每个变量。这样做的好处是允许对读取的行进行单独验证,然后对来自该行的每个变量的解析进行独立验证。

仔细看看,如果您有任何问题,请告诉我。