我在退出时使用了字节,但似乎无法确定确切位置。 (cs50, pset5)
I have bytes in use at exit but can't seem to make out where exactly. (cs50, pset5)
我刚刚完成了 cs50 pset 5 speller 代码。它还不完美和高效,但我首先想让它工作。该代码对给定词典中的文本进行拼写检查。该程序按预期运行。我在上面使用 valgrind 来检查内存泄漏,它显示以下内容
==12518== Memcheck, a memory error detector
==12518== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12518== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==12518== Command: ./speller texts/lalaland.txt
==12518==
==12518== Conditional jump or move depends on uninitialised value(s)
==12518== at 0x524A071: _IO_vfscanf (vfscanf.c:1021)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
==12518==
==12518== Use of uninitialised value of size 8
==12518== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
==12518==
==12518==
==12518== Process terminating with default action of signal 11 (SIGSEGV)
==12518== Bad permissions for mapped region at address 0x51DF0E8
==12518== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518==
==12518== HEAP SUMMARY:
==12518== in use at exit: 552 bytes in 1 blocks
==12518== total heap usage: 2 allocs, 1 frees, 4,648 bytes allocated
==12518==
==12518== 552 bytes in 1 blocks are still reachable in loss record 1 of 1
==12518== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12518== by 0x5258E49: __fopen_internal (iofopen.c:65)
==12518== by 0x5258E49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==12518== by 0x4011B1: load (dictionary.c:60)
==12518== by 0x4009B4: main (speller.c:40)
==12518==
==12518== LEAK SUMMARY:
==12518== definitely lost: 0 bytes in 0 blocks
==12518== indirectly lost: 0 bytes in 0 blocks
==12518== possibly lost: 0 bytes in 0 blocks
==12518== still reachable: 552 bytes in 1 blocks
==12518== suppressed: 0 bytes in 0 blocks
==12518==
==12518== For counts of detected and suppressed errors, rerun with: -v
==12518== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault
我是一名编码初学者,据我了解,我没有在某处释放 552 字节。下面是我的代码:
// Implements a dictionary's functionality
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 5000;
// Hash table
node *table[N];
int words = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
int x = hash(word);
node *cursor = table[x];
while (cursor != NULL)
{
if (strcasecmp (cursor->word, word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int x = 0;
for (int i = 0, n = strlen(word); i < n; i++)
{
char a;
a = toupper(word[i]);
x += a;
}
return x;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
printf("Dictionary couldn't be opened\n");
return false;
}
char *word[LENGTH + 1];
while (fscanf(file, "%s", *word) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
printf("Out of memory.\n");
return false;
}
strcpy (n->word, *word);
n->next = NULL;
int x = hash(*word);
if (table[x] == NULL)
{
table[x] = n;
}
else
{
n->next = table[x];
table[x] = n;
}
words++;
}
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return words;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
if (table[i] != NULL)
{
node *cursor = table[i];
node *tmp = table[i];
while (cursor != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
}
return true;
}
谁能帮我找出问题所在?
另请注意,我 运行 检查 50 以检查它是否工作正常但没有通过,我得到了 this result。我猜这与内存泄漏有关,但我不确定。
翻看日志,里面其实有非常有用的信息。它告诉我您正在引用一个未初始化的值。事实上,这可能会导致 SEGFAULT。这在日志中得到确认:
==12518== Process terminating with default action of signal 11 (SIGSEGV)
让我们看看如何解决这个问题。日志的相关部分是:
==12518== Conditional jump or move depends on uninitialised value(s)
==12518== at 0x524A071: _IO_vfscanf (vfscanf.c:1021)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
此日志的第一部分是回溯。它显示导致错误的函数调用顺序。在这种情况下,main
调用了 load
,后者调用了 <something>_fscanf
。回溯的其余部分用于实现 fscanf
的 libc
内的内部调用。这告诉我们 错误所在。它还告诉我 什么 错误是:程序使用了一个值而没有初始化它。
现在,让我们看一下 load
函数中的相关行:
while (fscanf(file, "%s", *word) != EOF) { ... }
其中,我可以看到 file
通过调用 fopen
并检查空值 return 来正确初始化。第二个参数是常量字符串。所以,第三个参数是有问题的。让我们看看它在哪里声明。
现在,查看上一行,您会看到 word
被声明为 char *word[]
,它是 char 指针数组 。我想您真正想要的是 指向字符数组的指针 。正确的声明应该是 char word[LENGTH + 1]
。在当前形式中,它是一个指针数组。这些指针尚未在此函数中初始化,因此实际上可能包含 LENGTH + 1
个空指针。此外,由于堆栈重用(查看堆栈帧如何工作),此数组可能包含其他随机垃圾,其中可能包括实际指针(并导致状态损坏)。事实上,这正是发生的事情。让我们回到日志:
==12518== Process terminating with default action of signal 11 (SIGSEGV)
==12518== Bad permissions for mapped region at address 0x51DF0E8
未初始化的指针保存值 0x51df0e8
,fscanf
可能试图写入此地址,但由于指针实际上无效而遇到分段错误。
最后,让我们看看日志的最后一部分:
==12518== HEAP SUMMARY:
==12518== in use at exit: 552 bytes in 1 blocks
这告诉我们一些分配的堆内存没有被释放。这是您的分段错误的结果。 malloc
已执行,但未执行相应的 free
,因为程序在其间崩溃了。
总而言之,我想强调的是,阅读和解读日志很有用,其中包含很多有用的信息。此外,我还建议您学习使用像 gdb
这样的调试器,它可以让您快速准确地识别程序中的问题,这将成为您 必不可少的 程序增长。 Bon 编码,厨师...
希望 LENGTH
在 dictionary.h
中有定义并且比文件
中的任何单词都长
char word[LENGTH + 1]; // not char *word[LENGTH + 1];
返回前记得close(file)
。
size_t table_index = x % N; //need table_index between 0 and N-1
如果更改其声明方式,请记住在开头将 table 归零。
我刚刚完成了 cs50 pset 5 speller 代码。它还不完美和高效,但我首先想让它工作。该代码对给定词典中的文本进行拼写检查。该程序按预期运行。我在上面使用 valgrind 来检查内存泄漏,它显示以下内容
==12518== Memcheck, a memory error detector
==12518== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12518== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==12518== Command: ./speller texts/lalaland.txt
==12518==
==12518== Conditional jump or move depends on uninitialised value(s)
==12518== at 0x524A071: _IO_vfscanf (vfscanf.c:1021)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
==12518==
==12518== Use of uninitialised value of size 8
==12518== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
==12518==
==12518==
==12518== Process terminating with default action of signal 11 (SIGSEGV)
==12518== Bad permissions for mapped region at address 0x51DF0E8
==12518== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518==
==12518== HEAP SUMMARY:
==12518== in use at exit: 552 bytes in 1 blocks
==12518== total heap usage: 2 allocs, 1 frees, 4,648 bytes allocated
==12518==
==12518== 552 bytes in 1 blocks are still reachable in loss record 1 of 1
==12518== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12518== by 0x5258E49: __fopen_internal (iofopen.c:65)
==12518== by 0x5258E49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==12518== by 0x4011B1: load (dictionary.c:60)
==12518== by 0x4009B4: main (speller.c:40)
==12518==
==12518== LEAK SUMMARY:
==12518== definitely lost: 0 bytes in 0 blocks
==12518== indirectly lost: 0 bytes in 0 blocks
==12518== possibly lost: 0 bytes in 0 blocks
==12518== still reachable: 552 bytes in 1 blocks
==12518== suppressed: 0 bytes in 0 blocks
==12518==
==12518== For counts of detected and suppressed errors, rerun with: -v
==12518== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault
我是一名编码初学者,据我了解,我没有在某处释放 552 字节。下面是我的代码:
// Implements a dictionary's functionality
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 5000;
// Hash table
node *table[N];
int words = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
int x = hash(word);
node *cursor = table[x];
while (cursor != NULL)
{
if (strcasecmp (cursor->word, word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int x = 0;
for (int i = 0, n = strlen(word); i < n; i++)
{
char a;
a = toupper(word[i]);
x += a;
}
return x;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
printf("Dictionary couldn't be opened\n");
return false;
}
char *word[LENGTH + 1];
while (fscanf(file, "%s", *word) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
printf("Out of memory.\n");
return false;
}
strcpy (n->word, *word);
n->next = NULL;
int x = hash(*word);
if (table[x] == NULL)
{
table[x] = n;
}
else
{
n->next = table[x];
table[x] = n;
}
words++;
}
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return words;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
if (table[i] != NULL)
{
node *cursor = table[i];
node *tmp = table[i];
while (cursor != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
}
return true;
}
谁能帮我找出问题所在?
另请注意,我 运行 检查 50 以检查它是否工作正常但没有通过,我得到了 this result。我猜这与内存泄漏有关,但我不确定。
翻看日志,里面其实有非常有用的信息。它告诉我您正在引用一个未初始化的值。事实上,这可能会导致 SEGFAULT。这在日志中得到确认:
==12518== Process terminating with default action of signal 11 (SIGSEGV)
让我们看看如何解决这个问题。日志的相关部分是:
==12518== Conditional jump or move depends on uninitialised value(s)
==12518== at 0x524A071: _IO_vfscanf (vfscanf.c:1021)
==12518== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==12518== by 0x4011FC: load (dictionary.c:67)
==12518== by 0x4009B4: main (speller.c:40)
==12518== Uninitialised value was created by a stack allocation
==12518== at 0x401194: load (dictionary.c:59)
此日志的第一部分是回溯。它显示导致错误的函数调用顺序。在这种情况下,main
调用了 load
,后者调用了 <something>_fscanf
。回溯的其余部分用于实现 fscanf
的 libc
内的内部调用。这告诉我们 错误所在。它还告诉我 什么 错误是:程序使用了一个值而没有初始化它。
现在,让我们看一下 load
函数中的相关行:
while (fscanf(file, "%s", *word) != EOF) { ... }
其中,我可以看到 file
通过调用 fopen
并检查空值 return 来正确初始化。第二个参数是常量字符串。所以,第三个参数是有问题的。让我们看看它在哪里声明。
现在,查看上一行,您会看到 word
被声明为 char *word[]
,它是 char 指针数组 。我想您真正想要的是 指向字符数组的指针 。正确的声明应该是 char word[LENGTH + 1]
。在当前形式中,它是一个指针数组。这些指针尚未在此函数中初始化,因此实际上可能包含 LENGTH + 1
个空指针。此外,由于堆栈重用(查看堆栈帧如何工作),此数组可能包含其他随机垃圾,其中可能包括实际指针(并导致状态损坏)。事实上,这正是发生的事情。让我们回到日志:
==12518== Process terminating with default action of signal 11 (SIGSEGV)
==12518== Bad permissions for mapped region at address 0x51DF0E8
未初始化的指针保存值 0x51df0e8
,fscanf
可能试图写入此地址,但由于指针实际上无效而遇到分段错误。
最后,让我们看看日志的最后一部分:
==12518== HEAP SUMMARY:
==12518== in use at exit: 552 bytes in 1 blocks
这告诉我们一些分配的堆内存没有被释放。这是您的分段错误的结果。 malloc
已执行,但未执行相应的 free
,因为程序在其间崩溃了。
总而言之,我想强调的是,阅读和解读日志很有用,其中包含很多有用的信息。此外,我还建议您学习使用像 gdb
这样的调试器,它可以让您快速准确地识别程序中的问题,这将成为您 必不可少的 程序增长。 Bon 编码,厨师...
希望 LENGTH
在 dictionary.h
中有定义并且比文件
char word[LENGTH + 1]; // not char *word[LENGTH + 1];
返回前记得close(file)
。
size_t table_index = x % N; //need table_index between 0 and N-1
如果更改其声明方式,请记住在开头将 table 归零。