我怎么知道要为数组分配多少空间?

时间:2018-11-10 04:57:03

标签: c arrays

我正在创建一个简单的程序(下面的代码),该程序向用户询问他/她的名字,并向您问好。我只是想知道代码中的注释是否正确。我试图了解如何创建数组,以及如何为它们分配空间并处理它们,因此我们不会超出内存范围。

#include <stdio.h>

// "-" (no quotes, just the dash) means garbage values
int main() {

    char name[5];
    // name = [0] [1] [2] [3] [4] [5]
    //         -   -   -   -   -   -

    char fav_nums[5];
    // fav_nums = [0] [1] [2] [3] [4] [5]
    //             -   -   -   -   -   -

    printf("What is your name (max characters 5)?\n");
    scanf("%s\n", name);
    // I typed "Sammy" (no quotes)
    // name = [0] [1] [2] [3] [4] [5]
    //         S   a   m   m   y   \0

    printf("Hi, %s\n", name);

    printf("Enter your 5 favorite numbers!\n");
    int i = 0;
    while (i < 5) {
        scanf("%d", fav_nums[i]);
        i++;
    }
    // I typed 2 3 6 7 1
    // fav_nums = [0] [1] [2] [3] [4] [5]
    //             2   3   6   7   1   -

    fav_nums[5] = '\0';
    // fav_nums = [0] [1] [2] [3] [4] [5]
    //             2   3   6   7   1   \0


    printf("Cool, I love");
    i = 0;
    while (i < 5) {
        printf(" %d", fav_num[i]);
        i++;
    }
    printf("\n");

    return 0;
}

2 个答案:

答案 0 :(得分:2)

  

我怎么知道要在数组中分配多少空间?

让我们先看看这个名字。

好,您要输入一个上限。

printf("What is your name (max characters 5)?\n");

错误,name[5]太小,不足以作为 string (一个包含5个字符的名称)保存。 "%s"不好。输入无限制。在"%s"之后不扫描空白。它一直阻塞,直到检测到跟随非空白区域为止。检查返回值。

// bad
char name[5];
scanf("%s\n", name);

相反,name[]需要5个宪章和一个空字符的空间。

char name[5+1]; 
if (scanf("%5s", name) == 1) Success();

使用匹配的说明符和类型。一个运行良好的良好编译器会已经告诉您了,并节省了我们的所有时间。

// not 
char fav_nums[5];
scanf("%d", fav_nums[i]); // bad char,%d
// Instead 
int fav_nums[5];
scanf("%d", fav_nums[i]); // good int,%d
// or 
signed char fav_nums[5];
scanf("%hhd", fav_nums[i]); // good signed char,%hhd
// or 
unsigned char fav_nums[5];
scanf("%hhu", fav_nums[i]); // good unsigned char,%hhu
// or 
char fav_nums[5];
int num;
scanf("%d", &num); // good int,%d
fav_nums[i] = num;

更深

如果您想让代码健壮地执行此操作,则代码需要检查更多内容。

从数据存储中分离出输入。

使用fgets()来读取用户输入,从而使缓冲区至少约为预期最大需求的2倍。

然后它足够大,可以处理数据,'\n''\0'和最后的空白之间的额外的前导空格,并且可能是无信息的前导'0'数字输入。

对于2x,代码还不允许滥用和滥用超长输入。应该检测到此类输入并将其标记为具有敌意。

将数据读入缓冲区后,解析为一个名称并保存到name[]

一些伪代码

char buffer[2*sizeof name];
fgets(buffer, ...);
trim_leading_trailing_whitespace(buffer);
insure_not_too_big(buffer, sizeof name);
copy buffer to name

答案 1 :(得分:2)

除了@chux的答案,如果您想读取任意长度的行:

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

int main(void)
{
    char *name = NULL;
    size_t length = 0;
    size_t size = 0;
    size_t const buffer_growth = 10;  // +10 ... or whatever length you expect

    int ch;
    while ((ch = getchar()) != EOF && ch != '\n' && ch != '\r')
    {
        if (length + 1 >= size) {
            if(size + buffer_growth <= size)  // we reached or overflow the max
                break;                        // object size on the platform

            char *new_name = realloc(name, size += buffer_growth);
            if (!new_name) {
                free(name);
                fputs("Memory allocation failed :(\n\n", stderr);
                return EXIT_FAILURE;
            }
            name = new_name;
        }

        name[length++] = ch;
        name[length] = '\0';
    }

    printf("\"%s\"\n", name);
}
相关问题