Create a 2d array of strings using dynamically allocation in c - 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...

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

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;}
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
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;}
Do not cast malloc or realloc function. See at Do I cast the result of malloc?

Related

Is there any problem while returning the "char pointer" from function

The code below is expected to return a string containing only numbers from an user entered string.
Also the returned string should group the numbers in three digits and put a '-' between them.
Everything runs fine, code compiles without any error, but the char* is not being returned from function.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* phoneNo(char*);
void main(){
char str[100];
char *strpass = str;
printf("Enter the string: ");
fgets(str,100,stdin);
printf("Entered stringis: %s\n",str);
char *result = phoneNo(strpass);
printf("Returned char* is: %s\n",result);
}
char* phoneNo(char *strpass){
char str[100];
strcpy(str,strpass);
printf("Char[] in Function: %s",str);
char answer[100];
char * result;
result = ( char* ) malloc(100*sizeof(char));
result=answer;
//printf("Char* pointed to Char[]: %s\n",result);
int i=0;
int j=0;
int k=3;
while(str[i]!='\0'){
if(str[i]=='1'||str[i]=='2'||str[i]=='3'||str[i]=='4'||str[i]=='5'||str[i]=='6'||str[i]=='7'||str[i]=='8'||str[i]=='9'||str[i]=='0')
{
if(j==0){
answer[j]=str[i];
answer[j+1]='\0';
j++;
i++;
continue;
}
if(j==k){
answer[j]='-';
answer[j+1]='\0';
j++;
k+=4;
}else{
answer[j]=str[i];
answer[j+1]='\0';
j++;
i++;
}
}
else
i++;
}
printf("Char* to be returned: %s\n",result);
return (char *)result;
}
This code snippet
char answer[100];
char * result;
result = ( char* ) malloc(100*sizeof(char));
result=answer;
has a memory leak because the address of the allocated memory is lost due to this statement
result=answer;
Now the pointer result points to the local array answer and returned from the function that results in undefined behavior because the array will not be alive after exiting the function.
Use the allocated dynamically array for processing instead of the local array answer.
Pay attention to that instead of this compound if statement
if(str[i]=='1'||str[i]=='2'||str[i]=='3'||str[i]=='4'||str[i]=='5'||str[i]=='6'||str[i]=='7'||str[i]=='8'||str[i]=='9'||str[i]=='0')
it is much better to write
if ( isdigit( ( unsigned char )str[i] ) )
And the function shall be declared like
char* phoneNo(const char *strpass);
that is its parameter must have the qualifier const.
I would write the function the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char * phoneNo( const char *s )
{
const size_t GROUP_SIZE = 3;
size_t digits_count = 0;
for ( const char *p = s; *p; ++p )
{
if ( isdigit( ( unsigned char )*p ) ) ++digits_count;
}
char *result = malloc( digits_count + digits_count / GROUP_SIZE + sizeof( ( char )'\0' ) );
size_t i = 0;
for ( size_t k = 0; *s; ++s )
{
if ( isdigit( ( unsigned char )*s ) )
{
if ( k == GROUP_SIZE )
{
if ( i != 0 )
{
result[i++] = '-';
}
k = 0;
}
result[i++] = *s;
++k;
}
}
result[i] = '\0';
return result;
}
int main(void)
{
const char *s = "123456789";
char *result = phoneNo( s );
puts( result );
free( result );
s = "12\t34567\t89";
result = phoneNo( s );
puts( result );
free( result );
return 0;
}
The program output is
123-456-789
123-456-789
First you allocate memory for result, then in the next line result=answer; you immediately have it point elsewhere, creating a memory leak while instead pointing at a local variable. This is the bug.

Memory leak with string arrays in c

char **add_string(char **existing, const char *string){
size_t size = 0;
while (NULL != existing[size])
{
++size;
}
char **arr = realloc(existing, (size + 2) * sizeof *arr);
arr[size] = malloc(strlen(string) + 1);
strcpy(arr[size], string);
arr[size+1] = '\0';
return arr;
}
void free_strings(char **strings)
{
size_t size = 0;
while (NULL != strings[size])
{
free(strings[size]);
++size;
}
}
I am having a memory leak at line
char **arr = realloc(existing, (size + 2) * sizeof *arr);
I thought existing memory was suppose to be free'd when using realloc? How do I fix this memory leak?
edit: added my free_string function and the main I am using to run the program.
You did not append the array pointed to by the pointer existing with null pointer. Thus in this loop
while (NULL != existing[size])
{
++size;
}
the function has undefined behavior.
It seems you mean the following
char ** add_string( char **existing, const char *string )
{
size_t size = 0;
while ( NULL != existing[size] ) ++size;
char **arr = realloc( existing, ( size + 2 ) * sizeof *arr );
if ( arr != NULL )
{
arr[size] = malloc( strlen( string ) + 1 );
strcpy( arr[size], string );
arr[size+1] = NULL;
}
return arr;
}
Also the function free_strings is incorrect. It should look like
void free_strings( char **strings )
{
size_t size` = 0;
do
{
free( strings[size] );
} while ( strings[size++] != NULL );
free( strings );
}

Passing 2D array of char as argument

I made a function that loads lines and save it to array which dinamically alocates everytime the getline function load a new line but It gives me segmentation fault when i want to print all saved lines from array in the end of my code. Could you please tell me where the problem is ? When i remove the function and put everything to main it works fine.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void load(char **array,int *index) {
int riadok;
size_t len = 0;
char *buffer = NULL;
printf("Slova:\n");
while( ( riadok = getline(&buffer,&len,stdin) ) != -1 ) {
if (riadok == 1){
break;
}
array = (char**) realloc ( array, ( *index + 1 ) * sizeof( char* ) );
array[*index] = (char*) malloc ( (riadok + 1) * sizeof(char*) );
strcpy( array[*index], buffer );
*index = *index + 1;
}
}
int main()
{
int index = 0;
int i;
char **array = NULL;
load(array,&index);
for (i = 0; i < index; i++ )
printf("%s",array[i]);
return 0;
}
In C arguments are pass by value. When you pass array in main to the function then it just copied to the parameter array in function load. The statement
array = (char**) realloc ( array, ( *index + 1 ) * sizeof( char* ) );
modify the pointer array to new allocated memory.
Pass the address of array from main with some changes to load function
void load(char ***array, int *index) { // Use pointer to pointer to pointer
int riadok;
size_t len = 0;
char *buffer = NULL;
printf("Slova:\n");
while( ( riadok = getline(&buffer,&len,stdin) ) != -1 ) {
//printf("%d\n", riadok);
//printf("%s\n", buffer);
if (riadok == 1){
break;
}
*array = realloc ( *array, ( *index + 1 ) * sizeof( char* ) );
if(*array == NULL)
break;
array[0][*index] = malloc(riadok + 1);
if(array[0][*index])
strcpy( array[0][*index], buffer );
//else
// printf("Memory Not allocated\n");
*index = *index + 1;
}
free(buffer);
}
and call it from main as
load(&array,&index);

Can I free only a part of a string?

I am filling up a string of characters and I double its size from time to time.
When I finish, I would like to free unused memory.
void fun (char **str, size_t *len) {
size_t lsi; //last_significant_index
//filling up the str and reallocating from time to time.
//*len is storing the total size of allocated memory at this point
// idea #1
free((*str)[lsi + 1]);
// idea #2
for(size_t i = lsi + 1; i < *len; i++) {
free(&(*str)[i]);
}
}
None of these ideas seem to work however
Is it even possible to do it? If so, how?
Details:
I am using this function to reallocate my strings:
static void increase_list_size(char **list, size_t *list_len)
{
size_t new_list_size = (*list_len + 1) * 2; // I am not allocating my list at the declaration, so *list_len initially equals 0.
char *new_list = malloc(sizeof(char) * new_list_size);
for (size_t i = 0; i < *list_len; i++)
{
new_list[i] = (*list)[i];
}
if (list != NULL) // I don't want to free an empty list (it wasn't allocated at the declaration!
{
free(*list);
}
(*list) = new_list;
*list_len = new_list_size;
}
As you can see, I am allocating two-times more memory every time - that's why I wanted to free unused memory at the end.
I thought there was some kind of a tricky way to do it, since I felt that you can only use free() to free whole memory block.
No, you can only free() pointers that have been returned by malloc().
You want to use realloc() to change the allocated memory size to a smaller (as well as larger) size. The contents of the array will be preserved.
Example:
#include <stdlib.h>
int main() {
char *str = malloc(100);
...
str = realloc(str, 50);
...
free(str);
}
Remember to check the return value of realloc() (as well as the one of malloc()) to ensure that the (re)allocation has not failed.
You can only free a pointer that is the result of malloc or realloc. You can't reduce the size of an allocation by freeing at an arbitrary offset from it. But you can realloc it to a smaller size: realloc(*str, lsi).
one way is to create a new string and use only space required and copy the content to this one. now you can free the previous one.
I will use this is realloc() is not allowed (sometimes in homework)
the other way is realloc() as others suggested.
You can use standard C function realloc declared in header <stdlib.h>
For example
char *s = malloc( 100 );
strcpy( s, "Hello world" );
char *p = realloc( s, strlen( s ) + 1 );
if ( p != NULL ) s = p;
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
char *s = malloc( 100 );
strcpy( s, "Hello world" );
char *p = realloc( s, strlen( s ) + 1 );
if ( p != NULL ) s = p;
puts( s );
free( s );
return 0;
}
The program output is
Hello world
Or if you want to write a separate function then it can look the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void resize( char **s, size_t n )
{
char *p = realloc( *s, n );
if ( p != NULL ) *s = p;
}
int main( void )
{
char *s = malloc( 100 );
strcpy( s, "Hello world" );
resize( &s, strlen( s ) + 1 );
puts( s );
free( s );
return 0;
}
Also you can use POSIX function strdup

What is the correct way to allocate and pass a string?

I have a string, for which i allocate memory. After that, i pass this string to another function, and then from the second function i pass it to a third function. The problem is, that after the tird function completes, i can access/use the variable. But after the second function completes, i can't access it's value in the first function. So obviously i'm doing somethin wrong, but i don't what.
Could someone please help me?
Of course if anyone has better idee, how i should do what i want, i would also appreciate it.
My code so far:
#define MAX_SIZE 100
void Func1()
{
char *Test = NULL;
Test = ( char * )malloc( MAX_SIZE*sizeof( char ) );
if ( Test == NULL )
{
return;
}
Func2( Test );
if ( Test!= NULL ) free( Test);
}
void Func2(char *string)
{
Func3( &string);
}
void Func3( char **string)
{
if (Len > MAX_SZIE )
{
char *tmp = NULL;
tmp = ( char * )realloc( *string, Len + 1 );
if ( !tmp )
{
return;
}
*string = tmp;
memset( *string, 0, sizeof( *string ) );
}
memcpy( *string, SomeOtherString, Len );
free( SomeOtherString );
}
Thanks in advance!
Update:
Updated the function, with the current code i have now:
bool __stdcall Function( DataToSendBack *DataArray )
{
char *Result = NULL;
char InString[ MAX_SIZE ] = { 0 };
int DataLen = 0;
bool bRetVal = false;
__try
{
Result = ( char * )malloc( MAX_SIZE );
if ( Result == NULL )
{
__leave;
}
memset( InString, 0, sizeof( InString ) );
memset( Result, 0, sizeof( Result ) );
memcpy( InString, DataArray->StringIn, strlen( DataArray->StringIn ) );
Result = GetInfo( InString, Result, &DataLen );
if ( Result == NULL )
{
MessageBoxA(NULL,"error",NULL,NULL);
__leave;
}
if ( strlen( ErrorMsg ) > 0 ) strcpy( DataArray->ErrorMessage, ErrorMsg );
if ( DataArray->RequiredSize < DataLen )
{
DataArray->RequiredSize = DataLen;
strcpy( DataArray->ErrorMessage, ErrorMsg );
__leave;
}
DataArray->Result = _strdup( Result );
bRetVal = true;
}
__finally
{
if ( Result != NULL ) free( Result );
}
return bRetVal;
}
char * GetInfo( char *String, char *Result, int *DataLen )
{
bool bRetVal = false;
__try
{
if ( DoStuff( String, &Result, DataLen ) )
{
bRetVal = true;
}
}
__finally
{
// free other things
}
return Result;
}
bool DoStuff( char *MyString, char **Result, int *DataLen )
{
__try
{
//Call function which returns dwsize
*DataLen = dwSize * 2;
OtherString = SomFunction();
if ( strlen( OtherString ) > MAX_SIZE )
{
char *tmp = NULL;
tmp = ( char * )realloc( *Result, strlen( OtherString ) );
if ( !tmp )
{
__leave;
}
*Result = tmp;
memset( *Result, 0, sizeof( *Result ) );
}
memcpy( *Result, OtherString, strlen( OtherString ) );
free( OtherString );
bretVal = true;
}
__finally
{
// free other things
}
return bretVal;
}
Func3() modifies the pointer that Func1() allocated. You need to pass it back to Func1():
void Func1()
{
char *Test = NULL;
if (NULL == (Test = malloc(MAX_SIZE) ) {
// Handle case of OOM error
return;
}
// Func2 may modify Test
Test = Func2( Test );
if (NULL == Test) {
// Handle case of error in Func3
}
free(Test); // Test = NULL;
}
/**
* Reads and modifies (through a call to Func3) a pointer to string
*/
char * Func2(char *string)
{
Func3( &string);
return string;
}
Also, in Func3(), you need to:
memset( *string, 0, Len + 1 );
to zero the whole string.
But actually you're writing OtherString into *string, so zeroing all those bytes, as WhozCraig points out, is unnecessary. What you should really do is make sure you have enough space, and zero the one byte immediately after the string, if it is necessary. So that would be
strncpy(*string, OtherString, Len);
(*string)[Len] = 0x0;
or more efficiently (since strncpy will zero whatever comes after the copy of OtherString, up to Len bytes)
size_t new_len = strlen(OtherString);
if (new_len <= Len) {
// Copy, including last zero
memcpy(*string, OtherString, new_len+1);
} else {
// Copy Len bytes, from 0 to Len-1
memcpy(*string, OtherString, Len);
// Zero last byte to make it a valid C string
(*string)[Len] = 0x0;
}
or
size_t new_len = min(Len, strlen(OtherString));
memcpy(*string, OtherString, new_len);
// Zero last byte to make it a valid C string
(*string)[new_len] = 0x0;
Update
For testing purposes, this is the Func3() I used:
#define OtherString "To be or not to be, that is the question\n"
#define Len 10240
#define min(a,b) (((a)<(b))?(a):(b))
void Func3( char **string)
{
char *tmp = realloc( *string, Len+1);
if (NULL == tmp)
{
return;
}
*string = tmp;
size_t new_len = strlen(OtherString);
new_len = min(Len, new_len);
memcpy(*string, OtherString, new_len);
// Zero last byte to make it a valid C string
(*string)[new_len] = 0x0;
}
In one case it returns "To be or not to be", in the other (Len=16) it returns "To be or not to ", as expected.
You're realloc()ating the string in Func3(). However, the new, potentially modified pointer is never returned to Func1(), because Func2() takes the pointer by value, not by pointer. Hence, you will access a potentially deallocated memory region.
The solution: depending on what you need, you might possibly want to pass the original string by pointer to Func2() (and perhaps to Func1()) as well.

Resources