C – 使用strcmp分割错误?
我似乎在strcmp函数的某处出现了分段错误。 我对C仍然很陌生,我不明白为什么它给了我错误。
int linear_probe(htable h, char *item, int k){ int p; int step = 1; do { p = (k + step++) % h->capacity; }while(h->keys[p] != NULL && strcmp(h->keys[p], item) != 0); return p; }
GDB:
Program received signal SIGSEGV, Segmentation fault. 0x0000003a8e331856 in __strcmp_ssse3 () from /lib64/libc.so.6 (gdb) frame 1 #1 0x0000000000400ea6 in linear_probe (h=0x603010, item=0x7fffffffde00 "ksjojf", k=-1122175319) at htable.c:52
编辑: 插入代码和htable结构
int htable_insert(htable h, char *item){ unsigned int k = htable_word_to_int(item); int p = k % h->capacity; if(NULL == h->keys[p]){ h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item); h->freqs[p] = 1; h->num_keys++; return 1; } if(strcmp(h->keys[p], item) == 0){ return ++h->freqs[p]; } if(h->num_keys == h->capacity){ return 0; } if(h->method == LINEAR_P) p = linear_probe(h, item, k); else p = double_hash(h, item, k); if(NULL == h->keys[p]){ h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item); h->freqs[p] = 1; h->num_keys++; return 1; }else if(strcmp(h->keys[p], item) == 0){ return ++h->freqs[p]; } return 0; }
struct htablerec{ int num_keys; int capacity; int *stats; char **keys; int *freqs; hashing_t method; };
谢谢
编辑: valgrind – 我input随机值添加到表
sdkgj fgijdfh dfkgjgg jdf kdjfg ==25643== Conditional jump or move depends on uninitialised value(s) ==25643== at 0x40107E: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== fdkjb kjdfg kdfg nfdg lkdfg oijfd kjsf vmf kjdf kjsfg fjgd fgkjfg ==25643== Invalid read of size 8 ==25643== at 0x400E0E: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== Invalid read of size 8 ==25643== at 0x400E2B: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== Invalid read of size 1 ==25643== at 0x4A06C51: strcmp (mc_replace_strmem.c:426) ==25643== by 0x400E3C: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x210 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== ==25643== Process terminating with default action of signal 11 (SIGSEGV) ==25643== Access not within mapped region at address 0x210 ==25643== at 0x4A06C51: strcmp (mc_replace_strmem.c:426) ==25643== by 0x400E3C: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== If you believe this happened as a result of a stack ==25643== overflow in your program's main thread (unlikely but ==25643== possible), you can try to increase the size of the ==25643== main thread stack using the --main-stacksize= flag. ==25643== The main thread stack size used in this run was 8388608. ==25643== ==25643== HEAP SUMMARY: ==25643== in use at exit: 1,982 bytes in 28 blocks ==25643== total heap usage: 28 allocs, 0 frees, 1,982 bytes allocated ==25643== ==25643== LEAK SUMMARY: ==25643== definitely lost: 0 bytes in 0 blocks ==25643== indirectly lost: 0 bytes in 0 blocks ==25643== possibly lost: 0 bytes in 0 blocks ==25643== still reachable: 1,982 bytes in 28 blocks ==25643== suppressed: 0 bytes in 0 blocks ==25643== Rerun with --leak-check=full to see details of leaked memory ==25643== ==25643== For counts of detected and suppressed errors, rerun with: -v ==25643== Use --track-origins=yes to see where uninitialised values come from ==25643== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 6 from 6) Segmentation fault (core dumped)
static unsigned int htable_word_to_int(char *word){ unsigned int result = 0; while(*word != '\0'){ result = (*word++ + 31 * result); } return result; }
除了你的htable
中的值可能是无效指针(即既不是NULL也不是指向正常的Cstring的指针)的可能性之外,如果它不包含NULL或string,则会遇到无限循环的严重问题,重新寻找。
对于眼前的问题,请尝试将代码更改为:
#define FLUSH fflush (stdout); fsync (fileno (stdout)) int linear_probe (htable h, char *item, int k) { int pos = k; do { pos = (pos + 1) % h->capacity; printf ("========\n"); FLUSH; printf ("inpk: %d\n", k); FLUSH; printf ("posn: %d\n", pos); FLUSH; printf ("cpct: %d\n", h->capacity); FLUSH; printf ("keyp: %p\n", h->keys[pos]); FLUSH; printf ("keys: '%s'\n", h->keys[pos]); FLUSH; printf ("item: '%s'\n", item); FLUSH; printf ("========\n"); FLUSH; } while ((pos != k) && (h->keys[pos] != NULL) && (strcmp (h->keys[pos], item) != 0)); return pos; }
这些debugging语句应该给出一个错误信息。
既然你得到了:
inpk: -2055051140 posn: -30 cpct: 113 keyp: 0x100000001
就在崩溃之前,很明显有人正在为k
传递一个虚假的值。 在负数上的模运算是在C标准中定义的,所以你也得到pos
的负值。 而且由于h->pos[-30]
将会是不确定的行为,所有的投注都closures。
要么find并修复通过这个假的值(可能是一个未初始化的variables)的代码,要么通过改变来保护你的函数:
int pos = k;
成:
int pos; if ((k < 0) || (k >= h->capacity)) k = 0; pos = k;
在你的function开始。 我实际上都做,但后来我很偏执:-)
而且,基于另一个更新(哈希键计算,如果您生成一个unsigned int
,然后盲目地使用它作为一个有符号int
,你有一个很好的机会得到负值:
#include <stdio.h> int main (void) { unsigned int x = 0xffff0000U; int y = x; printf ("%u %d\n", x, y); return(0); }
这输出:
4294901760 -65536
我的build议是使用无符号整数的值显然是无符号的。
如果你在linux上,试试valgrind。 它可以告诉你无效的访问,内存泄漏,未初始化的variables等。输出可能看起来凌乱,难以阅读,但如果你继续尝试,它会奖励你。 到底是怎么回事:
- 使用
-g
开关构build您的程序以包含debugging信息 - 使用valgrind:
valgrind ./myprogram
运行程序 - 利润通过阅读输出
正如我所说,输出可能看起来非常混乱,所以也许首先尝试一些简单的程序(纯空主),看看一切正常后的样子,然后尝试故意地使程序崩溃,如:
int *bullet = 0; *bullet = 123;
并看到输出。
有关示例的一个很好的基本介绍可以在这里find。
当你提供valgrind输出时,我将开始修复那里列出的问题。 首先, Conditional jump or move depends on uninitialised value(s)
错误。 你可以用--track-origins=yes
重新运行valgrind,因为valgrindbuild议看到更多的细节,然后修复它(你没有代码片段中的行号,我不能帮你更多)。
./valgrind --track-origins=yes ./myprogram #don't switch parameters!
然后Invalid read of size 1
错误意味着你已经访问了不是你自己的内存,而只是阅读它,所以它“不介意”。 但它仍然是一个不应该发生的错误,所以修复它(如果不是由第一个错误修复修复)。
最后, Access not within mapped region
的Access not within mapped region
不是分配给内存的写入。
现在尝试修复错误(按照valgrind列出它们)遵循valgrind的build议(如重新运行开关)。
以及你没有包括围绕填充这个哈希表等的周围的代码。strcmp可能segfaulted,因为你给它一个NULLstring或一个字符数组不正确结束0 ….
h->键是否用NULL完全初始化? 否则你里面有随机指针。
顺便说一句,
h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item);
无论错误发生的可能性如何,总是检查函数返回是否有错误。 malloc()
在失败时返回NULL。
乍一看,我的猜测是,你的段错误来自p
– 你永远不会初始化这个variables,所以不能保证从零开始。 你可以从-123456
开始,然后你将访问一个无效的内存地址。 编辑:误读做,而循环。 忽略这一段。
乍看之下,我会检查h->keys[p]
是否是一个以null结束的string – strcmp
继续读取值,直到它遇到一个零字节; 如果没有这样的字节,它可以继续前进,直到遇到无效的内存地址。