首页 > 解决方案 > 使用strtok在C中为这个结构分配空间的正确方法是什么

问题描述

我有一个包含我想从数组中填充的指针的结构,两者都在下面定义。我正在使用 strtok 拆分elements数组中的字符串,然后获取各个值并将它们放入相关的结构值中。

我可以拆分字符串,但填充的值eleNum是错误的。我似乎得到了一个指针值或类似的东西。我也不确定我对 3 个字段 ( eleNum, eleSym, eleName) 的内存分配是否正确。他们为他们工作eleSymeleName但我不知道这只是运气还是为他们分配空间的正确方式。

typedef struct PTdef {
    int     *eleNum;
    char    *eleSym;
    char    *eleName;
} ptDB;

int main(void)
{
    ptDB    pt[118] = {};
    char    elements[][40] = {"1,H,Hydrogen"};
    
    char    *token;
    char    *eleDup = (char *)malloc(40);
    char    sep[] = ",";

    strcpy(eleDup, elements[0]);
    token = strtok(eleDup, sep);        

    pt[0].eleNum = malloc(sizeof(int));
    pt[0].eleSym = (char *)malloc(sizeof(token));
    pt[0].eleName = (char *)malloc(strlen(token));

    pt[0].eleNum = (int *)token;
    token = strtok(NULL, sep);
    strcpy(pt[0].eleSym, token);
    token = strtok(NULL, sep);
    strcpy(pt[0].eleName, token);

输出应该是。

pt[0].eleNum = 1.
pt[0].eleSym = H.
pt[0].eleName = Hydrogen.

标签: arrayscpointersmallocstructure

解决方案


发布的代码有几个问题,请参阅下面内联的评论。

typedef struct PTdef {
    int     *eleNum;
    char    *eleSym;
    char    *eleName;
} ptDB;

int main(void)
{
    ptDB    pt[118] = {};
    char    elements[][40] = {"1,H,Hydrogen"};

    char    *token;
    char    *eleDup = (char *)malloc(40);  // no need to cast the return of malloc
                                           // https://stackoverflow.com/questions/605845/
    char    sep[] = ",";

    strcpy(eleDup, elements[0]);
    token = strtok(eleDup, sep);           // now 'token' points to nul-terminated "1"

    pt[0].eleNum = malloc(sizeof(int));    // 'eleNum' points to a newly allocated int

    pt[0].eleSym = (char *)malloc(sizeof(token));  // allocates sizeof(char*) bytes
                                                   // typically 4 bytes in 32-bit
                                                   // or 8 bytes in 64-bit compiles
                                                   // regardless of contents of 'token'

    pt[0].eleName = (char *)malloc(strlen(token)); // allocates strlen("1") = 1 byte

    pt[0].eleNum = (int *)token;            // discards the previous value of the pointer
                                            // so it leaks the malloc(sizeof(int)) memory
                                            // and forces 'eleNum' to point to string "1"
                                            // which is not an 'int'

    token = strtok(NULL, sep);              // now 'token' points to "H"
    strcpy(pt[0].eleSym, token);            // copies nul-terminated "H"
                                            // to oversized 4- or 8-byte buffer

    token = strtok(NULL, sep);              // now 'token' points to "Hydrogen"
    strcpy(pt[0].eleName, token);           // copies nul-terminated "Hydrogen"
                                            // to 1-byte buffer, which overruns it

使其尽可能接近原始代码,以下代码将正常工作。

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

typedef struct PTdef {
    int     eleNum;                   // store value, not pointer
    char    *eleSym;
    char    *eleName;
} ptDB;

int main()
{
    ptDB    pt[118] = {};
    char    elements[][40] = {"1,H,Hydrogen"};
    
    char    *token;
    char    eleDup[40];               // no need for dynamic allocation here
    char    sep[] = ",";

    strcpy(eleDup, elements[0]);
    token = strtok(eleDup, sep);        

    pt[0].eleNum = atoi(token);       // convert string "1" to integer 1

    token = strtok(NULL, sep);
    pt[0].eleSym = strdup(token);     // or:  pt[0].eleSym = malloc(strlen(token) + 1);
                                      //      strcpy(pt[0].eleSym, token);
    token = strtok(NULL, sep);
    pt[0].eleName = strdup(token);

    printf("num %d, sym '%s', name '%s'\n", pt[0].eleNum, pt[0].eleSym, pt[0].eleName);

    free(pt[0].eleName);              // cleanup
    free(pt[0].eleSym);

    return 0;
}

留给OP填写:


推荐阅读