简体   繁体   English

C - 使用strcmp进行分段错误?

[英]C - Segmentation Fault with strcmp?

I appear to be getting a segmentation fault somewhere with the strcmp function. 我似乎在strcmp函数的某处出现了分段错误。 I'm still very new to C and I can't see why it gives me the error. 我还是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: 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

Edit: insertion code and htable struct 编辑: 插入代码和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;
    };

Thanks 谢谢

Edit: valgrind - me entering random values to add to table 编辑: valgrind - 我输入随机值添加到表

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;
}

Apart from the possibility that the values in your htable may be invalid pointers (ie, neither NULL nor a pointer to a decent C string), you have a serious problem of encountering an infinite loop if it contains neither a NULL nor the string you're looking for. 除了你的htable中的值可能是无效指针(即,既不是NULL也不是指向正确的C字符串的指针)的可能性之外,如果它既不包含NULL也不包含字符串,则会遇到严重的问题:遇到无限循环正在寻找。

For the immediate problem, try changing the code to: 对于直接问题,请尝试将代码更改为:

#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;
}

Those debug statements should give you an indication as to what's going wrong. 那些调试语句应该可以指示出现了什么问题。


Since you're getting: 既然你得到了:

inpk: -2055051140
posn: -30
cpct: 113
keyp: 0x100000001

right before the crash, it's evident that someone is passing in a bogus value for k . 在崩溃之前,很明显有人正在为k传递虚假价值。 The modulo operation on negative numbers is implementation defined in the C standard so you're getting a negative value for pos as well. 负数的模运算是在C标准中定义的实现,所以你也得到了pos的负值。 And since h->pos[-30] is going to be undefined behaviour, all bets are off. 由于h->pos[-30]将成为未定义的行为,所有投注都将被取消。

Either find and fix the code that's passing in that bogus value (probably an uninitialised variable) or protect your function by changing: 找到并修复传递伪造值的代码(可能是未初始化的变量)或通过更改以下内容来保护您的函数:

int pos = k;

into: 成:

int pos;
if ((k < 0) || (k >= h->capacity))
    k = 0;
pos = k;

at the start of your function. 在你的功能开始。 I'd actually do both but then I'm pretty paranoid :-) 我实际上都做了两件事然后我很偏执:-)


And, based on yet another update (the hash key calculation, if you generate an unsigned int and then blindly use that as a signed int , you've got a good chance of getting negative values: 并且,基于另一个更新(散列键计算,如果生成unsigned int然后盲目地将其用作signed int ,则很有可能获得负值:

#include <stdio.h>

int main (void) {
    unsigned int x = 0xffff0000U;
    int y = x;
    printf ("%u %d\n", x, y);
    return(0);
}

This outputs: 这输出:

4294901760 -65536

My suggestion is to use unsigned integers for values that are clearly meant to be unsigned. 我的建议是使用无符号整数表示明确无符号的值。

If you are on linux, try valgrind. 如果您使用的是linux,请尝试valgrind。 It can tell you about invalid accesses, memory leaks, uninitialized variables, etc. The output may seem messy and hard to read, but if you keep trying, it will reward you. 它可以告诉你无效访问,内存泄漏,未初始化的变量等。输出可能看起来很混乱,难以阅读,但如果你继续尝试,它会奖励你。 What is going on: 到底是怎么回事:

  1. build you program with -g switch to include debugging information 使用-g开关构建程序以包含调试信息
  2. run the program using valgrind: valgrind ./myprogram 使用valgrind: valgrind ./myprogram运行程序
  3. profit by reading output 通过阅读产出获利

As I said, the output may seem very messy, so maybe first try some simple program (plain empty main) to see how it looks like when everything is ok, then try to deliberately crash your program, like: 正如我所说,输出可能看起来非常混乱,所以可能首先尝试一些简单的程序(普通的空主)来看看当一切正常时它是什么样的,然后尝试故意崩溃你的程序,如:

int *bullet = 0;
*bullet = 123;

and see the output. 并看到输出。


A nice basic introduction with examples can be found here . 可以在这里找到一个很好的基本介绍和示例。


As you provided valgrind output, I would start to fix problems listed there. 当你提供valgrind输出时,我会开始修复那里列出的问题。 First the Conditional jump or move depends on uninitialised value(s) error. 首先, Conditional jump or move depends on uninitialised value(s)错误。 You can rerun valgrind with --track-origins=yes as valgrind suggests to see more details, then fix it (you don't have line numbers in the code snippets, I cannot help you more). 您可以使用--track-origins=yes重新运行valgrind,因为valgrind建议查看更多详细信息,然后修复它(您的代码片段中没有行号,我无法帮助您更多)。

./valgrind --track-origins=yes ./myprogram      #don't switch parameters!

Then the Invalid read of size 1 error means you are already accessing memory which is not yours, but reading it only, so it "doesn't mind". 然后Invalid read of size 1错误意味着您已经访问了不属于您的内存,但仅读取它,因此它“不介意”。 But it is still an error which should not happen, so fix it (if not fixed by the first error fix). 但它仍然是一个不应该发生的错误,所以修复它(如果不是由第一个错误修复修复)。

And finally, the Access not within mapped region is a write to memory which is not allocated. 最后, Access not within mapped regionAccess not within mapped region是对未分配的内存的写入。

Now try fixing the errors (in order valgrind lists them) following valgrind suggestions (like reruning it with switches). 现在尝试修复错误(按照valgrind列出的顺序)遵循valgrind建议(比如用开关重新运行它)。

好吧你没有包括围绕htable填充这个哈希表等的代码.strcmp可能是segfaulted因为你要么给它一个NULL字符串或一个字符数组没有正确结束0 ....

Is h->keys completely initialized with NULLs? h->键是否用NULL完全初始化? Else you have random pointers inside. 否则你里面有随机指针。

BTW, 顺便说一句,

h->keys[p] = (char *)malloc(strlen(item)+1);
strcpy(h->keys[p], item);

Always check the return of a function for validity if it signals an error, no matter how unlikely the error case may be. 无论错误情况多么不可能,如果它发出错误信号,请务必检查函数的返回是否有效。 malloc() returns NULL on failure. malloc()失败时返回NULL。

At first glance, my guess is that your segfault comes from p - you're never initializing that variable, so it is not guaranteed to start out at zero; 乍一看,我的猜测是你的段错误来自p - 你永远不会初始化那个变量,因此不能保证从零开始; it could start out at -123456 for all you know, and then you'd be accessing an invalid memory address. 它可以从-123456开始,你所知道的,然后你将访问一个无效的内存地址。 EDIT: Misread the do-while loop. 编辑:误读了do-while循环。 Ignore this paragraph. 忽略这一段。

At second glance, I would check if h->keys[p] is a null-terminated string - strcmp goes on reading values until it hits a zero byte; 乍一看,我会检查h->keys[p]是否是以空字符结尾的字符串 - strcmp继续读取值,直到它达到零字节为止; if there's no such byte, it can keep on going until it hits an invalid memory address. 如果没有这样的字节,它可以继续运行直到它到达无效的存储器地址。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM