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

时间:2014-04-21 14:01:10

标签: c arrays

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

阵列应该是可变大小的,即VLA。我用Google搜索并发现了一些关于创建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("");
...
}

1 个答案:

答案 0 :(得分:1)

你写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的存储。