为什么读取结构指针字段无效? [英] Why is reading a struct pointer field invalid?

查看:79
本文介绍了为什么读取结构指针字段无效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Valgrind 中运行程序,它表示在转换时出现无效读入的8号大小"结构的指针.它和calloc有关吗?如果按原样读取,则为(nil).

Running the program in Valgrind, it says that there is an "Invalid read of size 8" at the transition pointer of the struct. It has something to do with the calloc? It is (nil) if it is read as is.

具有结构(称为trie),其用法如下:

Having a struct (called trie), it is used as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

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号读取":

Here, when valgrid tries to read, it says "Invalid read of size 8":

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

来自char * fin的相同消息:

Same message from the 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 < maxNode; ++counter){

        trie->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 < UCHAR_MAX; ++counter2){

            trie->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 < trie->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输出:

Valgrind output:

==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字节的值.

This says your code is trying to read an 8-byte value from an invalid address.

此地址紧接在通过createTrie中的malloc分配的8字节块之后.换句话说,这一行:

This address is just after an 8 byte block allocated via malloc in createTrie. In other words, this line:

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

为什么认为trie指向仅8个字节的内存?因为您分配了sizeof (Trie)个字节,而Trie

Why does it think trie points to only 8 bytes of memory? Because you allocated sizeof (Trie) bytes, and Trie is

typedef struct _trie * Trie;

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

Or on other words, you allocated memory for a pointer when you meant to allocate enough memory for a whole struct.

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

It is strongly recommended not to hide pointers behind typedefs, for exactly this reason.

建议的解决方法:

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的返回值,因为那将是另一个潜在的错误来源.
  • 无论如何声明trie,我们都使用sizeof *trie来获取trie所指向类型的正确字节数.
  • We use the same name (Trie) for both struct Trie and (bare) Trie because anything else is needlessly confusing.
  • All pointers are visibly declared as pointers, with *.
  • We don't cast the return value of malloc because that would be another potential source of errors.
  • We use sizeof *trie to get the correct number of bytes in the type trie is pointing to, no matter how trie is declared.

这篇关于为什么读取结构指针字段无效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆