adding zeros before string - c

zfill algorithm is supposed to work as follows:
zfill function accepts two parameters, a string and a number,
if string length is >= the number, then it doesn't have to add anything, and it returns a copy to the string,
else, malloc enough space and add zeros before the string.
I'm trying to understand why is this solution not correct, it has two warnings:
1st warning:
for (i; i < zeros; i++) {
s[i] = "0";
}
"=": char differs in level of indirection from char[2]
2nd warning:
for (i; i < n; i++) {
s[i] = str[i];
}
buffer overrun while writing to s
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
free(s);
return 0;
}
EDIT: I've solved the problem this way:
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum-1] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = '0';
}
for (size_t j = 0; i < n; j++) {
s[i++] = str[j];
}
s[sum-1] = 0;
}
return s;
}
and it works, but I don't know why I have this warning:
for (i; i < zeros; i++) {}
statement with no effect
but when I've debugged I've noticed that this statement has an effect, because it correctly copies the correct number of zeros. I don't know why I have this warning

SO is a place of learning.
When first dealing with a coding challenge, it's best to take time to work out what's needed before starting to write code.
Below is a working version of zfill() (along with a main() that tests it.)
Read through the comments. The only thing new here is memset().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// A trivial "helper function" determines the max of two values
int max( int a, int b ) { return a > b ? a : b; }
char *zfill( char *str, int minLen ) {
// Determine length of arbitrary string
int len = strlen( str );
// Determine max of length v. minimum desired
int allocSize = max( minLen, len );
// allocate buffer to store resulting string (with '\0')
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
// determine start location at which to copy str
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
// fill buffer with enough 'zeros'
memset( obuf, '0', allocSize ); // ASCII zero!
// copy str to that location in buffer
strcpy( obuf + loc, str );
// return buffer to calling function
return obuf;
}
int main() {
// collection of strings of arbitrary length
char *strs[] = { "abc", "abcdefghijkl", "abcde", "a", "" };
// pass each one to zfill, print, then free the alloc'd buffer.
for( int i = 0; i < sizeof strs/sizeof strs[0]; i++ ) {
char *cp = zfill( strs[i], 10 );
puts( cp );
free( cp );
}
return 0;
}
Output:
0000000abc
abcdefghijkl
00000abcde
000000000a
0000000000
Here's zfill() without the comments:
char *zfill( char *str, int minLen ) {
int len = strlen( str );
int allocSize = max( minLen, len );
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
memset( obuf, '0', loc ); // ASCII zero!
strcpy( obuf + loc, str );
return obuf;
}
You don't want to spend your time staring at lines and lines of code.
Fill your quiver with arrows that are (proven!) standard library functions and use them.
I've omitted, too, the test for zfill being passed a NULL pointer.

This code snippet
size_t sum = length + 1u;
s = malloc(sum);
//...
s[sum] = 0;
accesses memory outside the allocated character array because the valid range of indices is [0, sum). You need to write at least like
s[length] = 0;
In this code snippet
for (i; i < zeros; ++) {
s[i] = "0";
}
the expression s[i] represents a single object of the type char while on the right-hand side there is a string literal that as an expression has the type char *. You need to write at least
s[i] = '0';
using the integer character constant instead of the string literal.
In this code snippet
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
as the length of the string str can be less than n then this for loop
for (i; i < n; i++) {
s[i] = str[i];
}
accesses memory outside the string str.
Pay attention to that your function has redundant code. It can be written simpler.
The function can look for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
size_t i = 0;
size_t m = len < n ? n - len : 0;
for ( ; i < m; i++ )
{
result[i] = '0';
}
for ( ; i < n; i++ )
{
result[i] = s[i - m];
}
result[i] = '\0';
}
}
return result;
}
int main( void )
{
const char *s = "Hello";
size_t n = 10;
char *result = zfill( s, n );
if ( result ) puts( result );
free( result );
}
The program output is
00000Hello
Or as #Some programmer dude pointed to in his comment you can use the standard C function snprintf that alone performs the task. For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
int m = len < n ? n - len : 0;
snprintf( result, n + 1, "%.*d%s", m, 0, s );
}
}
return result;
}
int main( void )
{
char *p = zfill( "Hello", 5 );
if ( p ) puts( p );
free( p );
p = zfill( "Hello", 10 );
if ( p ) puts( p );
free( p );
}
The program output is
Hello
00000Hello

so you have 3 major problems in your code :
it's s[i] = '0'; not s[i] = "0";
it's s[i] = str[i - zeros]; not s[i] = str[i]; as the value of the i will be 27 in your test case : so it make sense to say s[27] because its size is about 41 but it doesn't make sense to say str[27] as its size is only about 13 in your test case , so you had to map the value 27 of i to the value 0 to be convenient to use with str
i is deprecated in first part here for (i; i < zeros; i++) , so use for (; i < zeros; i++)instead of for (i; i < zeros; i++) , but it will not cause any problem if you keep it.
and here is the full edited code :
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (; i < zeros; i++) {
s[i] = '0';
}
for (; i < n; i++) {
s[i] = str[i - zeros];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
printf("%s\n", s);
free(s);
return 0;
}

Related

Trying to reverse a C-string but it is not working

I am trying to reverse this C-string and I thought I did it correct but the string remains the same when it passes through the function.
#include <stdio.h>
char* reverse(char* string);
int main(int arc, char* argv[]) {
char word[] = "Hello World!";
printf("%s\n", word);
printf("%s\n", reverse(word));
return 0;
}
char* reverse(char* string) {
int i, j, n = 0;int len = 0;char temp;
//Gets string length
for (i = 0; *(string + i) != '0'; i++) {
len++;
}
//Reverses string
for (j = len - 1; j >= 0; j--) {
temp = string[n];
string[n] = string[j];
string[j] = temp;
n++;
}
return &string[0];
}
Expected output:
Hello World!
!dlroW olleH
For starters there is a typo
for (i = 0; *(string + i) != '0'; i++) {
You have to write
for (i = 0; *(string + i) != '\0'; i++) {
That is instead of the character '0' you have to use '\0' or 0.
In this for loop
for (j = len - 1; j >= 0; j--) {
temp = string[n];
string[n] = string[j];
string[j] = temp;
n++;
}
the string is reversed twice.:) As a result you get the same string.
The function can look for example the following way
char * reverse(char *string)
{
//Gets string length
size_t n = 0;
while ( string[n] != '\0' ) ++n;
//Reverses string
for ( size_t i = 0, m = n / 2; i < m; i++ )
{
char temp = string[i];
string[i] = string[n - i - 1];
string[n - i - 1] = temp;
}
return string;
}
Or the function can be defined the following way using pointers
char * reverse(char *string)
{
//Gets string length
char *right = string;
while ( *right ) ++right;
//Reverses string
if ( right != string )
{
for ( char *left = string; left < --right; ++left )
{
char temp = *left;
*left = *right;
*right = temp;
}
}
return string;
}
The same approach of the function implementation without using pointers can look the following way
char * reverse(char *string)
{
//Gets string length
size_t n = 0;
while ( string[n] != '\0' ) ++n;
//Reverses string
if ( n != 0 )
{
for ( size_t i = 0; i < --n; ++i )
{
char temp = string[i];
string[i] = string[n];
string[n] = temp;
}
}
return string;
}
Here is one more solution. I like it most of all. Tough it is inefficient but it is not trivial as the early presented solutions. It is based on an attempt of one beginner to write a function that reverses a string.:)
#include <stdio.h>
#include <string.h>
char *reverse( char *string )
{
size_t n = 0;
while (string[n]) ++n;
while (!( n < 2 ))
{
char c = string[0];
memmove( string, string + 1, --n );
string[n] = c;
}
return string;
}
int main( void )
{
char string[] = "Hello World!";
puts( string );
puts( reverse( string ) );
}
The program output is
Hello World!
!dlroW olleH
Of course instead of manually calculating the length of a string in all the presented solutions there could be used standard string function strlen declared in the header <string.h>.
The problem is that the input word[] is an array, which decays to a pointer when passed to the reverse function.
In the for loop, instead of using n to keep track of the position, I suggest you to use i and j to keep track of the start and end of the string, and increment and decrement them respectively and use strlen to get the length of string.
Also, as it is mentionned above by #Vlad from Moscow, in your for loop you are checking for 0 but it should be \0 which is the null character.
Please find down below an update of your posted code that is generating the expected result :
#include <stdio.h>
char* reverse(char* string);
int main(int arc, char* argv[]) {
char word[] = "Hello World!";
printf("%s ", word);
printf("%s\n", reverse(word));
return 0;
}
char* reverse(char* string) {
int i, j;
char temp;
int len = strlen(string);
//Reverses string
for (i = 0, j = len - 1; i < j; i++, j--) {
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
return &string[0];
}
The output is as expected: Hello World! !dlroW olleH
Aditionnally, you can include the header <string.h> or explicitly
provide a declaration for 'strlen' to avoid the warning that indicate to implicitly declaring library function 'strlen' with type 'unsigned long (const char *)' [-Wimplicit-function-declaration]

I need to make a program that will print characters in a word on how frequent it is used

I need to make a program that will print characters in a word on how frequent it is used. The unique characters will be printed in increasing order (spaces are ignored), if there are ties the character with lower ascii value will be printed first.
For an example if the input is hello world, the letters "h", "e", "w", "r" and "d" are only used once, the character "o" is used twice and the character "l" is used thrice. Since h,e,w,r,d are tie we should sort it into d,e,h,r,w. Then next would be o since it is used twice and then last is l. Thus if the input is hello world the output must be dehrwol. On my current program the problem is that when there are ties, it would not sort it alphabetically so the output is hewrdol instead of dehrwol.
This is the code I have written
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int times[256];
int cmpLetters(const void* a, const void* b)
{
return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);
}
int main()
{
char letters[256];
int i, j, k, lnum, t;
char s[1000];
fgets(s, sizeof(s), stdin);
// Init occurrences as 0
memset(times, 0, sizeof(times));
for (i = lnum = 0; s[i] != '\0'; i++)
if (times[s[i]]++ == 0)
letters[lnum++] = s[i];
// Sort letters by number of occurrences
qsort(letters, lnum, sizeof(char), cmpLetters);
char* new = malloc(sizeof(char) * (i + 1));
for (j = k = 0; j < lnum; j++)
for (i = 0; i < times[letters[j]]; i++)
new[k++] = letters[j];
// new[k] = '\0';
for (i = 0; i<lnum; i++)
{
if(letters[i] != '\n' && letters[i] !=' ')
printf("%c",letters[i]);
}
printf("\n\n");
return 0;
}
In this for loop
for (i = lnum = 0; s[i] != '\0'; i++)
if (times[s[i]]++ == 0)
letters[lnum++] = s[i];
you are not checking whether s[i] represents a letter.
The comparison function
int cmpLetters(const void* a, const void* b)
{
return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);
}
compares only characters without comparing also their frequencies.
This code snippet
char* new = malloc(sizeof(char) * (i + 1));
for (j = k = 0; j < lnum; j++)
for (i = 0; i < times[letters[j]]; i++)
new[k++] = letters[j];
does not make sense because the array new is not used further in the program. It only produces a memory leak.
The program will be simpler if to introduce a structure that contains two data members that store a letter and its frequency.
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct Pair
{
char c;
size_t n;
};
int cmp( const void *a, const void *b )
{
const struct Pair *p1 = a;
const struct Pair *p2 = b;
int result = ( p2->n < p1->n ) - ( p1->n < p2->n );
if (result == 0)
{
result = ( p2->c < p1->c ) - ( p1->c < p2->c );
}
return result;
}
int main( void )
{
enum { N = 1000} ;
char s[N];
fgets( s, sizeof( s ), stdin );
size_t n = 0;
for (size_t i = 0; s[i] != '\0'; ++i)
{
if (isalpha( ( unsigned char )s[i] ))
{
size_t j = 0;
while (j != i && s[j] != s[i]) ++j;
n += j == i;
}
}
if (n != 0)
{
struct Pair pairs[n];
memset( pairs, 0, n * sizeof( struct Pair ) );
for (size_t i = 0, m = 0; s[i] != '\0'; i++)
{
if (isalpha( ( unsigned char )s[i] ))
{
size_t j = 0;
while (j != m && pairs[j].c != s[i]) ++j;
if (j == m)
{
pairs[m].c = s[i];
++pairs[m].n;
++m;
}
else
{
++pairs[j].n;
}
}
}
qsort( pairs, n, sizeof( *pairs ), cmp );
for (size_t i = 0; i < n; i++)
{
putchar( pairs[i].c );
}
putchar( '\n' );
}
}
The program output might look like
hello world
dehrwol

My function that reverses a string gives me "stack smashing detected"

I am trying to write a function that reverses a given string but it gives me "stack smashing detected".
Here is my code:
void reverse(char *str2) {
int i, j;
char temp;
for (i = 0, j = str2[strlen(str2) - 1]; i < j; i++, j--) {
temp = str2[i];
str2[i] = str2[j];
str2[j] = temp;
}
str2[strlen(str2)] = '\0';
printf("%s", str2);
}
There are multiple problems in your code:
j should be initialized as j = strlen(str2) - 1, not j = str2[strlen(str2) - 1] which is the value of the last character in the string (if any).
str2[strlen(str2)] = '\0'; is absolutely useless and redundant.
Here is a modified version:
#include <stdio.h>
#include <string.h>
void reverse(char *str) {
for (size_t i = 0, j = strlen(str); i < j--; i++) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
printf("%s\n", str);
}
Such a function should return a pointer to the reversed string. That is it is better to declare the function like
char * reverse( char *str2 );
Also the name of the parameter looks strange. So declare the function like
char * reverse( char *s );
There is a typo in the function. The variable j must be initialized like
j = strlen( str2 ) - 1;
instead of
j = str2[strlen(str2) - 1];
This statement
str2[strlen(str2)] = '\0';
is redundant and should be removed.
The function should not output the reversed string. It is the caller of the function that will decide whether to output the reversed string.
Also instead of the type int for indices you should use the type size_t - the return type of the function strlen.
Using your approach the function should look the following way
char * reverse( char *s )
{
if ( *s )
{
for ( size_t i = 0, j = strlen( s ) - 1; i < j; i++, j-- )
{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
return s;
}
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * reverse( char *s )
{
if ( *s )
{
for ( size_t i = 0, j = strlen( s ) - 1; i < j; i++, j-- )
{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
return s;
}
int main(void)
{
char s[] = "Hello World!";
puts( s );
puts( reverse( s ) );
}
Its output is
Hello World!
!dlroW olleH

Count frequencies of string - using only stdio.h - C

We have got some exercise in C (We must use only stdio.h library):
Write a function that receives two strings and returns the number of occurences of the second in the first one, there could be overlapping dependent on cyclic parameter.
But I don't succeed treat the case of isCyclic is turned on.
for example if isCyclic is other than 0 and:
char *str1 = "aaa";
char *str2 = "aa";
We have to return 3
What is my mistake in isCyclic?..
Here is my implementation:
int strLength(const char *str) {
int count = 0;
while (*str) {
count++;
str++;
}
return count;
}
unsigned int countPatInStr(const char *str1, const char *str2, int isCyclic)
{
int patternSize = strLength(str2);
int textSize = strLength(str1);
int res = 0;
int j;
if (isCyclic) { // Here is the case when overlapping is needed
if (patternSize > textSize) {
for (int i = 0; i < patternSize - textSize; i++) {
for (int j = 0; j < textSize; j++) {
if (str1[j] != str2[i + j]) {
break;
}
if (j == textSize && i + j < patternSize) {
str2 += i + j;
} else if (j == textSize && i + j == patternSize) {
res++;
}
}
}
return 0;
}
} else {
/* A loop to slide pat[] one by one */
for (int i = 0; i <= textSize - patternSize; i++) {
/* For current index i, check for pattern match */
for (j = 0; j < patternSize; j++) {
if (str1[i + j] != str2[j]) {
break;
}
}
// if pat[0...M-1] = txt[i, i+1, ...i+M-1]
if (j == patternSize) {
res++;
}
}
return res;
}
return 0;
}
Your function at least is invalid because in this loop
for (int i = 0; i < patternSize - textSize; i++)
the condition can be equal to false. So the loop is never executed.
And in this loop
for (int j = 0; j < textSize; j++) {
if (str1[j] != str2[i + j]) {
break;
}
there is used the index j with the pointer str1 and the index i + j with the pointer str2 when isCyclic is non-zero.
The function can be written much simpler as it is shown in the demonstrative program below.
#include <stdio.h>
size_t strLength( const char *s )
{
size_t n = 0;
for ( ; *s; ++s ) ++n;
return n;
}
size_t countPatInStr( const char *s1, const char *s2, _Bool isCyclic )
{
size_t count = 0;
size_t n1 = strLength( s1 );
size_t n2 = strLength( s2 );
if ( !( n1 < n2 ) || isCyclic )
{
size_t n = isCyclic ? n1 : n1 - n2 + 1;
size_t divident = isCyclic ? n : n1;
for ( size_t i = 0; i < n; i++ )
{
size_t j = 0;
while ( j < n2 && s1[ ( i + j ) % divident] == s2[j] ) j++;
count += j == n2;
}
}
return count;
}
int main(void)
{
const char *s1 = "aaa";
const char *s2 = "aa";
printf( "%zu\n", countPatInStr( s1, s2, 0 ) );
printf( "%zu\n", countPatInStr( s1, s2, 1 ) );
return 0;
}
The program output is
2
3
Or if s1 and s2 are defined like
const char *s1 = "aa";
const char *s2 = "aaa";
then the output will be
0
2
Or if they are defined like
const char *s1 = "abcabc";
const char *s2 = "abc";
then the output is
2
2
Is it what you need?

C - Split Slows Down My Computer

I'm trying to program a split that takes in a char-array with multiple words and separates each word into their own smaller char-array. All the pointers of the smaller char-arrays are kept in a pointer array so I can return a double pointer.
Can you take a look at my code and see if you see any errors. When I try to run my program my computer gets gradually slower, after 3-4 seconds I can't move my mouse or alt+f4 my editor. So something has to be seriously wrong!
Also I'm completely new to C-programming so I will most definitely have a silly mistake in there.
char **split(char *s) {
char **result;
int wrd_cnt = 2; //I'm adding NULL at the end of the pointer-array.
//Counts the number of words to allocate memory for the pointer-array.
for(int i = 0; i < strlen(s); i++) {
if(s[i] == ' ') {
wrd_cnt++;
}
}
result = malloc(wrd_cnt * sizeof(char*));
//Counts letters in each word to allocate memory for every single small char-array with malloc.
for(int i = 0; i < strlen(s); i++) {
for(int j = 0; j < (wrd_cnt); j++) {
int char_cnt = 0;
for(int k = 0; s[i] != ' ' || s[i] != '\0'; k++, i++) {
char_cnt++;
result[j] = malloc(char_cnt * sizeof(char));
}
}
}
//Puts each word into their own place in the pointer array.
for(int i = 0; i < strlen(s); i++) {
for(int j = 0; j < (wrd_cnt); j++) {
for(int k = 0; s[i] != ' ' || s[i] != '\0'; k++, i++) {
result[j][k] = s[i];
}
}
}
result[wrd_cnt-1] = NULL;
return result;
}
In this situation the loops using j and k can be removed and instead increment and reset i, j and char_cnt based on the i loop as the s array is processed, similar to what you had done for wrd_cnt in the first loop
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char **split(char *s);
int main ( void) {
char **output = NULL;
int each = 0;
char line[99] = " string to parse for words ";
output = split ( line);
each = 0;
while ( output[each]) {
printf ( "%s\n", output[each]);
each++;
}
each = 0;
while ( output[each]) {
free ( output[each]);
each++;
}
free ( output);
exit ( 0);
}
char **split(char *s) {
char **result;
int wrd_cnt = 2; //I'm adding NULL at the end of the pointer-array.
int char_cnt = 0;
int i = 0;
int j = 0;
int k = 0;
//Counts the number of words to allocate memory for the pointer-array.
for(i = 0; i < strlen(s); i++) {
if(s[i] == ' ') {
wrd_cnt++;
}
}
if ( ( result = malloc(wrd_cnt * sizeof(char*))) == NULL) {
fprintf ( stderr, "malloc failure\n");
exit ( 1);
}
//Counts letters in each word to allocate memory for every single small char-array with malloc.
char_cnt = 1;
j = 0;
for( i = 0; i < strlen(s); i++) {
if ( s[i] == ' ') {
if ( ( result[j] = malloc(char_cnt * sizeof(char))) == NULL) {
fprintf ( stderr, "malloc failure\n");
exit ( 1);
}
j++;
char_cnt = 1;
continue;
}
char_cnt++;
}
if ( j == wrd_cnt - 2) {
//allocate for last word
if ( ( result[j] = malloc(char_cnt * sizeof(char))) == NULL) {
fprintf ( stderr, "malloc failure\n");
exit ( 1);
}
j++;
result[j] = NULL;
}
result[wrd_cnt - 1] = NULL;//just to make sure the last pointer is null
//Puts each word into their own place in the pointer array.
j = 0;
k = 0;
for( i = 0; i < strlen(s); i++) {
if ( s[i] == ' ') {
result[j][k] = '\0';//for space only so [j][0] is '\0'
k = 0;
j++;
continue;
}
result[j][k] = s[i];
k++;
result[j][k] = '\0';//for last word if there is no final space in s[]
}
return result;
}
Aside from the comments above your code scares me because of all the malloc() calls you do, one for each word. This means you must also free each word. This leaves programs open to memory leaks.
Given that this is C, which allows lots of casting, you can use a single malloc to hold both the (char *) pointer array AND the actual words.
char **split(char const *s) {
char **result; //
char *target; // where in result chars stored
size_t s_strlen = strlen(s); // length of s
int wrd_cnt = 2; //I'm adding NULL at the end of the pointer-array.
{
char const *sx;
for ( sx = s; sx = strpbrk( sx, " \t\n\r" ); sx++ )
{
wrd_cnt++;
}
}
result = malloc( (wrd_cnt * sizeof(char *)) + s_strlen + 2 );
/* allow for \0 and possible ' ' */
target = (char *)(result + wrd_cnt); /* where to save words */
strcpy( target, s ); /* copy to target known to be big enough */
if ( s_strlen > 0 && target[s_strlen-1] != ' ' )
strcat( target + s_strlen, " " ); /* assure ends in space */
{
char *tx, *tnext;
int n;
n = 0;
for ( tx = target; tnext = strpbrk( tx, " \t\n\r" ); tx = tnext + 1 )
{
result[n++] = tx; /* remember pointer */
*tnext = '\0'; /* terminate word */
}
result[n] = NULL; /* null termination */
}
return result;
}

Resources