动态分配结构数组C

时间:2017-01-05 21:57:08

标签: c arrays pointers struct malloc

我正在尝试在c中创建一个结构数组,但我无法使它工作。当我尝试运行它时,程序崩溃了。

typedef struct{
    char name[20];
    char manufacturer[20];
    unsigned int price;
} product;

unsigned int stringToNr(char *numbers){
   unsigned int nr = 0; 
   unsigned int i; 
   for (i = 0; i < strlen(numbers); i ++)
   {
       nr  *= 10; nr += numbers[i] - '0'; 
   }
   return nr; 
} 

我有一个将列表打印到文件的函数,有时它会到达此函数,有时它会崩溃。

void printList(product *products, unsigned int nr){
    unsigned int i;
    FILE *f;
    f = fopen("output.txt", "w");
    for (i = 0; i < nr; i ++){
        fprintf(f, "%s ", products[i].name);
        fprintf(f, "%s ", products[i].manufacturer);
        fprintf(f, "%d\n", products[i].price);
    }
    fclose(f);
}

我必须使用单独的函数从文件中读取列表。

void readList(product **products, unsigned int *nr){
    FILE *f;
    f = fopen("input.txt", "r");
    char *row;
    row = malloc(sizeof(char) * 45);
    unsigned int rowLength;
    fgets(row, 45, f);
    rowLength = strlen(row);
    if (row[rowLength - 1] == '\n'){
        rowLength--;
        row[rowLength ] = '\0';
    }
    *nr = stringToNr(row);
    products = malloc((*nr) * sizeof(product*));
    unsigned int i;
    char *rowElement;
    for (i = 0; i < *nr; i ++){
        fgets(row, 45, f);
        rowElement = strtok(row, " ");
        strcpy((*products)[i].name, rowElement);
        rowElement = strtok(NULL, " ");
        strcpy((*products)[i].manufacturer, rowElement);
        rowElement = strtok(NULL, " ");
        rowLength = strlen(row);
        if (row[rowLength- 1] == '\n'){
            rowLength--;
            row[rowLength] = '\0';
        }
        (*products)[i].price = stringToNr(rowElement);
    }
    free(row);
    fclose(f);
}

显然该程序有更多功能,但这些功能正常。

int main(){
    product *products;
    unsigned int nr;
    readList(&products, &nr);
    printList(products, nr);
    free(products);
    return 0;
}

我的输入文件如下所示:

   3
   AAA FactoryA 300
   BBB FactoryC 550
   ZZZ Factory5 100

1 个答案:

答案 0 :(得分:4)

代码忽略products的值。

readList()来自products的{​​{1}}收到的内容会被malloc()电话覆盖。

void readList(product **products, unsigned int *nr){
    ...
    // bad
    products = malloc((*nr) * sizeof(product*));

相反,请使用*products。也可以通过引用变量的大小来分配,而不是按类型的大小来分配。更容易编码,审查和维护。

    *products = malloc(sizeof *(*products) * (*nr));
    if (*products == NULL) Handle_OOM();

轻微:在fgets(row, ..., ...);之后,对于黑客利用读取初始空字符的行为不安全。

    rowLength = strlen(row);
    // What happens when rowLength == 0
    if (row[rowLength- 1] == '\n'){
      ...

相反,代码可以使用以下内容来删除可选的尾随'\n'

    row[strcspn(row, "\n")] = '\0';