SaltyGiampy
SaltyGiampy

Reputation: 95

Create a 2d array of strings using dynamically allocation in c

I have to store some strings given in the args of a c code. I iterate over them but I can't store them properly because I don't know the length of those and neither their number. The better method should be a 2d array of pointers, so I can dynamically allocate memory for every new string. The problem is that I'm new on c and I have a lot of confusion about that technique. I tried to initialize a double pointer and use a function to insert elements, it allocates space for another column(new string) and set the length(size of string).

char** files;
int files_i=0;

void insert(char** root,char[] str)
{
    root=(char **)malloc(sizeof(char *));
    root[files_i]=(char *)malloc(sizeof(char)*sizeof(str));
    root[files_i*sizeof(str)]=str;
    i++;
} 

I pass to the function the double pointer and the string I need to "append". It's not working and I have also really big doubts on how to iterate over that...

Upvotes: 1

Views: 1149

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311068

What you need is the following

char **files = NULL;
size_t files_i = 0;

//...

int insert( char ***root, const char str[], size_t i )
{
    char *p = malloc( strlen( str ) + 1 );

    int success = p != NULL;

    if ( success )
    {
        char **tmp = realloc( *root, ( i + 1 ) * sizeof( char * ) );

        if ( success )
        {
            strcpy( p, str );
            tmp[i] = p;
            *root = tmp;
        }
        else
        {
            free( p );
        }
    }

    return success;
}

and then in the caller you can write for example

if ( insert( &files, some_string, files_i ) ) ++files_i;

Here is a demonstrative program.

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

int insert( char ***root, const char str[], size_t i )
{
    char *p = malloc( strlen( str ) + 1 );

    int success = p != NULL;

    if ( success )
    {
        char **tmp = realloc( *root, ( i + 1 ) * sizeof( char * ) );

        if ( success )
        {
            strcpy( p, str );
            tmp[i] = p;
            *root = tmp;
        }
        else
        {
            free( p );
        }
    }

    return success;
}

int main(void) 
{
    char **files = NULL;
    size_t files_i = 0;

    if ( insert( &files, "Hello", files_i ) ) ++files_i; 
    if ( insert( &files, "World", files_i ) ) ++files_i; 

    for ( size_t i = 0; i < files_i; i++ )
    {
        puts( files[i] );
    }

    for ( size_t i = 0; i < files_i; i++ )
    {
        free( files[i] );
    }
    free( files );

    return 0;
}

Its output is

Hello
World

Upvotes: 2

Hitokiri
Hitokiri

Reputation: 3699

  1. use strlen(str) instead of sizeof(str) for calculating the string length.
root[files_i]= malloc(strlen(str) + 1); // +1 for null character at the end of the string
if(!root[file_i]) {return;}
  1. if you want to copy string, use strcpy instead of using = operator. Or use strdup (if you use strdup, you do not need to allocate memory for character pointer).
strcpy(root[files_i],str); // copy string str to "file_i" position of array root
  1. if you use the global counter file_i, you should use realloc for root, because the size of root has to be vary (i think it's typo, the i++ should change to file_i++ ?).
root= realloc(root, sizeof(char *) * (file_i + 1));
// do not forget to check the return value of malloc or realloc function.
if(!root) {return;}
  1. Do not cast malloc or realloc function. See at Do I cast the result of malloc?

Upvotes: 2

Related Questions