为什么读取结构指针字段无效?

在Valgrind中运行该程序,它表示在结构的转换指针处存在“无效读取大小为8”。 它与calloc有关吗? 如果按原样读取它是(零)。

有一个结构(称为trie),它使用如下:

#include  #include  #include  #include  const int MAX_SIZE = 20; struct _trie { int maxNode; int nextNode; int** transition; char* fin; }; typedef struct _trie * Trie; Trie createTrie (int maxNode){ Trie trie; trie = (Trie) malloc(sizeof(Trie)); printf("size of trie: %lu, size of the struct: %lu, size of _trie: %lu\n",sizeof(trie),sizeof(Trie), sizeof(struct _trie)); trie->maxNode = maxNode; printf("maxNode = %d, size of maxNode: %lu\n",trie->maxNode,sizeof(trie->maxNode)); printf("size of nextNode : %lu, size of transition: %lu, size of fin: %lu\n", sizeof(trie->nextNode),sizeof(trie->transition),sizeof(trie->fin)); 

在这里,当valgrid尝试阅读时,它会显示“无效读取大小为8”:

  //invalid read printf("transitions points to: %p, address: %p\n",trie->transition,&trie->transition); 

来自char * fin的相同消息:

  //invalid read printf("fin points to: %p, address: %p\n",trie->fin,&trie->fin); getchar(); trie->transition = (int**)calloc(maxNode,sizeof(int*)); printf("trie->transition done.\n"); printf("transitions points to: %p, address: %p\n",trie->transition,&trie->transition); if(trie->transition == NULL){ printf("null for trie->transition\n"); exit(0); } printf("Size of transition: %lu, size of int:%lu, pointer: %p\n\n",sizeof(trie->transition),sizeof(int),trie->transition); for(int counter = 0; counter transition[counter] = calloc(UCHAR_MAX,sizeof(int)); if(trie->transition[counter] == NULL){ printf("null for trie->transition[%d]\n",counter); exit(0); } //printf("size of transition[%d]: %lu\n",counter,sizeof(trie->transition[counter])); } printf("\nFilling up trie->transition\n"); for(int counter = 0; counter < maxNode; ++counter){ for(int counter2 = 0; counter2 transition[counter][counter2] = -1; //printf("size of transition[%d][%d]: %lu, value: %d\n",counter,counter2,sizeof(trie->transition[counter]),trie->transition[counter][counter2]); } //getchar(); } return (trie); } void free_all(Trie trie){ for(int counter = 0; counter maxNode; ++counter){ free(trie->transition[counter]); } free(trie->transition); free(trie); } int main(int argc, char *argv[]){ Trie trie = createTrie(MAX_SIZE); free_all(trie); return (0); } 

Valgrind输出:

 ==3079== Memcheck, a memory error detector ==3079== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==3079== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==3079== Command: ./debug_test ==3079== size of trie: 8, size of the struct: 8, size of _trie: 24 maxNode = 20, size of maxNode: 4 size of nextNode : 4, size of transition: 8, size of fin: 8 ==3079== Invalid read of size 8 ==3079== at 0x1088AD: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== transitions points to: (nil), address: 0x5201048 ==3079== Invalid read of size 8 ==3079== at 0x1088D1: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201050 is 8 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== fin points to: (nil), address: 0x5201050 ==3079== Invalid write of size 8 ==3079== at 0x108907: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== trie->transition done. ==3079== Invalid read of size 8 ==3079== at 0x108923: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== transitions points to: 0x5201910, address: 0x5201048 ==3079== Invalid read of size 8 ==3079== at 0x10893F: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== ==3079== Invalid read of size 8 ==3079== at 0x108962: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Size of transition: 8, size of int:4, pointer: 0x5201910 ==3079== Invalid read of size 8 ==3079== at 0x108991: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== ==3079== Invalid read of size 8 ==3079== at 0x1089B9: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Filling up trie->transition ==3079== Invalid read of size 8 ==3079== at 0x108A20: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== ==3079== Invalid read of size 8 ==3079== at 0x108A84: free_all (in /projects/trie/debug_test) ==3079== by 0x108AF8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== ==3079== Invalid read of size 8 ==3079== at 0x108AB3: free_all (in /projects/trie/debug_test) ==3079== by 0x108AF8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== ==3079== ==3079== HEAP SUMMARY: ==3079== in use at exit: 0 bytes in 0 blocks ==3079== total heap usage: 24 allocs, 24 frees, 22,616 bytes allocated ==3079== ==3079== All heap blocks were freed -- no leaks are possible ==3079== ==3079== For counts of detected and suppressed errors, rerun with: -v ==3079== ERROR SUMMARY: 5167 errors from 11 contexts (suppressed: 0 from 0) 

 ==3079== Invalid read of size 8 ==3079== at 0x1088AD: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) ==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd ==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3079== by 0x108835: createTrie (in /projects/trie/debug_test) ==3079== by 0x108AE8: main (in /projects/trie/debug_test) 

这表示您的代码正在尝试从无效地址读取8字节值。

该地址createTriecreateTrie通过malloc分配的8字节块createTrie 。 换句话说,这一行:

  trie = (Trie) malloc(sizeof(Trie)); 

为什么它认为只指向8字节的内存? 因为你分配了sizeof (Trie)字节,而Trie

 typedef struct _trie * Trie; 

或者换句话说,当您打算为整个结构分配足够的内存时,为指针分配了内存。

出于这个原因,强烈建议不要隐藏typedef后面的指针。

建议修复:

 typedef struct Trie Trie; struct Trie { int maxNode; int nextNode; int** transition; char* fin; }; Trie *createTrie(int maxNode) { Trie *trie; trie = malloc(sizeof *trie); 

笔记:

  • 我们对struct Trie和(裸) Trie使用相同的名称( Trie ),因为其他任何东西都是不必要的混淆。
  • 所有指针都明显地声明为指针,带*
  • 我们不会转换malloc的返回值,因为这可能是另一个潜在的错误来源。
  • 我们使用sizeof *trie来获取trie指向的类型中的正确字节数,无论如何声明trie