C 指针到指针内存分配

C 指针到指针内存分配,c,memory,allocation,C,Memory,Allocation,我是c语言中的noob,我有一段代码不能正常工作,因为我为char**指针做了一些坏的内存操作。你能帮忙吗?提前很多时间。 代码: #包括 #包括 #包括 结构节点{ struct tuple\u t*tuple;//Entrada na lista struct node\u t*next;//o node seguinte da lista }; 结构元组{ 长时间戳;/*criacao do tuplo实例*/ int n_字段;/*numero de campos deste tuplo

我是c语言中的noob,我有一段代码不能正常工作,因为我为char**指针做了一些坏的内存操作。你能帮忙吗?提前很多时间。 代码:

#包括
#包括
#包括
结构节点{
struct tuple\u t*tuple;//Entrada na lista
struct node\u t*next;//o node seguinte da lista
};
结构元组{
长时间戳;/*criacao do tuplo实例*/
int n_字段;/*numero de campos deste tuplo*/
字符**字段;/*数组com campos do tuplo*/
/*4+4+4字节*/
};
字符**拆分字符(字符[],字符**,常量字符*);
结构节点*node\u创建(void*node\u数据){
结构节点*node=NULL;
node=(struct node_t*)malloc(sizeof(struct node_t));
如果(!节点){
printf(“Erro ao criar um节点!\n”);
返回NULL;
}
node->tuple=(struct tuple_t*)malloc(sizeof(struct tuple_t));
if(!node->tuple){printf(“Erro ao criar o node->tuple\n”);free(node);返回NULL;}
node->tuple->fields=(char**)malloc(strlen((char*)node_data)*sizeof(char*);
如果(!node->tuple->fields){printf(“Erro ao criar o node->tuple->node_fields\n”);free(node->tuple);free(node);返回NULL;}
字符**数组;
const char*sep=“”;
char*s=(char*)节点_数据;
char arr[strlen(s)];
int i=0;
而(arr[i++]=s[i]);
array=split_str(arr,array,sep);
i=0;
while(数组[i]){
节点->元组->字段[i]=(char*)malloc((strlen(array[i]))*sizeof(char));
如果(!节点->元组->字段[i]){
printf(“Erro ao alocar memoria em node_create()para node->tuple->fields[i]\n”);
返回NULL;
}
节点->元组->字段[i]=数组[i];
//printf(“数组[i]=%s\n”,数组[i]);
//printf(“节点->元组->字段[i]=%s\n”,节点->元组->字段[i]);
i++;
}
节点->元组->n_字段=i;
节点->元组->时间戳=0L;
节点->下一步=空;
返回节点;
}
字符**split_str(字符可写字符串[],字符**数组,常量字符*sep){
数组=malloc(strlen(writeablestring)+1);
if(!array){printf(“Erro ao alocar memoria para o array em split\n”);返回NULL;}
char*token=strtok(可写字符串,sep);
int i=0;
while(令牌!=NULL)
{
数组[i]=malloc(strlen(令牌)+1);
如果(!数组[i])
返回NULL;
数组[i]=令牌;
令牌=strtok(空,“”);
i++;
}
返回数组;
}
int main(int argc,字符**argv)
{
void*n_data=“hello 123 ploc”;
结构节点*node=node\u创建(n\u数据);
printf(“节点->num\u字段=%d\n”,节点->元组->n\u字段);
int i=0;
而(节点->元组->字段[i]){
printf(“节点->元组->字段[%d]=%s\n”,i,节点->元组->字段[i]);
i++;
}
返回0;
}
结束代码。

您的
split_str()
函数返回指向
可写字符串的指针,该字符串是
节点创建()中的数组
arr
。然后将这些指针复制到
node->tuple->fields[i]
-但是
arr
数组在
node\u create()
函数退出后将不存在-因此这些指针将不再有效。相反,您需要将返回的字符串复制到已分配的内存中(这还显示了如何使用
for()
循环代替
while()
,并且您还需要释放在
split_str()
中分配的内存):

此外,您的代码假定由
split_str()
返回的数组将由
NULL
终止,但函数不能确保这一点。该函数还有许多其他问题(传递到
malloc()
的大小不正确,不必要的
malloc()
导致内存泄漏)-因此您也需要修复它:

char **split_str(char writablestring[], const char *sep)
{
    char **array = malloc(strlen(writablestring) * sizeof array[0]);

    if(!array) {
        printf("Erro ao alocar memoria para o array em split\n");
        return NULL;
    }

    char *token = strtok(writablestring, sep);
    int i;

    for (i = 0; (array[i] = token) != NULL; i++) {
        token = strtok(NULL, " ");
    }

    return array;
}
(请注意,
array
不需要作为参数传递-无论如何它都会被立即覆盖,所以我将其转换为局部变量)


完成此操作后,您可能会注意到,实际上没有理由在
split_str()
中分配
array
,而只是将其内容复制到
节点->元组->字段,然后释放它。您还可以将数组
节点->元组->字段
传递给
split\u str()
,并将其直接写入其中。然后,它可以返回分配的字符串数-如下所示:

int split_str(char [], char **, const char *);

struct node_t *node_create(void *node_data)
{
    struct node_t *node = NULL;
    char *s = node_data;
    size_t slen = strlen(s);

    node = malloc(sizeof *node);
    if (!node) {
        printf("Erro ao criar um node!\n");
        return NULL;
    }

    node->tuple = malloc(sizeof *node->tuple);
    if (!node->tuple) {
        printf("Erro ao criar o node->tuple\n");
        free(node);
        return NULL;
    }

    node->tuple->fields = malloc(slen * sizeof node->tuple->fields[0]);
    if (!node->tuple->fields) {
        printf("Erro ao criar o node->tuple->node_fields\n");
        free(node->tuple);
        free(node);
        return NULL;
    }

    char arr[slen + 1];
    strcpy(arr, s);

    int i = split_str(arr, node->tuple->fields, " ");

    node->tuple->n_fields = i;
    node->tuple->timestamp = 0L;
    node->next = NULL;

    return node;
}

int split_str(char writablestring[], char **array, const char *sep)
{
    char *token = strtok(writablestring, sep);
    int i;

    for (i = 0; token != NULL; i++) {
        array[i] = malloc(strlen(token) + 1);
        if (!array[i]) {
            printf("Erro ao criar o array[i]\n");
            break;
        }
        strcpy(array[i], token);
        token = strtok(NULL, " ");
    }

    return i;
}
函数的
split\u str()
返回指向
writeablestring
的指针,该字符串是
节点创建()中的数组
arr
。然后将这些指针复制到
node->tuple->fields[i]
-但是
arr
数组在
node\u create()
函数退出后将不存在-因此这些指针将不再有效。相反,您需要将返回的字符串复制到已分配的内存中(这还显示了如何使用
for()
循环代替
while()
,并且您还需要释放在
split_str()
中分配的内存):

此外,您的代码假定由
split_str()
返回的数组将由
NULL
终止,但函数不能确保这一点。该函数还有许多其他问题(传递到
malloc()
的大小不正确,不必要的
malloc()
导致内存泄漏)-因此您也需要修复它:

char **split_str(char writablestring[], const char *sep)
{
    char **array = malloc(strlen(writablestring) * sizeof array[0]);

    if(!array) {
        printf("Erro ao alocar memoria para o array em split\n");
        return NULL;
    }

    char *token = strtok(writablestring, sep);
    int i;

    for (i = 0; (array[i] = token) != NULL; i++) {
        token = strtok(NULL, " ");
    }

    return array;
}
(请注意,
array
不需要作为参数传递-无论如何它都会被立即覆盖,所以我将其转换为局部变量)


完成此操作后,您可能会注意到,实际上没有理由在
split_str()
中分配
array
,而只是将其内容复制到
节点->元组->字段,然后释放它。您还可以将数组
节点->元组->字段
传递给
split\u str()
,并将其直接写入其中。然后,它可以返回分配的字符串数-如下所示:

int split_str(char [], char **, const char *);

struct node_t *node_create(void *node_data)
{
    struct node_t *node = NULL;
    char *s = node_data;
    size_t slen = strlen(s);

    node = malloc(sizeof *node);
    if (!node) {
        printf("Erro ao criar um node!\n");
        return NULL;
    }

    node->tuple = malloc(sizeof *node->tuple);
    if (!node->tuple) {
        printf("Erro ao criar o node->tuple\n");
        free(node);
        return NULL;
    }

    node->tuple->fields = malloc(slen * sizeof node->tuple->fields[0]);
    if (!node->tuple->fields) {
        printf("Erro ao criar o node->tuple->node_fields\n");
        free(node->tuple);
        free(node);
        return NULL;
    }

    char arr[slen + 1];
    strcpy(arr, s);

    int i = split_str(arr, node->tuple->fields, " ");

    node->tuple->n_fields = i;
    node->tuple->timestamp = 0L;
    node->next = NULL;

    return node;
}

int split_str(char writablestring[], char **array, const char *sep)
{
    char *token = strtok(writablestring, sep);
    int i;

    for (i = 0; token != NULL; i++) {
        array[i] = malloc(strlen(token) + 1);
        if (!array[i]) {
            printf("Erro ao criar o array[i]\n");
            break;
        }
        strcpy(array[i], token);
        token = strtok(NULL, " ");
    }

    return i;
}

请尝试以下方法:

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


struct tuple_t
{ 
    long timestamp; /* instante de criacao do tuplo*/ 
    int n_fields; /* numero de campos deste tuplo */ 
    char** fields; /* array com campos do tuplo */ 
}; 

struct node_t
{ 
    struct tuple_t* tuple; //Entrada na lista 
    struct node_t* next; //o node seguinte da lista 
}; 


char** split_str(const char *, const char *, int *); 
void node_destroy(struct node_t*);

struct node_t* node_create(char* node_data)
{ 
    struct node_t* node = (struct node_t *) malloc(sizeof(struct node_t)); 
    if(!node)
    { 
        printf("Erro ao criar um node!\n"); 
        return NULL; 
    } 

    node->tuple = (struct tuple_t *) malloc(sizeof(struct tuple_t));
    if(!node->tuple)
    {
        printf("Erro ao criar o node->tuple\n");
        node_destroy(node);
        return NULL;
    } 

    node->tuple->timestamp = 0L; 

    node->tuple->fields = split_str(node_data, " ", &(node->tuple->n_fields));
    if(!node->tuple->fields)
    {
        printf("Erro ao criar o node->tuple->node_fields\n");
        node_destroy(node);
        return NULL;
    } 

    node->next = NULL; 

    return node; 
} 

void node_destroy(struct node_t* node)
{
    if(node)
    {
        if(node->tuple)
        {
            if(node->tuple->fields)
            {
                for(int i = 0; i < node->tuple->n_fields; ++i)
                    free(node->tuple->fields[i]);

                free(node->tuple->fields);
            }

            free(node->tuple);
        }

        free(node);
    }
}

char** split_str(const char* str, const char* sep, int* found)
{ 
    if (found) *found = 0;

    int len = strlen(str);

    char** array = (char**) malloc(len * sizeof(char*));
    if(!array)
    {
        printf("Erro ao alocar memoria para o array em split\n");
        return NULL;
    }

    ++len;

    char* writablestring = (char*) malloc(len); 
    if(!array)
    {
        printf("Erro ao alocar memoria para writeablestring em split\n");
        free(array);
        return -1;
    } 

    strncpy(writablestring, str, len);

    char* token = strtok(writablestring, sep); 
    int i = 0;

    while(token)
    { 
        len = strlen(token) + 1;

        array[i] = (char*) malloc(len);
        if(!array[i]) 
        {
            printf("Erro ao alocar memoria para o array item em split\n");

            free(writeablestring);
            for(int j = 0; j < i; ++j)
                free(array[j]);
            free(array);
            return NULL;
        }

        strncpy(array[i], token, len); 
        ++i;

        token = strtok(NULL, sep);
    } 

    free(writeablestring);

    if(found) *found = i;
    return array; 
} 


int main(int argc, char** argv) 
{ 
    char* n_data = "hello 123 ploc"; 

    struct node_t* node = node_create(n_data); 
    if(node)
    {
        printf("node->tuple->n_fields=%d\n", node->tuple->n_fields);

        for(int i = 0; i < node->tuple->n_fields; ++i)
            printf("node->tuple->fields[%d]=%s\n", i, node->tuple->fields[i]);

        node_destroy(node);
    }

    return 0; 
} 
#包括
#包括
#包括
结构元组
{ 
长时间戳;/*criacao do tuplo瞬间*/
int n_字段;/*目的地编号*/
字符**字段;/*数组