我对 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 来分配第一个内存地址。
先生,您提供的代码是一种不好的做法,假设它缺乏经验。即使有人可以重构它,但这对你简化它来说将是一个很好的挑战。
第一个是让任何检查它的人都能够更轻松地修复错误代码。 第二个告诉您函数的作用域,这样您就可以看到哪个函数调用了哪个函数以及哪里出现了段错误。
Valgrind 的含义
==1444== 地址 0x0 未被堆栈、分配或(最近)释放
是您试图读取 NULL 指针。先看看吧。
其中还有一些不好的实现,但到时候你就可以学习了。
这里有很多问题,但我怀疑主要是,您可能没有意识到 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 新手来说,指针可能是一个真正的问题。我可以建议你学习一下指针吗:)