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);
Related
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?
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.
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 );
}
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.
How do you use a string array as a parameter in C? If I were to write a function with signature:
Guess i didnt explain myself very well... I'll post the code that i'm trying to get to work.
int format_parameters(char* str) {
char local_str[201] = "";
int i = 0;
int j = 0;
int flip = 0;
while(str[i]) {
if((str[i] == '"') && (flip == 0)) flip = 1;//Sentence allowed
else if((str[i] == '"') && (flip == 1)) flip = 0;//Sentence not allowed
if(flip == 1) append_char(local_str, str[i]);
//check if space
else if(flip == 0) {
int c = str[i];
if(!isspace(c)) append_char(local_str, str[i]);
else {
if((strlen(local_str) > 0) && (j < 4)) {
//local-str copied to param[j] here
//printf("j = %d %s\n",j,local_str);
local_str[0] = '\0';
j++;
}
}
}
i++;
}
//Add \0 to param
return flip;
}//end format_parameters
void append_char(char* str, char c) {
int len = strlen(str);
str[len] = c;
str[len+1] = '\0';
}//end append_char
int main() {
char str[200];
//str filled with stuff...
int x = format_parameters(str);
}
There should be a second (and third?) parameter in format_parameterssignature, a char* param[5] which should be readable from main.
Does this work?
#include <string.h>
#include <assert.h>
#include <stdio.h>
int format_parameters(char *str, char *param[], size_t nparam)
{
char **next = param;
char **end = param + nparam;
char *data = str;
assert(str != 0 && param != 0 && nparam != 0);
while (next < end && *data != '\0')
{
*next++ = data;
data = strchr(data, ' '); // Choose your own splitting criterion
if (data == 0)
break;
*data++ = '\0';
}
return(next - param);
}
int main(void)
{
char str[] = "a b c d";
char *param[5];
int nvals = format_parameters(str, param, 5);
int i;
for (i = 0; i < nvals; i++)
printf("Param %d: <<%s>>\n", i+1, param[i]);
return 0;
}
The return value is the number of parameters found. If you pass an empty string, that would be 0. Beware leading, trailing and repeated blanks; the code works - but maybe not as you want it to.
This is entirely about memory allocation.
If you allocate static memory for param before the function is called, the memory will exist in that scope.
Otherwise take a look at dynamic allocation, it will exist until you tell it to go away.
You have to create the char* param[] array outside the function and just pass it as a parameter:
int paramCount = countParameters(str); // you have to create this function
char* param[] = malloc(paramCount * sizeof(char*));
format_parameters(str, param);
and inside the function:
int format_parameters(char* str, char* param[])
{
int currentParamIndex = 0;
..........
//TODO: check if currentParamIndex < paramCount
char* currentParam = str + currentParamStart; // currentParamStart is the start index of the parameter in the str containing all parameters
param[currentParamIndex] = currentParam;
currentParamIndex++;
.............
}
And in order to write safe code you have to pass also the paramCount as a parameter to format_parameters so the function will not access an element out of the bounds of the array.
Or maybe you should just use getopt?
As Jonatahan pointed out, you need more parameters:
int format_parameters(char* strInput, char* paramOutput[], size_t cbMaxParams );
// return value is actual number of parameter strings in paramOutput
paramOutput is an array of pointers. So the caller has to provide an array of pointers and the called function has to allocate memory for the strings and set the pointers in the array:
// main:
#define SIZE 20
char * params[SIZE];
int result = format_parameters( szInput, params, SIZE );
// after use go through params and free all pointers
// function:
int format_parameters(char* strInput, char* paramOutput[], size_t cbMaxParams )
{
// ...
for( size_t i=0; (i<cbMaxParams) && (!noMoreParams); i++ )
{
// ...
paramOutput[i] = (char *)malloc( xxxx );
// ...
}
// ...
}