I am a noob in c, and i have this code that doesnt work properly because some bad memory allcoation i make for a char** pointer. Could you please help? Thx a lot in advance. Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node_t {
struct tuple_t *tuple; //Entrada na lista
struct node_t *next; //o node seguinte da lista
};
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 */
/* 4 + 4 + 4 bytes?? */
};
char ** split_str(char [], char **, const char *);
struct node_t *node_create(void *node_data){
struct node_t *node = NULL;
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"); free(node); return NULL;}
node->tuple->fields = (char ** )malloc(strlen((char *) node_data) * sizeof(char *));
if(!node->tuple->fields){ printf("Erro ao criar o node->tuple->node_fields\n"); free(node->tuple); free(node); return NULL; }
char **array;
const char *sep=" ";
char *s = (char *)node_data;
char arr[strlen(s)];
int i = 0;
while(arr[i++]=s[i]);
array = split_str(arr,array, sep);
i = 0;
while(array[i]){
node->tuple->fields[i] = (char *)malloc((strlen(array[i])) * sizeof(char));
if(!node->tuple->fields[i]){
printf("Erro ao alocar memoria em node_create() para node->tuple->fields[i]\n");
return NULL;
}
node->tuple->fields[i] = array[i];
// printf("array[i]=%s\n",array[i]);
// printf("node->tuple->fields[i]=%s\n",node->tuple->fields[i]);
i++;
}
node->tuple->n_fields = i;
node->tuple->timestamp = 0L;
node->next = NULL;
return node;
}
char** split_str(char writablestring[],char **array, const char *sep ){
array = malloc(strlen(writablestring) + 1);
if(! array){printf("Erro ao alocar memoria para o array em split\n"); return NULL;}
char *token = strtok(writablestring, sep);
int i=0;
while(token != NULL)
{
array[i] = malloc(strlen(token)+1);
if(!array[i])
return NULL;
array[i] = token;
token = strtok(NULL, " ");
i++;
}
return array;
}
int main(int argc, char** argv)
{
void * n_data = "hello 123 ploc";
struct node_t * node = node_create(n_data);
printf("node->num_fields=%d\n", node->tuple->n_fields);
int i=0;
while( node->tuple->fields[i] ){
printf("node->tuple->fields[%d]=%s\n",i,node->tuple->fields[i]);
i++;
}
return 0;
}
End code.
Your split_str()
function returns pointers into writablestring
, which is the array arr
in node_create()
. You then copy these pointers into node->tuple->fields[i]
- but the arr
array won't exist after the node_create()
function exits - so those pointers will no longer be valid. Instead, you need to copy the returned string into the memory that you have allocated (this also shows how you can use a for()
loop in place of your while()
, and you also need to free the memory that was allocated in split_str()
):
for (i = 0; array[i]; i++) {
node->tuple->fields[i] = malloc(strlen(array[i]) + 1);
if (!node->tuple->fields[i]){
printf("Erro ao alocar memoria em node_create() para node->tuple->fields[i]\n");
return NULL;
}
strcpy(node->tuple->fields[i], array[i]);
}
free(array);
Additionally, your code assumes that the array returned by split_str()
will be terminated by a NULL
, but the function does not ensure this. The function has numerous other problems (incorrect size passed to malloc()
, memory leak caused by unnecessary malloc()
) - so you need to fix it, too:
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;
}
(Note that array
does not need to be passed as a parameter - it's being immediately overwritten anyway, so I turned it into a local variable).
Once you've done this, you might notice that there's really no reason to allocate array
in split_str()
, only to copy its contents to node->tuple->fields
and then free it. You might as well pass the array node->tuple->fields
to split_str()
and have it write directly into it. It could then return the number of strings allocated - that would look like:
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;
}
Try something like this instead:
#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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.