0

this is my first time asking a question so I might be doing something wrong, I apologize for that.

So, I did a function in C to allocate a 2D array dynamically of void** so i can cast it and use this function to create a 2D array of char or int or else if wanted. Here is the function :

    void    **ft_new_arr(size_t row, size_t col, size_t size)
    {
        void    **arr_ptr;
        int     *arr_byte;
        size_t    total_size;
        size_t    y;
    
        if (row == 0 || col == 0 || size == 0)
            return (NULL);
        total_size = (col * sizeof(void*)) + (row * col * size);
        if ((total_size - col * sizeof(void*)) != (row * col * size))
            return (NULL);
        arr_ptr = (void**)malloc(total_size);
        if (arr_ptr == NULL)
            return (NULL);
        memset(arr_ptr, 0, total_size);
        arr_byte = (int *)arr_ptr + col * sizeof(void*);
        y = 0;
        while (y < col) 
        {
            arr_ptr[y] = arr_byte + (y * (row * size));
            y++;
        }
        return (arr_ptr);
    }

The only issue I know is that I might be wasting some ram because all the rows will have the same size but I guess its not that bad.

To test it, I did a function that split a string (char *) between whitespaces (0 to 32 in ASCII) and fill my previously allocated array with one word of the string for each column. And then I did a function just to print my array.

So Here's my big split function :

static int    get_nb_words(char *str)
{
    int    i;
    int    res;

    i = 0;
    res = 0;
    while (str[i])
    {
        while (str[i] && str[i] >= 0 && str[i] <= 32)
            i++;
        if (str[i] && str[i] > 32)
        {
            while (str[i] && str[i] > 32)
                i++;
            res++;
        }
    }
    return (res);
}

static int    get_word_len(char *str)
{
    int    i;
    int    tmp;
    int    res;

    i = 0;
    tmp = 0;
    res = 0;
    while (str[i])
    {
        while (str[i] && str[i] >= 0 && str[i] <= 32)
            i++;
        if (str[i] && str[i] > 32)
        {
            tmp = 0;
            while (str[i] && str[i] > 32)
            {
                i++;    
                tmp++;
            }
            if (tmp > res)
                res = tmp;
        }
    }
    return (res);
}

static void    fill_array(char **new_arr, char *str)
{
    int    i;
    int    x;
    int    y;

    i = 0;
    x = 0;
    y = 0;
    while (str[i])
    {
        while (str[i] && str[i] >= 0 && str[i] <= 32)
            i++;
        if (str[i] && str[i] > 32)
        {
            y = 0;
            while (str[i] && str[i] > 32)
            {
                new_arr[x][y] = str[i];
                i++;
                y++;
            }
            new_arr[x][y] = '\0';
            x++;
        }
    }
}

void    ft_printab(char **new_arr, int nb_row)
{
    for (int i = 0; i < nb_row; i++)
        printf("arr[%d] = |%s|\n", i, new_arr[i]);    
}

char    **ft_split(char *str)
{
    int        nb_words;
    int        words_len;
    char    **new_arr;

    nb_words = 0;
    words_len = 0;
    if (!str)
        return (NULL);
    nb_words = get_nb_words(str);
    words_len = get_word_len(str);
    if (!nb_words || !words_len)
        return (NULL);
    new_arr = (char **)ft_new_arr(words_len, nb_words, sizeof(char));
    if (!new_arr)
        return (NULL);
    fill_array(new_arr, str);
    ft_printab(new_arr, nb_words);
    return (new_arr);
}

Here is the main btw :

int    main(int ac, char **av)
{
    if (ac != 2) 
        return (print_err("Invalid number of arguments", -1));
    char **new_arr;
    new_arr = ft_split(av[1]);
    free(new_arr);
    return (0);
}

I must say that if I don't fill or print the array, I get no error.

when I do, the array is filled like I wanted BUT valgrind gives me a lots of error :

==401691== Memcheck, a memory error detector
==401691== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==401691== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==401691== Command: ./cub3d I\ am\ a\ Fish
==401691== 
==401691== Invalid write of size 1
==401691==    at 0x109830: fill_array (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10999F: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==  Address 0x4a9f0c0 is 16 bytes inside an unallocated block of size 4,194,096 in arena "client"
==401691== 
==401691== Invalid write of size 1
==401691==    at 0x109881: fill_array (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10999F: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==  Address 0x4a9f0c1 is 17 bytes inside an unallocated block of size 4,194,096 in arena "client"
==401691== 
==401691== Conditional jump or move depends on uninitialised value(s)
==401691==    at 0x484ED19: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==401691==    by 0x48EADB0: __vfprintf_internal (vfprintf-internal.c:1517)
==401691==    by 0x48D481E: printf (printf.c:33)
==401691==    by 0x1098EF: ft_printab (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x1099B0: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691== 
==401691== Conditional jump or move depends on uninitialised value(s)
==401691==    at 0x484ED28: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==401691==    by 0x48EADB0: __vfprintf_internal (vfprintf-internal.c:1517)
==401691==    by 0x48D481E: printf (printf.c:33)
==401691==    by 0x1098EF: ft_printab (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x1099B0: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691== 
==401691== Conditional jump or move depends on uninitialised value(s)
==401691==    at 0x48FF7B7: _IO_new_file_xsputn (fileops.c:1218)
==401691==    by 0x48FF7B7: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1196)
==401691==    by 0x48EB08B: outstring_func (vfprintf-internal.c:239)
==401691==    by 0x48EB08B: __vfprintf_internal (vfprintf-internal.c:1517)
==401691==    by 0x48D481E: printf (printf.c:33)
==401691==    by 0x1098EF: ft_printab (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x1099B0: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691== 
==401691== Syscall param write(buf) points to uninitialised byte(s)
==401691==    at 0x4988A37: write (write.c:26)
==401691==    by 0x48FEF6C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1180)
==401691==    by 0x4900A60: new_do_write (fileops.c:448)
==401691==    by 0x4900A60: _IO_new_do_write (fileops.c:425)
==401691==    by 0x4900A60: _IO_do_write@@GLIBC_2.2.5 (fileops.c:422)
==401691==    by 0x48FF754: _IO_new_file_xsputn (fileops.c:1243)
==401691==    by 0x48FF754: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1196)
==401691==    by 0x48EA049: outstring_func (vfprintf-internal.c:239)
==401691==    by 0x48EA049: __vfprintf_internal (vfprintf-internal.c:1593)
==401691==    by 0x48D481E: printf (printf.c:33)
==401691==    by 0x1098EF: ft_printab (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x1099B0: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==  Address 0x4a9f0ba is 10 bytes inside a block of size 1,024 alloc'd
==401691==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==401691==    by 0x48F2C23: _IO_file_doallocate (filedoalloc.c:101)
==401691==    by 0x4901D5F: _IO_doallocbuf (genops.c:347)
==401691==    by 0x4900FDF: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:744)
==401691==    by 0x48FF754: _IO_new_file_xsputn (fileops.c:1243)
==401691==    by 0x48FF754: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1196)
==401691==    by 0x48E91CC: outstring_func (vfprintf-internal.c:239)
==401691==    by 0x48E91CC: __vfprintf_internal (vfprintf-internal.c:1263)
==401691==    by 0x48D481E: printf (printf.c:33)
==401691==    by 0x1098EF: ft_printab (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x1099B0: ft_split (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691==    by 0x10922A: main (in /mnt/nfs/homes/hlevi/42/Ghub/Cub3D/cub3d)
==401691== 
arr[0] = |I|
arr[1] = |am|
arr[2] = |a|
arr[3] = |Fish|
==401691== 
==401691== HEAP SUMMARY:
==401691==     in use at exit: 0 bytes in 0 blocks
==401691==   total heap usage: 2 allocs, 2 frees, 1,072 bytes allocated
==401691== 
==401691== All heap blocks were freed -- no leaks are possible
==401691== 
==401691== Use --track-origins=yes to see where uninitialised values come from
==401691== For lists of detected and suppressed errors, rerun with: -s
==401691== ERROR SUMMARY: 36 errors from 6 contexts (suppressed: 0 from 0)

I must be something wrong, but I've tried a lot of stuff and still can't manage to make this work, does anyone have any solution ?

Lyfmeno
  • 1
  • 1
  • 4
    A pointer to pointer is not a 2D array. That misconception is where all your problems originate. Check out [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Lundin Nov 10 '22 at 12:13
  • And you can probably replace this whole function with `int(*arr)[col] = malloc( sizeof(int[row][col]) );` – Lundin Nov 10 '22 at 12:22
  • Why do you have `int *` in `ft_new_arr()` if it is supposed to be generic? – Ian Abbott Nov 10 '22 at 12:33
  • One problem is that `int *arr_byte` should be `char *arr_byte`. Another problem is that it assumes the array element type is not more strictly aligned than `void *`. To fix that, either add an alignment size parameter or assume the alignment size is the same as the element size. Then if the alignment size is greater than the _Alignof(void *), work out how much padding is required after all the pointers in order to align the elements properly, and add that padding to the total size (and to the size of the start of the memory before the elements). – Ian Abbott Nov 10 '22 at 12:48
  • Another problem is conversion of incompatible pointer types, such as converting `void **` to `char **` and vice versa. – Ian Abbott Nov 10 '22 at 12:49

1 Answers1

0

Ok, thank's for the answer, what I was doing wrong was declaring int *arr_byte instead of int8_t* or char*.
Thank's to Ian, the padding was wrong !
Now the function works perfectly

Lyfmeno
  • 1
  • 1