0

after a long time spent trying to debug this I've come for your help. Basically in this exercise I'm trying to read the string "31|Name1;23|Name2;15|Name3" and store it in an array of struct s_perso where the | are marking the end of an age and the beginning of a name, and where the ; are marking the beginning of a new struct.

Here's the given ft_perso.h :

#include <string.h>
#ifndef FT__PERSO__H
#define FT__PERSO__H

typedef struct      s_perso
{
    char    *name;
    float   life;
    int     age;
    char    *profession;
}   
                        t_perso;

#endif

We will only use the datas age and name from this struct s_perso.

Here's my code :

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

int     numberofstructs(char *str)
{
    int         i;
    int         length;

    i = 0;
    length = 0;
    if (str[0])
        length = 0;
    else
    {
        while (str[i])
        {
            if (str[i] == ';')
                length += 1;
            i++;
        }
    }
    return (length);
}

int     get_data_length(char *str, int i)
{
    int         length;

    length = 0;
    while (str[i] != '|' && str[i] != ';' && str[i] != '\0')
    {
        length++;
        i++;
    }
    return (length);
}

char    *get_data(char *str, int i)
{
    int j;
    char    *str2;

    j = 0;
    str2 = (char *)malloc(sizeof(char) * get_data_length(str, i) + 1);
    while (str[i] != '|' && str[i] != ';' && str[i] != '\0')
    {   
        str2[j] = str[i];
        i++;
        j++;
    }
    str2[j] = '\0';
    return (str2);
}

t_perso     **ft_decrypt(char *str)
{
    int             i;
    int             j;
    t_perso         **textttt_perso;

    i = 0;
    j = 0;
    textttt_perso = (t_perso **)malloc(sizeof(t_perso **));
    *textttt_perso = (t_perso *)malloc(sizeof(t_perso *) * numberofstructs(str));
    
    while (j <= strlen(str) && str[j])
    {
        if (str[j] == ';')
        {
            i++;
            j++;
        }
        textttt_perso[i]->age = atoi(get_data(str, j));
        j = j + get_data_length(str, j) + 1;
        textttt_perso[i]->name = get_data(str, j);
        j = j + get_data_length(str, j);
    }
    textttt_perso[i+1] = 0;
    return (textttt_perso);
}

int     main(void)
{
    int i;
    t_perso **tab;
    i = 0;
    char        str[29] = "31|Name1;23|Name2;15|Name3";
    tab = ft_decrypt(str);
    while(i <= numberofstructs(str))
    {
        printf("age = %d\n", tab[i]->age);
        printf("age = %s\n", tab[i]->.name);
        i++;
    }
}

From my debugging, I get the segfault error on the second call (when i = 1 and we are working on the substring 23) instruction of t_perso **ft_decrypt(char *str) :

textttt_perso[i]->age = atoi(get_data(str, j));

My guess is that my allocation of memory either for the array of struct in itself or the number of arrays it can contain is wrong. I can't point my finger on the problem tho...

Thanks in advance for your help, have a nice day !

3
  • 1
    How do I work with dynamic multi-dimensional arrays in C? Commented Mar 11, 2021 at 17:49
  • 3
    str[i] != '|' && str[i] && ';' ugh, something not right here. That's str[i] != ';' Commented Mar 11, 2021 at 17:50
  • @KamilCuk my god can't believe I wrote that one, what a shame. The program is infinitely looping tho with that fixed, I'm trying to see where that could come from Commented Mar 11, 2021 at 18:00

1 Answer 1

2

You never allocate space for an actual structure. In your example:

textttt_perso = (t_perso **)malloc(sizeof(t_perso **));

allocates space for one pointer and:

*textttt_perso = (t_perso *)malloc(sizeof(t_perso *) * numberofstructs(str));

allocates enough space for 3 pointers. At some point you need to allocate space for the actual structures.

You also have other issues. In numberofstructs() you have if(str[0]) that will cause length to always be zero. Also in numberofstructs(), you count the semi-colons. If there is data after the last sem-colon you would need to add 1 to length.

You have many other issues in this code that will show up if the data isn't perfect but here is an implementation of ft_decrypt that should work. Initial malloc should be to hold the array of pointers. Then the loop should allocate a structure for each array entry.

t_perso** ft_decrypt(char* str)
{
  int i = 0;
  int j = 0;
  t_perso** textttt_perso;

  textttt_perso = malloc(sizeof(*textttt_perso) * numberofstructs(str));

  while (j <= strlen(str) && str[j])
  {
    if (str[j] == ';')
    {
      i++;
      j++;
    }
    textttt_perso[i] = malloc(sizeof(*textttt_perso[i]));
    textttt_perso[i]->age = atoi(get_data(str, j));
    j = j + get_data_length(str, j) + 1;
    textttt_perso[i]->name = get_data(str, j);
    j = j + get_data_length(str, j);
  }
  return (textttt_perso);
}
Sign up to request clarification or add additional context in comments.

8 Comments

Isn't that what I want to do here tho ? Allocating enough spaces for 3 t_perso * typed pointers ?
I'm not the downvoter, but there are no benefits to casting the mallocs return value, in C.
@M. Nejat Aydin I think it's done for clarity purposes. @ Jim Rhodes , care to explain how would you do that ? I absolutely have no clue how to achieve this. I tried this line : *textttt_perso = (t_perso *)malloc(sizeof(t_perso) * numberofstructs(str) + 1); but still get the segfault error.
@badakzz No, it doesn't help to the clarity. You may consider reading this
@badakzz Also, the idiomatic way to allocate n elements using malloc, simulating an array definition T a[n] where T is a type, is a = malloc(n * sizeof *a);. Then you don't need to touch the malloc line in case the type of a changes.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.