c - realloc() C语言改变int数组中的值

标签 c malloc valgrind realloc

我尝试在每个循环中使用 realloc(),因此我只为 C 中的 int 数组使用必要的内存,但输出值已更改。尽管如此,在我的代码中使用 Valgrind 时,我得到了正确的值。

我在做 Advent of Code 2022 的第一天.

输入文件是一个 .txt 文件,如下所示:

7569
1357
10134
4696
4423
8869
3562
6597

4038
9038
1352
8005
4811
6281
3961
4023

7234
3510
7728
1569
4583
7495
3941
6015
6531
2637

我试图对数字求和并将其存储在我的数组中的特定索引中,如果有空行则增加我的索引。

给定示例输入,它应该像这样打印:

elf [0] = 47207
elf [1] = 41509 
elf [2] = 51243

我得到的:

elf [245] = 63138
elf [246] = 181168
elf [247] = 41570
elf [248] = 36264
elf [249] = 59089
elf [250] = 185061

我想要的(使用 valgrind 的结果):

elf [245] = 63138
elf [246] = 52399
elf [247] = 41570
elf [248] = 36264
elf [249] = 59089
elf [250] = 56308

我的代码:

int *read_calories(char *filename)
{
    FILE *fp = fopen(filename, "r");
    char *line = NULL;
    int i = 0;
    size_t len = 0;
    ssize_t nread;
    struct stat size;
    stat(filename, &size);
    int tab_size = 1;
    int *calories = malloc(sizeof(int) * 2);

    if (fp == NULL)
    {
        perror("Can't open file\n");
        exit(EXIT_FAILURE);
    }

    while ((nread = getline(&line, &len, fp)) != -1) 
    {
        if (nread == 1) {
            i++;
            ++tab_size;
            calories = realloc(calories, tab_size * sizeof(int));
        } else {
            calories[i] += atoi(line);
        }
    }
    calories[i + 1] = '\0';
    free(line);
    fclose(fp);

    return calories;
}

int main()
{
    int *calories = read_calories("input.txt");
    for (int i = 0; calories[i] != '\0'; i++) {
        printf("elf [%d] = %d \n", i, calories[i]);
    }
    free(calories);
    return 0;
}

最佳答案

您的卡路里读取代码中包含一些好东西,但相当困惑。 malloc()分配的数据没有归零,所以在calories[i] += atoi(line);中使用+=不是好的。您没有显示输入数据格式。

目前尚不清楚您是否必须读取一堆数字直到空白行并将总和存储在数组中(然后冲洗并重复到 EOF),或者您是否只需要从文件中读取数字并将这些存储到数组中。

每一行都有一个数字单独存储

下面的代码假设每一行都包含一个应该存储在数组中的数字。适应其他处理方式并不困难。

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

extern int *read_calories(const char *filename);

int *read_calories(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file '%s' for reading (%d: %s)\n", filename, errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    int tab_used = 0;
    int tab_size = 2;
    int *calories = malloc(sizeof(int) * tab_size);
    if (calories == NULL)
    {
        fprintf(stderr, "Failed to allocate memory (%d: %s)\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    char *line = NULL;
    size_t len = 0;
    while (getline(&line, &len, fp) != -1) 
    {
        if (tab_used == tab_size - 1)
        {
            size_t new_size = 2 * tab_size;
            void  *new_data = realloc(calories, new_size * sizeof(int));
            if (new_data == NULL)
            {
                fprintf(stderr, "Failed to allocate memory (%d: %s)\n", errno, strerror(errno));
                exit(EXIT_FAILURE);
            }
            calories = new_data;
            tab_size = new_size;
        }
        calories[tab_used++] = atoi(line);
    }
    calories[tab_used] = 0;
    free(line);
    fclose(fp);

    return calories;
}

int main(void)
{
    int *calories = read_calories("input.txt");
    assert(calories != NULL);
    for (int i = 0; calories[i] != 0; i++)
        printf("elf [%d] = %d \n", i, calories[i]);
    free(calories);
    return 0;
}

我不喜欢 perror() — 它可以完成工作并且很简单,但是相对来说很难从中获得好的信息。该代码确保数组中有一个额外的条目用于末尾的零条目。但是,它不会在数组中间发现零条目。这通常是由于 atoi() 未能转换值造成的。

我生成了一个包含 10 到 1000 之间的 10 个随机值的 input.txt 文件:

478
459
499
997
237
423
185
630
964
594

程序的输出是:

elf [0] = 478 
elf [1] = 459 
elf [2] = 499 
elf [3] = 997 
elf [4] = 237 
elf [5] = 423 
elf [6] = 185 
elf [7] = 630 
elf [8] = 964 
elf [9] = 594 

要求和的数字 block ,用空行分隔

此代码与之前的答案非常相似,但“添加到数组”代码被提取到一个函数中,因此可以使用两次。使用结构来封装数组细节可能会更好。我可能还应该使用 size_t 而不是 int 作为大小。

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

static void add_to_array(int **table, int *tab_size, int *tab_used, int value)
{
    if (*tab_used == *tab_size - 1)
    {
        size_t new_size = 2 * *tab_size;
        void  *new_data = realloc(*table, new_size * sizeof(int));
        if (new_data == NULL)
        {
            fprintf(stderr, "Failed to allocate memory (%d: %s)\n", errno, strerror(errno));
            exit(EXIT_FAILURE);
        }
        *table = new_data;
        *tab_size = new_size;
    }
    (*table)[(*tab_used)++] = value;
}

static int *read_calories(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file '%s' for reading (%d: %s)\n", filename, errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    int tab_used = 0;
    int tab_size = 2;
    int *calories = malloc(sizeof(int) * tab_size);
    if (calories == NULL)
    {
        fprintf(stderr, "Failed to allocate memory (%d: %s)\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    char *line = NULL;
    size_t len = 0;
    int current_sum = 0;
    ssize_t nread;
    while ((nread = getline(&line, &len, fp)) != -1) 
    {
        if (nread == 1)
        {
            add_to_array(&calories, &tab_size, &tab_used, current_sum);
            current_sum = 0;
        }
        else
            current_sum += atoi(line);
    }
    if (current_sum > 0)
        add_to_array(&calories, &tab_size, &tab_used, current_sum);
    calories[tab_used] = 0;
    free(line);
    fclose(fp);

    return calories;
}

int main(void)
{
    int *calories = read_calories("input.txt");
    assert(calories != NULL);
    for (int i = 0; calories[i] != 0; i++)
        printf("elf [%d] = %d \n", i, calories[i]);
    free(calories);
    return 0;
}

修改后的数据文件:

184
861
513
507
790

897
715
287
729
534
777
945

950
696
605

287
763
839
860
779

522
140
281
190
744
976

420
462
591
710
435
707
580
855
208

806
205
799

537
395

922
356
397
464
435
470
973

203
713
264

(注意末尾没有空行!)

输出:

elf [0] = 2855 
elf [1] = 4884 
elf [2] = 2251 
elf [3] = 3528 
elf [4] = 2853 
elf [5] = 4968 
elf [6] = 1810 
elf [7] = 932 
elf [8] = 4017 
elf [9] = 1180 

交叉检查结果的 Awk 脚本:

awk 'NF == 0 { print sum; sum = 0 } NF == 1 { sum += $1 } END { print sum }' input.txt

结果:

2855
4884
2251
3528
2853
4968
1810
932
4017
1180

关于c - realloc() C语言改变int数组中的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74707228/

相关文章:

C 程序获取jar文件的版本

c - 如何标记有副作用的代码?

c - malloc() 何时设置 EAGAIN 错误?

c - 为结构内的结构分配内存

c++ - Valgrind - callgrind 探查器 : How to know which function is taking more time

c - ADC dsPIC33 问题

c - 如何使控制台输出固定到位

ios - 如何在arm64 ios程序集中调用malloc

c - ocilib 的稳定性如何

c - Valgrind:在 C 中释放链接列表时,大小 8 的读取无效