I am stuck in memory allocation while solving the exercise.
Exercise requirement: Create a function that splits a string of characters depending on a separator. The second argument is a unique character separator. The function should return an array that contains a string wrapped between separator.
Example:
Input: "abc def gh-!" && "-"
Output: ["abc def gh", "!"]
Code:
#include<stdlib.h>
typedef struct s_string_array {
int size;
char** array;
} string_array;
string_array* my_split(char* a, char* b) {
//Memory allocation part:
string_array*ptr=(string_array*)malloc(sizeof(string_array));
int count=0;
for(int i=0;a[i]!='\0';i++)
{
if(a[i]==b[0])
{
count++;
}
}
ptr->size=count+1;
ptr->array=malloc(sizeof(char*)*ptr->size);
int size2=0;
int q=0;
for(int i=0;i<ptr->size;i++)
{
for(;a[q]!=b[0];q++)
{
size2++;
}
ptr->array[i]=malloc(sizeof(char)*(size2+2));
ptr->array[i][size2+1]='\0';
q+=2;
}
//Filling the array:
int c=0;
for(int i=0;a[i]!='\0';i++)
{
if(a[i]!=b[0]){
for(int j=i,r=0;a[j]!=b[0];j++,r++)
{
ptr->array[c][r]=a[j];
}
c++;
}
}
return ptr;
}
It is giving me an error. Could somebody explain what I am doing wrong?
I think you are heading in the wrong direction. When I read this:
The function should return an array that contains a string
it tells me that the function shall return a char-pointer to a zero-terminated char array (ie a C style string).
In other words - what you are trying to return is way to complex.
Something like this should do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
char* my_split(const char* str, const char sep)
{
const char* p = str;
size_t len = 0;
size_t words = 1;
// Count the number of chars to copy and the number of words
while (*p)
{
if (*p == sep) ++words; else ++len;
++p;
}
if (len == 0)
{
char* out = malloc(3);
assert(out);
strcpy(out, "[]");
return out;
}
// Calculate required memory
size_t total =
1 + // termination
2 + // [ and ]
2 * words + // " and " around each word
2 * (words-1) + // the , and space between words
len; // the strings
char* out = calloc(total, 1);
assert(out);
strcpy(out, "[\"");
size_t index = 2;
p = str;
while(*p)
{
if (*p == sep)
{
// Word finished prepare the next word (if any)
strcat(out, "\"");
++index;
if (*(p+1))
{
strcat(out, ", \"");
index +=3;
}
}
else
{
out[index] = *p;
++index;
}
++p;
}
strcat(out, "\"]");
// Verify the malloc size
assert((total-1) == strlen(out));
return out;
}
int main()
{
char* input1 = "abc def gh-!";
char* output1 = my_split(input1, '-');
printf("%s\n", output1);
free(output1);
char* input2 = "a-b-c-d-e-f-g";
char* output2 = my_split(input2, '-');
printf("%s\n", output2);
free(output2);
return 0;
}
Output:
["abc def gh", "!"]
["a", "b", "c", "d", "e", "f", "g"]
For starters this function declaration:
string_array* my_split(char* a, char* b) {
does not make great sense. The first parameter shall have the qualifier const because the passed string is not being changed in the function and the second parameter shall not be a pointer. Also it is senseless to return from the function a pointer to an object of the type string_array
.
The function shall be declared at least like
string_array my_split( const char *s, char c ) {
This loop
int count=0;
for(int i=0;a[i]!='\0';i++)
{
if(a[i]==b[0])
{
count++;
}
}
does not count the number of sub-strings separated by the character b[0]
because such characters can follow each other without intermediate other characters. So for example this string
"---A-"
has only one sub-string "A"
provided that the separator is '-'
.
It is unclear why ptr->size
is set to the value count+1
.
As the source string can start from the separate character then this loop
for(;a[q]!=b[0];q++)
{
size2++;
}
will not iterate as a result this memory allocation
ptr->array[i]=malloc(sizeof(char)*(size2+2));
does not make sense.
And you have to reinitialize the variable size_t to zero within the outer loop
int size2=0;
int q=0;
for(int i=0;i<ptr->size;i++)
Pay attention to that functions that allocate memory can fail. That is they can return NULL. You have to process such situations.
Here is a demonstrative program that shows how the function can be implemented. The returned structure contains three data members: the total number of sub-strings in the string, the actual number of extracted sub-string and the pointer to the allocated memory for sub-string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct substring_array
{
size_t total;
size_t actual;
char **p;
} split( const char *s, char c )
{
struct substring_array a = { .total = 0, .actual = 0, .p = NULL };
// count the total number of substrings
for ( const char *t = s; *t; )
{
while ( *t == c ) ++t;
if ( *t )
{
++a.total;
while ( *++t != '\0' && *t != c );
}
}
// extract substrings
int success = 1;
while ( success && *s )
{
while ( *s == c ) ++s;
if ( *s )
{
const char *first = s;
while ( *++s != '\0' && *s != c );
size_t len = s - first;
char *current = malloc( len + 1 );
success = current != NULL;
if ( success )
{
char **tmp = realloc( a.p, ( a.actual + 1 ) * sizeof( char * ) );
success = tmp != NULL;
if ( success )
{
a.p = tmp;
strncpy( current, first, len );
current[len] = '\0';
a.p[a.actual++] = current;
}
else
{
free( current );
}
}
}
}
return a;
}
int main(void)
{
const char *s = "abc def gh-!";
char c = '-';
struct substring_array a =split( s, c );
if ( a.total == a.actual )
{
printf( "There were extracted all %zu substrings\n", a.total );
}
else
{
printf( "There were extracted %zu substrings of total %zu substrings\n",
a.actual, a.total );
}
for ( size_t i = 0; i < a.actual; i++ ) puts( a.p[i] );
while ( a.actual != 0 ) free( a.p[--a.actual] );
free( a.p );
return 0;
}
The program output is:
There were extracted all 2 substrings
abc def gh
!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.