c - 如何填充字符串可变大小数组?

标签 c arrays

我需要构建一个投币器应用程序。我已经写了取款和存款部分,但在项目库存创建中我无法创建解决方案。项目名称应作为字符串从键盘中获取。对应于商品的商品价格应作为 unsigned int 从键盘获取。

数组应该是可变大小的,也就是 VLA。我用谷歌搜索并找到了一些关于创建 VLA 的资源,我认为我应该使用 malloc 动态地为它们分配内存。我做不到,所以我基本上使用 BUFSIZ 创建了有限大小的数组。

在这种情况下如何使用 VLA,以及如何用字符串填充它们?

我还应该防止缓冲区溢出。这将是第二种情况。

宏和代码块:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMBER_OF_COINS 5
#define ITEM_NAME_LEN 9

...

void editorMain(void)
{
    printf("Please enter the number of items:  ");
    scanf("%u", &itemQuantity);
    printf("\n\n");

    char ** itemNames[BUFSIZ] = {0};
    unsigned int itemPrices[BUFSIZ] = {0};

    printf("Please enter the names of items:  \n");

    for (int i = 0; i < itemQuantity; ++i) {
        printf("#%d:  ", i + 1);
        gets(** itemNames[i]);
       puts("");
    }

    printf("Please enter the prices of items:  \n");

    for (int i = 0; i < itemQuantity; ++i) {
        printf("#%d:  ", i + 1);
        scanf("%u", &itemPrices[i]);
        puts("");
    }

    dispenserMain(*itemNames, itemPrices);

    return;
}

此外,程序应将项目名称和价格作为列表输出。函数 dispenserMain 执行以下操作:

void dispenserMain(char * itemNames[], unsigned int itemPrices[]) {

...

    for (counterItemNames = 1; counterItemNames <= itemQuantity; ++counterItemNames) {                //the for loop will print out the item name and prices with their correspondence.
        printf("%10u.%14s%12.2f TL\n", counterItemNames, itemNames[counterItemNames - 1], currencyConverter(itemPrices[counterItemNames - 1]));
    }

...
}

编辑(新代码):

void editorMain(void)
{
    printf("Please enter the number of items:  ");
    scanf("%u", &itemQuantity);
    printf("\n\n");

    char itemNames[itemQuantity][ITEM_NAME_LEN+1];

    memset(&itemNames, 0, sizeof(itemNames));

    printf("Please enter the names of items:  \n");

    char line[ITEM_NAME_LEN+1];

    for (int i = 0; i < itemQuantity; ++i) {
        printf("#%d:  ", i + 1);

        if (! fgets(line, sizeof(line), stdin) || !line[0])
            // abort...

            // fgets leaves the trailing newline in the input

            if (line[strlen(line)-1] == '\n') {
                line[strlen(line)-1] = 0;
            }

        snprintf(itemNames[i], ITEM_NAME_LEN+1, "%s", line);
        puts("");
    }

    unsigned int itemPrices[] = {0};

    printf("Please enter the prices of items:  \n");

    for (int i = 0; i < itemQuantity; ++i) {
        printf("#%d:  ", i + 1);
        scanf("%u", &itemPrices[i]);
        puts("");
    }

    dispenserMain(itemNames, itemPrices);

    return;
}   //end globalMenuOut

输出:

                   Welcome to CoinedDispenser!

                         Author: Buğra Ekuklu

          Contact: bugraekuklu [at] hotmail.de


  1. Dispenser
  2. Editing variables
  3. Readme

Please make a choice:  2

Please enter the number of items:  3


Please enter the names of items:  
#1:  
#2:  blabla

#3:  glagla

Please enter the prices of items:  
#1:  45

#2:  65

#3:  75

  ................... AVAILABLE ITEMS oo

         #      Item Name          Price
         =      =========         ======

         1.             
        0.45 TL
         2.       blabla
        0.65 TL
         3.       glagla
        0.75 TL

  Enter your item selection:  

分配器功能:

void dispenserMain(char (*itemNames)[ITEM_NAME_LEN+1], unsigned int itemPrices[])
{

printf("%s\n\n", "  ................... AVAILABLE ITEMS oo");
printf("%10s%15s %14s\n", "#", "Item Name", "Price");
printf("%10s%15s %14s\n", "=", "=========", "======");
puts("");

unsigned int counterItemNames = 0;   //initializing counter

for (counterItemNames = 1; counterItemNames <= itemQuantity; ++counterItemNames) {    //the for loop will be print out the item name and prices with their correspondence.
    printf("%10u.%12s%12.2f TL\n", counterItemNames, itemNames[counterItemNames - 1], currencyConverter(itemPrices[counterItemNames - 1]));
}
puts("");
...
}

最佳答案

你在哪里写 char ** itemNames[BUFSIZ] = {0}; 应该是:

char itemNames[itemQuantity][ITEM_NAME_LEN+1];

这是一个 VLA,因为它有一个维度为已知的数组 运行。通过 malloc 分配的空间不是 VLA。

不幸的是,VLA 不能有初始值设定项,所以你也会有 写:

memset(&itemNames, 0, sizeof itemNames);

如果你想动态分配这个数组,它会是:

char (*itemNames)[ITEM_NAME_LEN+1];
itemNames = calloc( itemQuantity, sizeof *itemNames );

在这两种情况下,用法都是相同的。 itemNames[i] 指定您分配的数组。

您的代码 gets(** itemNames[i]); 有两个问题;它解引用空指针,并使用 gets 函数,允许用户导致缓冲区溢出。您应该读取数组 itemNames[i],在使用我上面的建议后,它指定了您分配的存储空间。

不幸的是,在 C 中只输入一个固定长度的字符串是很尴尬的。您必须担心如果用户键入的内容超过您的行长会发生什么。如果您不太关心这些,那么:

char line[BUFSIZ];
if ( ! fgets(line, sizeof line, stdin) || !line[0] )
    // abort...

// fgets leaves the trailing newline in the input    
if ( line[strlen(line)-1] == '\n' )
    line[strlen(line)-1] = 0;

snprintf(itemNames[i], ITEM_NAME_LEN+1, "%s", line);

要调用您的函数,请执行以下操作:

 dispenserMain(itemNames, itemPrices);

函数必须是

void dispenserMain(char (*itemNames)[ITEM_NAME_LEN+1], unsigned int itemPrices[]);

如果您想使用 dispenserMain 的原始语法,那么您必须分配一个指针数组,而不是像我所描述的那样使用二维数组。在这种情况下,您将使用 char **itemNames = malloc(itemQuantity * sizeof *itemNames); 并循环遍历和 malloc 每个指针指向更多的长度存储ITEM_NAME_LEN+1

关于c - 如何填充字符串可变大小数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23198981/

相关文章:

字符转十六进制?

c - 如何在C中对单个字符执行scanf

c - 将 32 位值分配给 64 位变量并保证前 32 位在 C 中为 0 的最佳方法

c - 递归哈希代码?

java - 将所有8位二进制序列放入字符串数组Java

objective-c - 从枚举派生字符串的方法

mysql - rails 中#<MatchResult::ActiveRecord_Relation:0x0000000232e608> 的未定义方法 `updated_at'

javascript - Array.splice 在 Firefox 控制台中不起作用

Java:数组列表的二维数组?

c++ - 大型二维静态数组和 vector 的 vector 的内存使用