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 !

badakzz
  • 35
  • 6
  • 1
    [How do I work with dynamic multi-dimensional arrays in C?](https://stackoverflow.com/a/917824) – 001 Mar 11 '21 at 17:49
  • 3
    `str[i] != '|' && str[i] && ';'` ugh, something not right here. That's `str[i] != ';'` – KamilCuk Mar 11 '21 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 – badakzz Mar 11 '21 at 18:00

1 Answers1

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);
}
Jim Rhodes
  • 5,021
  • 4
  • 25
  • 38
  • Isn't that what I want to do here tho ? Allocating enough spaces for 3 `t_perso *` typed pointers ? – badakzz Mar 11 '21 at 18:08
  • I'm not the downvoter, but there are no benefits to casting the `malloc`s return value, in `C`. – M. Nejat Aydin Mar 11 '21 at 18:21
  • @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 Mar 11 '21 at 18:31
  • @badakzz No, it doesn't help to the clarity. You may consider reading [this](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – M. Nejat Aydin Mar 11 '21 at 18:34
  • 1
    @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. – M. Nejat Aydin Mar 11 '21 at 18:38
  • @ M. Nejat Aydin alright, thanks for that one. @Jim Rhodes I was trying to avoid allocating memory if the string was empty with that `if(str[0])` – badakzz Mar 11 '21 at 18:40
  • `What I think you need to do is move the second malloc into the for loop.` I've tried to insert the line `*textttt_perso = (t_perso *)malloc(sizeof(t_perso *);` right after the `while` and right after the `if` since I need to allocate memory in both cases, but I am still getting the same segfault error so I guess i didn't quite understand where I needed to write this line – badakzz Mar 11 '21 at 19:00
  • @Jim Rhodes alright it makes sense !! takes a lot for your time you're the man. Have a nice day – badakzz Mar 15 '21 at 14:55