在 `realloc` 之后为指针赋值时出现分段错误

问题描述 投票:0回答:2

我对 C 非常陌生(4 天前开始,有 Python 和 Java 背景)。我尝试创建一个动态数组(python列表)来解决advent of code day 4第2部分。

own
列表和
win
列表正常工作,我不明白为什么
cardInstancesCount
只是拒绝接受在一个值中。

Valgrind 输出

==1444== Invalid write of size 4
==1444==    at 0x1097FD: main (part2.c:91)
==1444==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int is_a_num_char(char *p_char) { return (*p_char >= '0' && *p_char <= '9'); }

int extract_int(char **p_start) {
    char *p_end = *p_start;
    while (is_a_num_char(p_end)) p_end++;
    size_t length = p_end - *p_start;
    char tmp[length + 1];
    tmp[length] = '\0';
    memcpy(tmp, *p_start, length);
    *p_start = p_end;
    return (int)strtol(tmp, (char **)NULL, 10);
}

int main(int argc, char *argv[]) {
    FILE *file = fopen(argv[1], "r");
    int res = 0;
    char buffer[500];
    int tmpNum;
    int cardQuantity = 0;
    int *cardInstancesCount = NULL;

    for (int cardIdx = 0; fgets(buffer, sizeof(buffer), file); cardIdx++) {
        int *win = NULL;
        int *own = NULL;
        int winIdx = 0;
        int ownIdx = 0;
        int matchCount = 0;

        char *p_line = buffer;
        // Skip to ':'
        while (*p_line != ':') p_line++;

        // Load list of winning numbers
        for (; *p_line != '|'; p_line++) {
            if (!is_a_num_char(p_line)) {
                continue;
            }
            tmpNum = extract_int(&p_line);
            int *tmp = realloc(win, sizeof(int) * (winIdx + 1));
            if (tmp == NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            }
            win = tmp;
            win[winIdx++] = tmpNum;
        }

        // Load list of own numbers
        for (; *p_line != '\0'; p_line++) {
            if (!is_a_num_char(p_line)) {
                continue;
            }
            tmpNum = extract_int(&p_line);
            int *tmp = realloc(own, sizeof(int) * (ownIdx + 1));
            if (tmp == NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            }
            own = tmp;
            own[ownIdx++] = tmpNum;
        }

        // Check how many matchings
        for (int ownCheckIdx = 0; ownCheckIdx < ownIdx; ownCheckIdx++) {
            for (int winCheckIdx = 0; winCheckIdx < winIdx; winCheckIdx++) {
                if (own[ownCheckIdx] == win[winCheckIdx]) {
                    matchCount++;
                    break;
                }
            }
        }
        free(win);
        free(own);

        if (cardQuantity == cardIdx) {
            printf("%p\n", &cardInstancesCount);
            int *tmp =
                realloc(cardInstancesCount, sizeof(int) * (cardQuantity + 1));
            if (tmp = NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            }
            cardInstancesCount = tmp;
            printf("%p\n", &cardInstancesCount);
            cardInstancesCount[cardIdx] = 1; // Line 91
            printf("%s\n", "no");
            printf("%d",*cardInstancesCount);
        }

        // If need to expand cardQuantity
        int newCardQuantity = cardIdx + matchCount + 1;
        if (newCardQuantity > cardQuantity) {
            int *tmp =
                realloc(cardInstancesCount, sizeof(int) * newCardQuantity);
            if (tmp == NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            } else {
                cardInstancesCount = tmp;
            }

            // Initialise all 1 for new card discovery
            for (int i = cardQuantity; i < newCardQuantity; i++) {
                cardInstancesCount[i] = 1;
            }
            cardQuantity = newCardQuantity;

            // Add current instance to the cards
            for (int i = cardIdx + 1; i < newCardQuantity; i++) {
                cardInstancesCount[i] += cardInstancesCount[cardIdx];
            }
            // Set newCardQuantity
            cardQuantity = newCardQuantity;
        }
        // If no cardQuantity expansion.
        else {
            for (int i = cardIdx + 1; i < newCardQuantity; i++) {
                cardInstancesCount[i] += cardInstancesCount[cardIdx];
            }
        }
    }
    for (int i = 0; i < cardQuantity; i++) {
        printf("%d", cardInstancesCount[i]);
    }
    free(cardInstancesCount);
    printf("Res: %d\n", res);
    return 0;
}

适用于第 1 部分的代码

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int is_a_num_char(char *p_char) { return (*p_char >= '0' && *p_char <= '9'); }

int extract_int(char **p_start) {
    char *p_end = *p_start;
    while (is_a_num_char(p_end)) p_end++;
    size_t length = p_end - *p_start;
    char tmp[length + 1];
    tmp[length] = '\0';
    memcpy(tmp, *p_start, length);
    *p_start = p_end;
    return (int)strtol(tmp, (char **)NULL, 10);
}

int main(int argc, char *argv[]) {
    FILE *file = fopen(argv[1], "r");
    int res = 0;
    char buffer[500];
    int tmpNum;

    while (fgets(buffer, sizeof(buffer), file)) {
        int *win = NULL;
        int *own = NULL;
        int winIdx = 0;
        int ownIdx = 0;
        int matchCount = 0;

        char *p_line = buffer;
        while (*p_line != ':') p_line++;
        for (; *p_line != '|'; p_line++) {
            if (!is_a_num_char(p_line)) {
                continue;
            }
            tmpNum = extract_int(&p_line);
            int *tmp = realloc(win, sizeof(int) * (winIdx + 1));
            if (tmp == NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            }
            win = tmp;
            win[winIdx++] = tmpNum;
        }
        for (; *p_line != '\0'; p_line++) {
            if (!is_a_num_char(p_line)) {
                continue;
            }
            tmpNum = extract_int(&p_line);
            int *tmp = realloc(own, sizeof(int) * (ownIdx + 1));
            if (tmp == NULL) {
                printf("%s\n", "Memory Allocation Failed");
                return 1;
            }
            own = tmp;
            own[ownIdx++] = tmpNum;
        }
        for (int ownCheckIdx = 0; ownCheckIdx < ownIdx; ownCheckIdx++) {
            for (int winCheckIdx = 0; winCheckIdx < winIdx; winCheckIdx++) {
                if (own[ownCheckIdx] == win[winCheckIdx]) {
                    matchCount++;
                    break;
                }
            }
        }
        if (matchCount) {
            res += (int)pow(2, matchCount - 1);
        }
        free(win);
        free(own);
    }
    printf("Res: %d\n", res);
    return 0;
}

我尝试 valgrind,尝试打印出东西,尝试使用 malloc 而不是 null 来分配第一个内存地址。

c pointers segmentation-fault realloc
2个回答
0
投票

先生,您提供的代码是一种不好的做法,假设它缺乏经验。即使有人可以重构它,但这对你简化它来说将是一个很好的挑战。

  1. 将代码从每个“if..else”语句和“for循环”中分离出来,使它们成为独立的函数
  2. 然后在编译时使用'-fsanitize=address'标志

第一个是让任何检查它的人都能够更轻松地修复错误代码。 第二个告诉您函数的作用域,这样您就可以看到哪个函数调用了哪个函数以及哪里出现了段错误。

Valgrind 的含义

==1444== 地址 0x0 未被堆栈、分配或(最近)释放

是您试图读取 NULL 指针。先看看吧。

其中还有一些不好的实现,但到时候你就可以学习了。


0
投票

这里有很多问题,但我怀疑主要是,您可能没有意识到 C 不会像 Python 或 Java 那样初始化变量。当您声明一个变量(或指针,如本例所示)时,将为该变量分配空间,但分配空间中的内容将是未初始化/未知/随机垃圾等。

因此,对未初始化的变量调用 realloc 将产生不可预测的结果:

int *tmp = realloc(own, sizeof(int) * (ownIdx + 1));

Realloc 要求 *tmp 之前已经过 malloc(ed) 或设置为 null,如果设置为 null,realloc 将调用 malloc。

附注,代码如下:

while (*p_line != ':') p_line++;
for (; *p_line != '|'; p_line++)

如果您正在搜索的特定字符不存在,可能会导致各种问题。您应该考虑添加第二个条件检查字符串的长度,以免溢出。

对于许多 C 新手来说,指针可能是一个真正的问题。我可以建议你学习一下指针吗:)

© www.soinside.com 2019 - 2024. All rights reserved.