【问题标题】:Problem with scanf to a field in a structscanf 到结构中的字段的问题
【发布时间】:2019-09-15 09:34:00
【问题描述】:

我已经定义了一个指向结构的指针数组,当我尝试扫描到一个字段时,我收到一条错误消息,我不明白我做错了什么。

我尝试了不同的方法 - scanf("%s",arr[i]->code);scanf("%s",(*(arr+i))->code); - 它仍然不起作用。

这是我的代码的开头:

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

#define N 5

typedef struct DEPARTMENT
{
    char code[11];
    int sales;
}
department;

int main()
{
    department *arr[N];
    int i;
    printf("Enter values for %d departments:", N);
    for (i = 0; i < N; i++)
    {
        printf("\nThe %d department-", (i + 1));
        printf("\nCode:");
        scanf("%s",(arr[i])->code);
        printf("\nNumber of sales:");
        scanf("%d", &((arr[i])->sales));
    }
}

【问题讨论】:

  • “我收到一条错误消息...”您愿意分享错误消息吗?或者只是让我们猜测?
  • 建议对代码等使用正确的 SO 格式,以使您的问题/代码 sn-p 更具可读性。
  • 你有一个由 5 个指针组成的数组,它们指向任何地方或任何地方。您需要为每个人分配空间,然后才能对其进行任何设置,否则您将处于未定义的行为领域。
  • 回答问题“每个N 指针指向什么有效的内存块?”

标签: c arrays pointers struct scanf


【解决方案1】:

您的直接问题是尝试将值分配给无效的内存位置。您的声明:

    department *arr[N];

声明一个 指向 struct DEPARTMENT [N] 的指针数组(例如 5 个指向 struct 的指针)。然而,这些指针中的每一个都未初始化并指向一个不确定的内存位置。请记住,指针只是一个普通变量,它保存其他东西的地址作为它的值,就像一个普通变量一样,它在分配一个值之前保存一个不确定的值。

就像声明的任何其他局部变量一样,在值不确定时访问该值的任何尝试都会导致未定义行为。要使用指针数组,必须将每个指针的起始地址分配给有效的内存块作为其值。在这里,由于您的意图是为N 结构提供存储,因此无需声明N 指针,然后为N 结构单独分配存储。您可以简单地声明一个 指向 struct 的指针,然后在单个内存块中为 N struct 分配存储空间,例如

#define N 5
...
typedef struct {
    char code[MAXC];
    int sales;
} department;
...
    department *arr;        /* declares a pointer to struct */
    ...
    /* allocate/validate storage for N struct */
    if ((arr = malloc (N * sizeof *arr)) == NULL) {
        perror ("malloc-arr");
        return 1;
    }

注意:总是验证每次分配)

在单个块中为N 结构分配存储具有提供单个free() 以释放分配的内存块的优点。

正如您必须验证每个分配,您必须验证每个用户输入。这意味着至少,您必须验证每个都返回到scanf。但是,您使用scanf 有一个缺点。使用scanf 的输入非常脆弱,因为输入的任何变化都会导致匹配 失败,从stdin 提取字符将在匹配 失败发生时停止,离开stdin 中的冒犯角色未读 正等着下次打电话给 scanf 时再次咬你。此外,如果在有效输入之后有任何无意的字符,它们也会留在stdin 中未读。

您的选择是在每次输入后清空stdin,以确保没有剩余的违规字符,或者,更好的选择是每次使用面向行的输入函数读取完整的输入行像 fgets() 或 POSIX getline() 然后从填充的缓冲区中解析您需要的值。这有很多好处。每次输入都会读取并丢弃任何无关的字符。您还可以从能够独立验证 (1) 读取中受益; (2) 从缓冲区解析所需信息。您可以使用sscanf 解析填充缓冲区中的信息,就像使用scanfstdin 读取信息一样。

总而言之,您可以重写代码,如下所示:

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

#define N 5
#define CODESZ 12   /* if you need more than 1 constant, define them */
#define MAXC 1024   /* (don't skimp on buffer size) */

typedef struct {
    char code[MAXC];
    int sales;
} department;

int main()
{
    department *arr;        /* declares a pointer to struct */
    char buf[MAXC];         /* buffer to hold each line */
    int i, ndx = 0;

    /* allocate/validate storage for N struct */
    if ((arr = malloc (N * sizeof *arr)) == NULL) {
        perror ("malloc-arr");
        return 1;
    }

    printf("Enter values for %d departments:\n", N);
    while (ndx < N) {       /* loop until info for N departments received */
        printf ("\nThe %d department-\n  Code  : ", ndx + 1);
        if (fgets (buf, MAXC, stdin) == NULL || 
                sscanf (buf, "%11s", arr[ndx].code) != 1)
            break;
        fputs ("  Sales : ", stdout);
        if (fgets (buf, MAXC, stdin) == NULL ||
                sscanf (buf, "%d", &arr[ndx].sales) != 1)
            break;
        ndx++;
    }
    puts ("\nDepartment Sales Results:\n");
    for (i = 0; i < ndx; i++)   /* output results, free memory */
        printf ("Dept Code: %-12s   Sales: %d\n", arr[i].code, arr[i].sales);

    free (arr); /* don't forget to free what you allocate */
}

注意:使用了一个单独的索引计数器ndx,即使用户在输入后取消输入,它也提供填充的实际结构数的计数,例如 3 个部门而不是 5 个)

使用/输出示例

$ ./bin/allocstructloop
Enter values for 5 departments:

The 1 department-
  Code  : 001
  Sales : 123

The 2 department-
  Code  : 002
  Sales : 234

The 3 department-
  Code  : 003 -- this department met sales goals.
  Sales : 345

The 4 department-
  Code  : 004
  Sales : 456 -- this department exceeded sales goals.

The 5 department-
  Code  : 005 -- this department had most sales for period.
  Sales : 567

Department Sales Results:

Dept Code: 001            Sales: 123
Dept Code: 002            Sales: 234
Dept Code: 003            Sales: 345
Dept Code: 004            Sales: 456
Dept Code: 005            Sales: 567

在您输入后尝试输入额外的文本(甚至是额外的击键),看看您的代码如何响应。保持 Ctrl+C 处于就绪状态。

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

    【解决方案2】:

    尽管您确实声明了您的 department 数组,但您并没有分配每个 department 的内存。

    您可以在循环中执行此操作,在其中填充数组:

    for (i = 0; i < N; i++)
    {
        arr[i] = malloc(sizeof(department));
        /* .. */
    }
    

    cmets 中提到的更清洁的解决方案,一次分配就足够了:

    department *arr = malloc(sizeof(department) * N);
    

    不要忘记释放分配的内存并检查mallocs的返回值。

    【讨论】:

    • 注意事项不要忘记validate分配的每个块也是按顺序排列的。
    • 在这种情况下,department *arr = malloc(sizeof(department) * N); 可能会更好,因此您只需进行一次分配。
    猜你喜欢
    • 2011-08-04
    • 1970-01-01
    • 2010-11-03
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多