我try 在每个循环中使用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个介于input.txtinput.txt0之间的随机值的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 

要求和的数字块,由空行分隔

这段代码紧密地基于前面的答案,但是"添加到数组"代码被提取到一个函数中,因此它可以被使用两次.使用 struct 来封装数组详细信息可能更好.我可能也应该用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++相关问答推荐

无效使用未定义类型'structsquare'?

GCC:try 使用—WError或—pedantic using pragmas

为什么GCC可以调用未定义的函数?

如何在C中从函数返回指向数组的指针?

为什么在此程序中必须使用Volatile关键字?

为什么C语言允许你使用var =(struct NAME){

C语言中的strstr问题

使用TCL C API导航到列表中的元素

接受任何参数的函数指针是否与接受不同参数的函数兼容

可变宏不能编译

为什么编译器不能简单地将数据从EDI转移到EAX?

C-try 将整数和 struct 数组存储到二进制文件中

C++中PUTS函数的返回值

向左移位3如何得到以字节为单位的位数?

可以';t从A9G模块拨打电话

使用 c 中的 write() 函数将非 ASCII 字符写入标准输出

这些表达式是否涉及 C 中定义的复合文字?

const struct 成员的 typedef 中的灵活数组大小

多行表达式:C 编译器如何处理换行符?

获取 struct 中匿名 struct 的大小