在结构中设置一个 const char 指针

Set a const char pointer in a struct

我正在尝试编写一个程序,我可以在其中创建令牌,使每个令牌都有一个常量类型和值。

token.h:

#ifndef TOKEN_H
#define TOKEN_H
typedef struct{
    const char *type;
    const char *value;
}token;

token *gen_token(const char *r, const char *val);

#endif

token.c:

#include <stdlib.h>
#include <string.h>
#include "lib/token.h"

token *gen_token(const char *type, const char *val){
    token o = {type, val}, *out = &o;
    return out;
}

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "lib/token.h"

int main(int argi, char *argv[]){
    const char th[] = "line", va[] = ":";

    token *t = gen_token(th, va);

    printf("(%s, %s)\n", t->type, t->value);

    return 0;
}

当我运行正常时,似乎没有错误发生,但是当valgrind查看它时,它会抱怨很多。这是我的日志:

==4086== Memcheck, a memory error detector
==4086== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4086== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4086== Command: ./a lol
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4E7FD4F: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4C2EBE2: strlen (vg_replace_strmem.c:458)
==4086==    by 0x4E80D77: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4C2EBF4: strlen (vg_replace_strmem.c:458)
==4086==    by 0x4E80D77: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4EAAEEB: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1307)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4EAAEF1: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1309)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4EAAF03: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1307)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4EAAF0D: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1309)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4C32EB3: is_overlap (vg_replace_strmem.c:137)
==4086==    by 0x4C32EB3: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4C32EB9: is_overlap (vg_replace_strmem.c:140)
==4086==    by 0x4C32EB9: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4C32EC7: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4C32ECC: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Conditional jump or move depends on uninitialised value(s)
==4086==    at 0x4C32F64: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4C32F70: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086== 
==4086== Use of uninitialised value of size 8
==4086==    at 0x4C32F7E: __GI_mempcpy (vg_replace_strmem.c:1525)
==4086==    by 0x4EAAE23: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1327)
==4086==    by 0x4E80BBA: vfprintf (vfprintf.c:1637)
==4086==    by 0x4E871F8: printf (printf.c:33)
==4086==    by 0x1087AB: main (main.c:11)
==4086==  Uninitialised value was created by a stack allocation
==4086==    at 0x108785: main (main.c:10)
==4086==  (line, :)
==4086== 
==4086== HEAP SUMMARY:
==4086==     in use at exit: 0 bytes in 0 blocks
==4086==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==4086== 
==4086== All heap blocks were freed -- no leaks are possible
==4086== 
==4086== For counts of detected and suppressed errors, rerun with: -v
==4086== ERROR SUMMARY: 36 errors from 14 contexts (suppressed: 0 from 0)

如果对我的代码提出任何帮助 and/or 批评,我将不胜感激。

函数中

token *gen_token(const char *type, const char *val){
    token o = {type, val}, *out = &o;
    return out;
}

变量out指向局部变量o,配置在函数returns之后。这纯属偶然,您可以在调用函数后读取这些值。因此关于

的警告

Uninitialised value was created by a stack allocation

相反,您需要分配内存并将值复制到其中。 注意你需要记住在退出你的程序之前释放分配的内存,特别是如果你想让 valgrind 开心:)

您正在返回变量的地址 automatic storage duration in gen_token function. For this kind of storage duration in :

The storage is allocated when the block in which the object was declared is entered and deallocated when it is exited by any means (goto, return, reaching the end).

注意: 使用您从 gen_token 函数返回的地址是 未定义的行为.

我建议您在示例中使用 opaque pointer 技术,如下所示:

token.h

#ifndef TOKEN_H
#define TOKEN_H

struct token; /* incomplete type, but you can use pointers to it */
typedef struct token token;

/* allocates memory for 'token' and initializes it */
token* gen_token(const char* r, const char* val);
/* deallocates the specified memory */
void delete_token(token* ptr);
/* returns the value of 'type' member */
const char* get_type(token* ptr);
/* returns the value of 'value' member */
const char* get_value(token* ptr);

#endif

token.c

#include <stdlib.h>
#include "token.h"

/* the 'struct token' is defined here in the source file */
struct token {
    const char* type;
    const char* value;
};

token *gen_token(const char* type, const char* val) {
    token* out = (token*)malloc(sizeof(token));
    out->type = type;
    out->value = val;
    return out;
}
void delete_token(token* ptr) {
    free(ptr);
}
const char* get_type(token* ptr) {
    return ptr == NULL ? "" : ptr->value;
}
const char* get_value(token* ptr) {
    return ptr == NULL ? "" : ptr->type;
}

在上面的示例中,gen_tokentoken 对象分配内存,初始化它,returns 分配内存块的地址。 中的这种存储时长是分配的存储时长:

The storage is allocated and deallocated on request, using dynamic memory allocation functions.

示例用法:

#include <stdio.h>
#include <stdlib.h>
#include "token.h"

int main() {
    token* t = gen_token("line", ":");
    printf("(%s, %s)\n", get_type(t), get_value(t));
    return 0;
}

还有一件重要的事情。 main 函数中的以下变量是具有自动存储持续时间的常量数组:

const char th[] = "line", va[] = ":";

您可以存储指向数组第一个元素的指针,但如果按如下方式进行,您将得到 dangling pointers:

token* create_token() {
    const char th[] = "line", va[] = ":";
    return gen_token(th, va);
} /* from this point the created 'token' object will store dangling pointers */