replacing spaces with %20 in c program - c

I have written the following program to replace spaces with %20.It works fine.
But it prints some garbage values for the pointer variable ptr though it might have been limited to 8 characters as the malloc assigns it 8 bytes of memory.
Can anyone tell me where did I go wrong here ?
Or is there any in place algorithm ?
void replaceSpaces(char *inputStr )
{
char *ptr;
int i,length, spaceCount=0;
int newLength,j;
for (length=0; *(inputStr+length)!='\0';length++ )
{
if (*(inputStr+length)==' ')
{
spaceCount++;
}
}
newLength = length + 2*spaceCount;
ptr = (char *)malloc(newLength*sizeof(char));
for ( i = length-1; i >=0; i--)
{
if (*(inputStr+i)==' ')
{
*(ptr+newLength-1)='0';
*(ptr+ newLength-2)='2';
*(ptr+newLength-3)='%';
newLength = newLength -3;
}
else
{
*(ptr+newLength-1) = *(inputStr+i);
newLength = newLength -1;
}
}
for ( i = 0; *(ptr+i)!='\0'; i++)
{
printf("%c",*(ptr+i));
}
}

Either use calloc() to allocate memory for ptr or terminate it with '\0' after allocation.
With your code, ptr never gets terminated with '\0'.
So either change
ptr = (char *)malloc(newLength*sizeof(char));
to
ptr = calloc(newLength*sizeof(char), sizeof(char));
Or add below line after allocating the ptr.
ptr[newLength] = '\0';

If you don't need the converted string, then you don't need to worry about conversion: you can just output characters directly.
void replace_spaces(const char *in) {
for (const char *p=in; *p; p++) {
if (*p == ' ') {
puts("%20");
} else {
putch(*p);
}
}
}
If you do need the converted string, then a useful pattern for this sort of code is to do the string conversion twice; once in "dry-run" mode where you do the conversion but don't write to the result, and once in "live" mode where you're actually writing. In the first pass, you calculate the needed length. This avoids duplication of logic, and makes it more obvious if you've counted the resulting length correctly. Here's some code in that style, with some test-cases.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_spaces(const char *in) {
char *result = 0;
for (int write = 0; write <= 1; write++) {
int n = 0;
for (const char *from = in; ;from++) {
if (*from == ' ') {
if (write) memcpy(result + n, "%20", 3);
n += 3;
} else {
if (write) result[n] = *from;
n++;
}
if (!*from) break;
}
if (!write) result = malloc(n);
}
return result;
}
int main(int argc, char**argv) {
const char*cases[] = {"Hello world", "abc", " sp sp sp "};
for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
char *rep = replace_spaces(cases[i]);
printf("'%s' -> '%s'\n", cases[i], rep);
free(rep);
}
return 0;
}

Assuming that this is going to work on fairly short strings, it is a bit silly to go through the strings twice. If, like in most cases, CPU is more valuable than memory, do:
char *dst = malloc(3*strlen(src) + 1);
char *result = dst;
while (*src) {
if (*src == ' ') {
strcpy(dst, "%20"); dst+=3;
}
else *dst++ = *src;
src++;
}
*dst = 0;
// result is result

Related

IOT instruction when converting string to word array

I'm coming back to you about my function char **my_str_to_word_array(char *str). The purpose is to separate the string at each non-printable ASCII character and include the above in a new row of the double dimensional array.
Non-printable ASCII characters should be used as separators and should not be included in the line.
Example:
char *test = "My name is John Doe.\nI have 0 GPA.\nI will survive." ;
char **array = my_str_to_word_array(test) ;
array[0] = "My name is John Doe." (zero terminated string)
array[1] = "I have 0 GPA." (zero terminated string)
array[2] = "I will survive." (zero terminated string)
array[3] = NULL
I have 2 problems:
If in my test main() I have a printf() below the call to my_str_to_word_array, the format passed to printf() will be included in the array. So I conclude that there is a memory read error.
When I try to free() the array I get an error :
double free or corruption (out)
[1] 33429 IOT instruction (core dumped) ./libmy
size_t get_words_number(char const *str)
{
size_t count = 0;
const char *i = str;
while (*i != 0) {
if (isprint(*i)) {
count++;
}
while (*i != 0 && isprint(*i)) {
i++;
}
i++;
}
return count;
}
char **free_corrupted_array(char **array, size_t i)
{
size_t j = 0;
while (j < i) {
free(array[j]);
j++;
}
free(array);
return NULL;
}
char **fill_array(char **array, const char *str, size_t word_count)
{
size_t word_size = 0, j = 0;
const char *i = str;
while (j < word_count) {
while (*i != 0 && isprint(*i)) {
word_size++;
i++;
}
array[j] = strndup(i - word_size, word_size);
if (!array[j]) {
return free_corrupted_array(array, j);
}
word_size = 0;
j++;
while (!isprint(*i)) {
i++;
}
}
array[j] = NULL;
return array;
}
char **my_str_to_word_array(char const *str)
{
char **word_array = NULL;
size_t word_count = 0;
if (!str) {
return NULL;
}
word_count = get_words_number(str);
word_array = malloc(word_count * sizeof(char *));
if (!word_array) {
return NULL;
}
word_array = fill_array(word_array, str, word_count);
return word_array;
}
void my_free_word_array(char **word_array)
{
if (!word_array) {
return;
}
while (*word_array != NULL) {
free(*word_array);
word_array++;
}
free(word_array);
}
int main(int argc, char **argv)
{
const char *test = "My name is John Doe.\nI have 0 GPA.\nI will survive.";
char **word_array = my_str_to_word_array(test);
while (*word_array != NULL) {
printf("%s\n", *word_array);
word_array++;
}
printf("Test print original size %lu\n", strlen(test));
my_free_word_array(word_array);
return 0;
}
And the output :
My name is John Doe.
I have 0 GPA.
I will survive.
Test print original size %lu
Test print original size 50
double free or corruption (out)
[1] 33429 IOT instruction (core dumped) ./libmy
Do you see the problem?
Errors:
get_words_number goes out of bounds (off by one) and may read arbitrary memory after your string (check with the example I included in main).
You need an additional slot in your array to put there a terminating NULL.
Stop thrashing your input pointer if you later need it (both in my_free_word_array and in the printing loop in main).
EDITED: as Fe2O3 commented, I missed another bug in the fill_array function. You should also ensure that *i!=0 in the last loop.
Suggestions:
Next time make a Minimal, Reproducible Example by including all required headers;
strndup is not standard (unless you have __STDC_ALLOC_LIB__ and define __STDC_WANT_LIB_EXT2__ to 1).
You don't need the free_corrupted_array function at all.
EDITED: it's useless to check that *i!=0 if you are also checking that isprint(*i). 0 is not printable, so no need for the first check.
#define _CRT_SECURE_NO_WARNINGS
#ifdef __STDC_ALLOC_LIB__
#define __STDC_WANT_LIB_EXT2__ 1
#else
#include <stdlib.h>
#include <string.h>
char *strndup(const char *str, size_t size)
{
return strncpy(calloc(size + 1, 1), str, size);
}
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
size_t get_words_number(char const *str)
{
size_t count = 0;
const char *i = str;
while (*i != 0) {
if (isprint(*i)) {
count++;
}
while (*i != 0 && isprint(*i)) {
i++;
}
if (*i != 0) { // <--- This was missing
i++;
}
}
return count;
}
void my_free_word_array(char **word_array) // <--- Moved up
{
if (!word_array) {
return;
}
for (size_t i = 0; word_array[i] != NULL; ++i) { // <--- Stop thrashing word_array
free(word_array[i]);
}
free(word_array);
}
char **fill_array(char **array, const char *str, size_t word_count)
{
size_t word_size = 0, j = 0;
const char *i = str;
while (j < word_count) {
while (*i != 0 && isprint(*i)) {
word_size++;
i++;
}
array[j] = strndup(i - word_size, word_size);
if (!array[j]) {
my_free_word_array(array); // <--- No need for another free here
return NULL;
}
word_size = 0;
j++;
while (*i != 0 && !isprint(*i)) {
i++;
}
}
array[j] = NULL;
return array;
}
char **my_str_to_word_array(char const *str)
{
char **word_array = NULL;
size_t word_count = 0;
if (!str) {
return NULL;
}
word_count = get_words_number(str);
word_array = malloc((word_count + 1) * sizeof(char *)); // <--- You need a +1 here
if (!word_array) {
return NULL;
}
word_array = fill_array(word_array, str, word_count);
return word_array;
}
int main(int argc, char **argv)
{
char test[] = "My name is John Doe.\nI have 0 GPA.\nI will survive.\nThis will be removed from the string";
*strrchr(test,'\n') = 0;
char **word_array = my_str_to_word_array(test);
if (word_array) {
for (size_t i = 0; word_array[i] != NULL; ++i) { // <--- Stop thrashing word_array
printf("%s\n", word_array[i]);
}
printf("Test print original size %zu\n", strlen(test));
my_free_word_array(word_array);
}
return 0;
}
OP's code missed a check for a null character. #Costantino Grana
Candidate get_words_number() correction and simplification:
Count transitions from "non-word" to "word".
Use unsigned char* for defined use for all characters in is...() functions.
#include <ctype.h>
#include <stdbool.h>
size_t get_words_number(char const *str) {
const unsigned char *ustr = (const unsigned char *) str;
size_t count = 0;
bool previous_not_a_word = true;
while (*ustr) {
count += previous_not_a_word && isprint(*ustr);
previous_not_a_word = !isprint(*ustr);
ustr++;
}
return count;
}
The biggest problem with the OP code is that it has been fractured into so many helper functions that it is almost unreadable. A simple process has been muddied by this fragmentation.
Below is a "single pass" version that solves this problem. It does not involve helper functions with their parameters and maddening variable names.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
// OP string still as "string literal"
char *test = "My name is John Doe.\nI have 0 GPA.\nI will survive.";
// mutable copy of that string
char *copy = malloc( strlen( test ) + 1 ); // Verify!
strcpy( copy, test );
// get one element that is NULL
size_t cnt = 0;
char **arr = calloc( ++cnt, sizeof *arr ); // Verify!!
// chop copy on separators
char *cp = copy;
while( *cp ) {
// skip leading/trailing separators
while( *cp && !isprint( *cp ) ) cp++;
if( !*cp ) break; // was 1 or more trailing seps
// search for end of segment
char *ep = cp;
while( isprint( *ep ) ) ep++;
// remember if this is the final segment
bool atEnd = *ep == '\0';
// terminate segment and store pointer
*ep = '\0';
arr = realloc( arr, ++cnt * sizeof *arr ); // Verify!!!
arr[ cnt-2 ] = cp;
arr[ cnt-1 ] = NULL;
// move on (only if there is more to examine).
cp = ep + !atEnd;
}
// output
cnt = 0;
do
printf( "%d: %s\n", cnt, arr[ cnt ] ? arr[ cnt ] : "END OF ARRAY" );
while( arr[ cnt++ ] );
// cleanup
free( arr );
free( copy );
return 0;
}
The crucial verifications of return values from the heap allocation functions have been deliberately omitted to improve the clarity of this example code. Those verifications are left as an exercise for the reader.

Replace a word in string

How do i make below program work properly, The main problem i have seen so far is str1 is not defined properly which may be the real cause for the program not working properly.
#include<stdio.h>
#include<string.h>
int main()
{
char string[]="We will rock you";
char s1[10],s2[10];
printf("Enter string 1 ");
gets(s1);
printf("Enter string 2 ");
gets(s2);
int start,end,compare;
for(int i=0;string[i]!='\0';i++)
if(string[i]==s1[0])
{
start=i;
break;
}
//printf("%d",start);
end=start+strlen(s1);
//printf("\n%d",end);
char str1[30],check[10];
//Defining string 1
for(int i=0;i<start;i++)
str1[i]=string[i];
//printf("\n%sd",str1);
//Defining check
for(int i=start;i<end;i++)
check[i-start]=string[i];
//printf("\n%s\n",check,str1);
compare=strcmp(check,s1);
//printf("\n%d",compare);
if(compare==0)
strcat(str1,s1);
printf("\n%s",str1);
for(int i=end,j=strlen(str1);i<strlen(string);i++)
{
str1[j]=string[i];
}
strcpy(string,str1);
printf("\n%s",string);
}
I know this is not the best way to do it, it has so many loopholes as it wont work for words appearing again and it may also change words like (ask, task or asking) if str1 is given ask.
But still help me , What am i doing wrong???
What am i doing wrong???
For starters the function gets is unsafe and is not supported by the C Standard. Instead either use scanf or fgets.
If in this for loop
int start,end,compare;
for(int i=0;string[i]!='\0';i++)
if(string[i]==s1[0])
{
start=i;
break;
}
the condition string[i]==s1[0] does not evaluate to true then the variable start will have an indeterminate value because it is not initialized and all the subsequent code after the for loop invokes undefined behavior because there is used the uninitialized variable start.
If the condition evaluates to true then the value of end
end=start+strlen(s1);
can be larger than the length of the original string string. That again can invoke undefined behavior in this for loop
for(int i=0;i<start;i++)
str1[i]=string[i];
After this for loop
for(int i=start;i<end;i++)
check[i-start]=string[i];
//printf("\n%s\n",check,str1);
compare=strcmp(check,s1);
the array check does not contain a string. So calling the function strcmp also invokes undefined behavior.
It seems that in this call there is at least a typo.
if(compare==0)
strcat(str1,s1)
it seems you mean
strcat( str1, s2 );
^^^
If s1 was not found in string then this loop
for(int i=end,j=strlen(str1);i<strlen(string);i++)
{
str1[j]=string[i];
}
just does not make a sense.
Pay attention to that in general the length of s2 can be greater than the length of s1. In this case you may not change s1 to s2 within string declared like
char string[]="We will rock you";
because that results in accessing memory outside the array.
Function replacing string in the string.
char *strreplace(char *haystack, const char *needle, const char *replace, char *buff)
{
int length = strlen(haystack);
int needlelength = strlen(needle);
int replacelength = strlen(replace);
char *ptr = buff;
char *start, *source, *dest;
if (buff == NULL)
{
ptr = malloc((length + 1) * sizeof(char));
source = ptr;
dest = haystack;
}
else
{
source = haystack;
dest = buff;
}
if (ptr != NULL)
{
if (buff == NULL) strcpy(ptr, haystack);
else
{
if (!length)
{
*buff = 0;
}
}
while (needlelength && *source)
{
size_t chunklen;
char *result;
start = source;
if ((result = strstr(source, needle)) == NULL)
{
strcpy(dest, source);
break;
}
chunklen = result - start;
strncpy(dest, start, chunklen);
dest += chunklen;
strcpy(dest, replace);
dest += replacelength;
source = result;
source += needlelength;
}
if (buff == NULL)
{
free(ptr);
ptr = haystack;
}
else
{
ptr = buff;
}
}
return ptr;
}
Hello and Sorry for bad English.
I think this code can help you
char* replace ( char text[] , char mainchar, char replace_char )
{
char out [120];
char* out_pointer = out ;
register char index_2=0;
for ( register char index_1 = 0 ; index_1 < strlen (text) ; ++index_1 )
{
if ( text[index_1] != mainchar )
{
out_pointer[index_2]=text[index_1];
++index_2 ;
}
else
{
out_pointer[index_2]=replace_char;
++index_2 ;
}
}
return out_pointer;
}
To use this function in your source code, proceed as follows :
#include <stdio.h>
#include <string.h>
int main ()
{
char* replace ( char text[] , char mainchar, char replace_char )
{
char out [120];
char* out_pointer = out ;
register char index_2=0;
for ( register char index_1 = 0 ; index_1 < strlen (text) ; ++index_1 )
{
if ( text[index_1] != mainchar )
{
out_pointer[index_2]=text[index_1];
++index_2 ;
}
else
{
out_pointer[index_2]=replace_char;
++index_2 ;
}
}
return out_pointer;
}
char Array[100];
strcpy (Array, replace("Hello", 'H', 'e'));
printf ("%s", Array);
}

Copying specific number of characters from a string to another

I have a variable length string that I am trying to divide from plus signs and study on:
char string[] = "var1+vari2+varia3";
for (int i = 0; i != sizeof(string); i++) {
memcpy(buf, string[0], 4);
buf[9] = '\0';
}
since variables are different in size I am trying to write something that is going to take string into loop and extract (divide) variables. Any suggestions ? I am expecting result such as:
var1
vari2
varia3
You can use strtok() to break the string by delimiter
char string[]="var1+vari2+varia3";
const char delim[] = "+";
char *token;
/* get the first token */
token = strtok(string, delim);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, delim);
}
More info about the strtok() here: https://man7.org/linux/man-pages/man3/strtok.3.html
It seems to me that you don't just want to want to print the individual strings but want to save the individual strings in some buffer.
Since you can't know the number of strings nor the length of the individual string, you should allocate memory dynamic, i.e. use functions like realloc, calloc and malloc.
It can be implemented in several ways. Below is one example. To keep the example simple, it's not performance optimized in anyway.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char** split_string(const char* string, const char* token, int* num)
{
assert(string != NULL);
assert(token != NULL);
assert(num != NULL);
assert(strlen(token) != 0);
char** data = NULL;
int num_strings = 0;
while(*string)
{
// Allocate memory for one more string pointer
char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
if (ptemp == NULL) exit(1);
data = ptemp;
// Look for token
char* tmp = strstr(string, token);
if (tmp == NULL)
{
// Last string
// Allocate memory for one more string and copy it
int len = strlen(string);
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
++num_strings;
break;
}
// Allocate memory for one more string and copy it
int len = tmp - string;
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
// Prepare to search for next string
++num_strings;
string = tmp + strlen(token);
}
*num = num_strings;
return data;
}
int main()
{
char string[]="var1+vari2+varia3";
// Split the string into dynamic allocated memory
int num_strings;
char** data = split_string(string, "+", &num_strings);
// Now data can be used as an array-of-strings
// Example: Print the strings
printf("Found %d strings:\n", num_strings);
for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
// Free the memory
for(int i = 0; i < num_strings; ++i) free(data[i]);
free(data);
}
Output
Found 3 strings:
var1
vari2
varia3
You can use a simple loop scanning the string for + signs:
char string[] = "var1+vari2+varia3";
char buf[sizeof(string)];
int start = 0;
for (int i = 0;;) {
if (string[i] == '+' || string[i] == '\0') {
memcpy(buf, string + start, i - start);
buf[i - start] = '\0';
// buf contains the substring, use it as a C string
printf("%s\n", buf);
if (string[i] == '\0')
break;
start = ++i;
} else {
i++;
}
}
Your code does not have any sense.
I wrote such a function for you. Analyse it as sometimes is good to have some code as a base
char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
size_t srcLen;
char *result = buff;
if(str && buff)
{
if(*str)
{
srcLen = strlen(str);
if(srcLen < start + len)
{
if(start < srcLen) strcpy(buff, str + start);
else buff[0] = 0;
}
else
{
memcpy(buff, str + start, len);
buff[len] = 0;
}
}
else
{
buff[0] = 0;
}
}
return result;
}
https://godbolt.org/z/GjMEqx

Changing character in a string to two characters

Hello I have a problem with strchr() because yea it will return the pointer to the first occurance of the character but how do I get the index from that to be able to change it? and how can I change one character to two characters?
So I need to change every 'x' in the src to 'ks' in the dest.
My code:
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
strcpy(dest, src);
if (strchr(dest, 'x')) {
}
printf("\n%s", dest);
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}
You can do:
void antikorso(char *dest, const char *src) {
const char *p = src;
int i;
for (i = 0; *p != '\0'; i++, p++) {
if (*p != 'x') {
dest[i] = *p;
} else {
dest[i++] = 'k';
dest[i] = 's';
}
}
dest[i] = '\0';
printf("\n%s", dest);
}
following lines of code might be helpful :
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
int j=0;
for(int i=0;i<strlen(src);i++)
{
if (src[i] == 'x')) {
dst[j]='k';
j++;
dst[j] = 's';
j++;
}
else
{
dst[j] = stc[i];
j++;
}
i++;
}
dst[j] = '\0';
printf("\n%s", dest);
return dest;
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}
You may not need the index, just a pointer. The "index" would be the offset from the beginning, so dest[i], which is the same as dest + i, which is the address of dest, plus i characters further. So you can use:
char *cp;
if (cp=strchr(dest, 'x')) {
*cp= 'y';
But if you do want the index, it is just
if (cp=strchr(dest, 'x')) {
int i = cp - dest;
Other answers not being incorrect, just want to address an important issue: You are not safe from undefined behaviour by writing past the end of your target buffer (same problem as with so many stdlib functions like strcpy or strcat nowadays considered insecure)! So I strongly recommend modifying your function signature (if you have the freedom to do so):
size_t antikorso(char* dest, size_t length, const char* src)
// ^^ ^^
{
char* d = dest;
char* end = d + length;
for(; *src; ++src, ++d)
{
// not much different than the other answers, just the range checks...
if(d == end)
break;
*d = *src;
if(*d == 'x')
{
*d = 'k'
if(++d == end)
break;
*d = 's';
}
}
// now null-terminate your string;
// first need to get correct position, though,
// in case the end of buffer has been reached:
d -= d == end;
// this might possibly truncate a trailing "ks";
// if not desired, you need extra checks...
*d = 0;
return d - dest;
}
The return value does not add anything to safety, but prevents you from having to call strlen on the output, once written...
If strchr returns a valid address, you can use pointer arithmetic to get the index, by subtracting the "base address" - that is, the pointer to the first element of the array.
#include <string.h>
#include <stddef.h> // NULL, ptrdiff_t
const char* result = strchr(dest, 'x');
if ( result != NULL)
{
ptrdiff_t index = result - dest;
... // do stuff with index
}
ptrdiff_t is a standard C integer type suitable for expressing the result of pointer arithmetic.

String Split in C

I want to split a String in C.
My String is defined by my Struct:
struct String
{
char *c;
int length;
int maxLength;
}
Then I have a function that does the splitting. Perhaps C has something that does this, but although I wanted my own, I have not found anything that will do it so far.
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
// set of splitters: {'\n', ' '}
}
Input looks something like this: This is Sparta.
Then I want to return a pointer to each character array.
*p1 = This
*p2 = is
*p3 = Sparta.
If that makes any sense, I want an array of pointers, and each pointer points to a character array.
I will have to realloc the String as I increment the size of each character array. Probably my biggest problem is imagining how the pointers work.
Similar problem: c splitting a char* into an char**
So, how do I go about doing this?
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string test = "aa aa bbc cccd";
vector<string> strvec;
string strtemp;
string::size_type pos1, pos2;
pos2 = test.find(' ');
pos1 = 0;
while (string::npos != pos2)
{
strvec.push_back(test.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = test.find(' ', pos1);
}
strvec.push_back(test.substr(pos1));
vector<string>::iterator iter1 = strvec.begin(), iter2 = strvec.end();
while (iter1 != iter2)
{
cout << *iter1 << endl;
++iter1;
}
return 0;
}
Have you looked at strtok? It should be possible to do this using strtok.
here is a exemple :
String ** spliter(String *s)
{
int i;
int j;
char *p1;
char *p2;
char *p3;
i = 0;
j = 0;
if(s == NULL)
return NULL;
p1 = malloc(sizeof(*p1) * strlen(s));
p2 = malloc(sizeof(*p2) * strlen(s));
p3 = malloc(sizeof(*p3) * strlen(s));
while (s[i] != ' ')
{
p1[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != ' ')
{
p2[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != '\0')
{
p3[j++] = s[i];
i++;
}
printf("%s\n", p1);
printf("%s\n", p2);
printf("%s\n", p3);
}
You're looking for strtok, check out man 3 strtok, or here if you're not on *nix.
You would use it like this: (Assuming that you can write the add_string code yourself.)
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
String **return_strings = NULL;
char *delim = " \n";
char *string = strtok(s, delim);
int i = 0;
for(i = 0; add_string(return_strings, string, i) != -1; i++) {
string = strtok(NULL, delim);
}
return strings;
}
Note that if you need to save the original string (strtok modifies the string it works on), you'll need to call strdup on the original string, then operate on the copy.
EDIT: OP said he was having trouble thinking about the pointers. With the above code sample, add_string only has to worry about dealing with a string of characters, as opposed to an array of pointers to pointers to characters. So it might look something like this:
int add_string(String **strings, char *s, int len)
{
if(s == NULL)
return -1;
String *current_string = NULL;
strings = realloc(strings, sizeof(String) * (len + 1));
current_string = strings[len];
/* fill out struct fields here */
}
add strdup and strtok can work on a copy of the string. The split() call is more generic than the other spliter() examples, but does the same thing with strtok on a duplicate.
char **
split(char **result, char *w, const char *src, const char *delim)
{
int i=0;
char *p;
strcpy(w,src);
for(p=strtok(w, delim) ; p!=NULL; p=strtok('\0', delim) )
{
result[i++]=p;
result[i]=NULL;
}
return result;
}
void display(String *p)
{
char *result[24]={NULL};
char *w=strdup(p->c);
char **s=split(result, w, p->, "\t \n"); split on \n \t and space as delimiters
for( ; *s!=NULL; s++)
printf("%s\n", *s);
free(w);
}

Resources