下标值既不是数组也不是指针也不是向量。在 C

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

问题是我从用户那里获取输入,使用 C 中的结构输入 n 个名称。我编写了以下代码:

#include<stdio.h>
typedef struct employee{ 
    int code; 
    char name[]; 
} emp; 

int main () {
    emp em; 
    int n; 
    printf ("Number of entries: "); 
    scanf ("%d", &n); 
    
    int i; 
    for (i=0;i<n;i++){ 
        printf ("Enter name: "); 
        gets(em[i].name); 
    }

    return 0; 
}

我在这段代码中遇到错误:

T2.c:16:16: 错误:下标值既不是数组也不是指针也不是向量 获取(em[i].name);

如何编写正确的代码??

我什至尝试在使用的数组和使用 scanf 函数中添加维度。似乎没有任何效果,我一次又一次地出错,

arrays c string multidimensional-array c-strings
2个回答
1
投票

这里有一些问题。首先,您定义的结构是单个

int
的大小:

typedef struct employee{ 
    int code; 
    char name[]; 
} emp; 

name
参数的大小为 0。这种定义在更高级的分配方法中很有用,我猜这有点超出你现在的技能范围。我们需要在那里提供实际尺寸:

#define MAX_NAME_LEN 128

typedef struct employee{
    int code;
    char name[MAX_NAME_LEN];
} emp;

代码中的原始错误是由于尝试访问定义的结构,就好像它是一个数组,当它是单个实例时:

emp em;

我在评论中建议的方法是为此使用

n

emp em[n];

如果您的编译器支持,这是可以的,但是,这是一种称为 VLA 的特殊数组。如果我们想避免这种情况,我们可以像对

name
参数一样做同样的事情,并提供一个大小:

#define MAX_STUDENTS 32
int main() {
   emp em[MAX_STUDENTS];

就个人而言,我什至不知道如何使用

scanf
,因为它在像这样的家庭作业之外毫无用处。我用
scanf
gets
代替了
fgets
,这是
gets
的安全哥哥。 不要使用gets。请注意,
atoi
是一个简单的字符串到 int 的转换函数。由于我们刚刚为 students 数组定义了一个最大大小,我们需要强制执行该限制,这样我们就不会超出该数组的范围进行读取:

    int n = atoi(line);
    if (n <= 0 || n > MAX_STUDENTS) {
        printf("student count %d out of range (0, %d]\n", n, MAX_STUDENTS);
        return 1;
    }

这是一个最终的解决方案,可以帮助您入门:

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

#define MAX_NAME_LEN 128
#define MAX_STUDENTS 32

typedef struct employee{
    int code;
    char name[MAX_NAME_LEN];
} emp;

int main () {
    char line[MAX_NAME_LEN];
    emp em[MAX_STUDENTS];
    printf ("Number of entries: ");
    fgets(line, MAX_NAME_LEN, stdin);

    // fgets keeps newline, so remove it.
    line[strcspn(line, "\n")] = '\0';
    int n = atoi(line);
    if (n <= 0 || n > MAX_STUDENTS) {
        printf("student count %d out of range (0, %d]\n", n, MAX_STUDENTS);
        return 1;
    }

    int i;
    for (i=0;i<n;i++){
        printf ("Enter name: ");
        fgets(em[i].name, MAX_NAME_LEN, stdin);
        em[i].name[strcspn(em[i].name, "\n")] = '\0';
    }

    return 0;
}

请注意,不包括使用这些

MAX_*
常量的更通用的解决方案将使用通过
malloc
calloc
的动态内存分配。这种解决方案将允许多个学生和他们名字的长度仅受系统可用内存量的限制。但是,根据作业猜测,您还没有接触到该主题。


0
投票

在循环中

for (i=0;i<n;i++){ 
    printf ("Enter name: "); 
    gets(em[i].name); 
}

你似乎在使用

em
就好像它是一个
n
元素的数组。但是,它不是数组。它只是一个元素。

要解决此问题,您可以将

em
定义为 可变长度数组,如下所示:

int main( void )
{
    int n;
    printf("Number of entries: ");
    scanf("%d", &n);
    emp em[n];

    [...]

然而,并不是所有的编译器都支持变长数组,ISO C 标准也没有要求编译器支持它们。

或者,您可以定义一个固定长度的数组,如下所示:

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

#define MAX_ENTRIES 20

[...]

int main( void )
{
    emp em[MAX_ENTRIES];
    int n;
    printf("Number of entries: ");
    scanf("%d", &n);

    //verify that number of entries is not so high that it would
    //overflow the buffer
    if ( n > MAX_ENTRIES )
    {
        printf( "Too many entries!\n" );
        exit( EXIT_FAILURE );
    }

    [...]

此解决方案适用于所有编译器,因为它不要求编译器支持可变长度数组。

另一个问题是在行中

gets(em[i].name); 

您有责任确保有足够的内存来存储字符串。在您的程序中,没有足够的内存来存储任何长度的字符串,因为您甚至没有为字符串的终止空字符提供足够的空间。

在声明中

typedef struct employee{ 
    int code; 
    char name[]; 
} emp; 

成员

name
是一个灵活的数组成员。如果您决定使用灵活的数组成员,那么您有责任确保在对象之后立即有额外的可用内存来存储灵活数组成员的数据。在您的程序中,您没有这样做。您可能一开始就不想使用灵活的数组成员,所以我不会进一步解释如何使用它。

为了保证

name
有足够的空间来存放字符串,可以指定一个固定数量的字符来存放字符串,例如这样:

typedef struct employee {
    int code;
    char name[100];
} emp;

但是,如果用户输入超过 100 个字符,那么您的程序将溢出数组

name
,这将调用未定义的行为。这意味着您的程序可能会以其他方式崩溃或行为不端。

为了防止这种情况,我建议您使用函数

fgets
而不是
gets
。但是请注意,与
gets
相反,
fgets
会将换行符写入字符串中,因此您可能希望将其删除。

还有一个问题是线

scanf ("%d", &n);

将在输入流中留下换行符,这将导致下一次调用

gets
/
fgets
读取空行,这不是您想要的。因此,您必须丢弃此换行符(以及该行上的任何其他剩余字符),例如:

int c;

do
{
    c = getchar();

} while ( c != '\n' && c != EOF );

这里是整个程序,不使用变长数组:

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

#define MAX_ENTRIES 20

typedef struct employee
{
    int code;
    char name[100];
} emp;

int main( void )
{
    emp em[MAX_ENTRIES];
    int n;
    int c;

    //read number of entries from user
    printf("Number of entries: ");
    scanf("%d", &n);

    //discard remainder of line
    do
    {
        c = getchar();

    } while ( c != '\n' && c != EOF );

    //verify that number of entries is not so high that it would
    //overflow the buffer
    if ( n > MAX_ENTRIES )
    {
        printf( "Too many entries!\n" );
        exit( EXIT_FAILURE );
    }

    //read individual entries from user
    for ( int i=0; i < n; i++ )
    {
        char *p;

        printf( "Enter name: " );
        fgets( em[i].name, sizeof em[i].name, stdin );

        //attempt to find the newline character
        p = strchr( em[i].name, '\n' );
        if ( p == NULL )
        {
            //since we found no newline character, we must
            //assume that the line was too long to fit into
            //the memory buffer
            printf( "Line was too long to fit into the buffer!\n" );
            exit( EXIT_FAILURE );
        }

        //remove the newline character by overwriting it with a
        //null character
        *p = '\0';
    }

    //print back the stored strings
    printf( "\nStored the following strings:\n" );
    for ( int i=0; i < n; i++ )
    {
        printf( "%s\n", em[i].name );
    }

    return EXIT_SUCCESS;
}

这个程序有以下行为:

Number of entries: 5
Enter name: Mike
Enter name: Alice
Enter name: Charlie
Enter name: Bob 
Enter name: Jimmy

Stored the following strings:
Mike
Alice
Charlie
Bob
Jimmy
© www.soinside.com 2019 - 2024. All rights reserved.