I'm looking at writing a function that parses a given string input and separates the string into its constituents (as defined by one or more space characters).
Unfortunately, I have had no real experience with string parsing, so any help would be really appreciated!
Many thanks!
Take a look to strsep(3) too, since it is "intended as a replacement for the strtok() function."
https://www.freebsd.org/cgi/man.cgi?strsep(3)
The function can be declared and defined the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <ctype.h>
size_t string_parser( const char *input, char *word_array[] )
{
size_t n = 0;
while ( *input )
{
while ( isspace( ( unsigned char )*input ) ) ++input;
if ( *input )
{
word_array[n++] = ( char * )input;
while ( *input && !isspace( ( unsigned char )*input ) ) ++input;
}
}
return n;
}
#define N 10
int main(void)
{
char s[] = "Hello Sam Talbot. How do you do?";
char * word_array[N];
size_t n = string_parser( s, word_array );
for ( size_t i = 0; i < n; i++ ) puts( word_array[i] );
return 0;
}
Its output is
Hello Sam Talbot. How do you do?
Sam Talbot. How do you do?
Talbot. How do you do?
How do you do?
do you do?
you do?
do?
Another approach to defining the function is to allocate dynamically the array of words inside the function. In this case the function declaration can look like
size_t string_parser( const char *input, char ***word_array )
You should at first count the words using one loop and then in another loop fill the array of words.
For example
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
size_t string_parser( const char *input, char ***word_array)
{
size_t n = 0;
const char *p = input;
while ( *p )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
n += *p != '\0';
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
}
if ( n )
{
size_t i = 0;
*word_array = malloc( n * sizeof( char * ) );
p = input;
while ( *p )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
if ( *p )
{
const char *q = p;
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
size_t length = p - q;
( *word_array )[i] = ( char * )malloc( length + 1 );
strncpy( ( *word_array )[i], q, length );
( *word_array )[i][length] = '\0';
++i;
}
}
}
return n;
}
int main(void)
{
char s[] = "Hello Sam Talbot. How do you do?";
char ** word_array = NULL;
size_t n = string_parser( s, &word_array );
for ( size_t i = 0; i < n; i++ ) puts( word_array[i] );
for ( size_t i = 0; i < n; i++ ) free( word_array[i] );
free( word_array );
return 0;
}
The program output is
Hello
Sam
Talbot.
How
do
you
do?
Take a look at strtok, this does what you require.
You need to at least attempt this on your own.
Related
I am trying to write a program that compares strings by their length and sorts them with qsort. I have been able to make them sort alphabetically, now I'm trying to sort them by length. What am I doing wrong with my comparison method? I'm unsure about pointers and feel that issue lies there. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int stringCmp(const void *str1, const void *str2); //Function prototype.
int main (int argc, char *argv[])
{
int i;
char **arr = malloc(argc * sizeof(char *));
printf("Original Args:\n");
for (i = 0; i < argc-1; i++){
arr[i] = argv[i+1];
printf("%s\n",arr[i]);
}
qsort(arr, argc-1, sizeof *arr, stringCmp);
printf("\nSorted Args:\n");
for (i = 0; i < argc-1; i++){
printf("%s\n", arr[i]);
}
free (arr);
return 0;
}
int stringCmp(const void *str1, const void *str2)
{
return strlen(str1) - strlen(str2);
// return strcmp(*(char **)str1,*(char**) str2);
}
As with the commented out call to strcmp, the pointers received by the function actually have type char ** so you need to cast to that type.
return strlen(*(char **)str1) - strlen(*(char **)str2);
It seems you need to allocate argc - 1 pointers instead of argc pointers
char **arr = malloc( ( argc - 1 ) * sizeof(char *));
As for the comparison function then it can be defined the following way
int cmp( const void *s1, const void *s2 )
{
size_t n1 = strlen( *( const char ** )s1 );
size_t n2 = strlen( *( const char ** )s2 );
return ( n2 < n1 ) - ( n1 < n2 );
}
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmp( const void *s1, const void *s2 )
{
size_t n1 = strlen( *( const char ** )s1 );
size_t n2 = strlen( *( const char ** )s2 );
return ( n2 < n1 ) - ( n1 < n2 );
}
int main(void)
{
char * s[] = { "12345", "1234", "123", "12", "1" };
const size_t N = sizeof( s ) / sizeof( *s );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s ", s[i] );
}
putchar( '\n' );
qsort( s, N, sizeof( *s ), cmp );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s ", s[i] );
}
putchar( '\n' );
}
The program output is
12345 1234 123 12 1
1 12 123 1234 12345
Pay attention to that to implements the comparison function like
return strlen(*(char **)str1) - strlen(*(char **)str2);
will be incorrect because values of an expression of the unsigned integer type size_t can not be negative. And conversion such a value to the type int results in undefined behavior.
Hello my function should print str1 beginning with str2 (if found), I would like to return a new string (newStr) in the following function but it doesn't work. Some help please
char *myFunction(char *str1, char *str2){
int strLen;
int i;
int j;
char temp;
char *newStr;
strLen=0;
while(str1[strLen]!='\0'){
strLen++;
}
i=0;
j=0;
while(i<=strLen && str1[i]!='\0'){
if(str1[i]==str2[j] ){
newStr[i]=str1[i];
j++;
} else {
newStr[i]=str1[i];
}
i++;
}
return (newStr);
}
char *newStr is uninitialized; you must allocate memory to it, before assigning any value to it.
Allocate memory using malloc or calloc.
For starters the function should be declared like
char * myFunction( const char *str1, const char *str2 );
because the passed strings are not being changed within the function.
If the function has to return a new string then you need to allocate a character array where the string will be stored. However you are using an uninitialized pointer newStr
char *newStr;
The condition in the while loop
while(i<=strLen && str1[i]!='\0'){
does not make a great sense.
The variable j in fact is not used.
The if-else statement within the while loop does not make a sense.
If you are allowed to use standard C string functions then your function can be implemented very easy.
#include <string.h>
char * myFunction( const char *s1, const char *s2 )
{
char *p = strstr( s1, s2 );
if ( p != NULL )
{
size_t n = strlen( p );
s1 = p;
p = malloc( n + 1 );
if ( p != NULL ) memcpy( p, s1, n + 1 );
}
return p;
}
Otherwise the function can be defined the following way
char * myFunction( const char *s1, const char *s2 )
{
size_t n1 = 0;
while ( s1[n1] ) ++n1;
size_t n2 = 0;
while ( s2[n2] ) ++n2;
char *p = NULL;
if ( !( n1 < n2 ) )
{
int found = 0;
size_t i = 0;
while ( !found && i < n1 - n2 + 1 )
{
if ( s1[i] == s2[0] )
{
size_t j = 1;
while ( j < n2 && s1[i + j] == s2[j] ) ++j;
found = j == n2;
}
if ( !found ) ++i;
}
if ( found )
{
p = malloc( n1 - i + 1 );
if ( p != NULL )
{
size_t j = 0;
do
{
p[j] = s1[i + j];
} while ( p[j++] != '\0' );
}
}
}
return p;
}
I have a program which reads in the lines of a text file and stores them in linesArr, I have also defined a function compFunc which takes two strings as inputs, makes copies of them and converts the copies to lowercase before returning the value of strcmp(copy1, copy2). I am trying to use this function to sort linesArr into alphabetical order with qsort(linesArr, size, 255, compFunc. But the values in the array turn from {"Bob", "James", "Alice"} to {(null), (null), (null)}.
This is how linesArr is initialised.
char **linesArr = (char**)malloc(size*sizeof(char));
for (int i = 0; i < size; i++) {
linesArr[i] = (char*)malloc(255*sizeof(char));
}
And it it filled with values from the text using the file pointer fp
for (int i = 0; i < size; i++) {
fgets(line, 255, fp);
strcpy(linesArr[i], line);
}
Why is qsort deleting the values in the array?
For starters this memory allocation
char **linesArr = (char**)malloc(size*sizeof(char));
^^^^^
is incorrect, You need to write
char **linesArr = (char**)malloc(size*sizeof(char *));
^^^^^^
Secondly the call of qsort must look like
qsort(linesArr, size, sizeof( char * ), compFunc);
because the array pointed to by the pointer linesArr is an array of pointers.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int compFunc( const void *a, const void *b )
{
const char *s1 = *( const char ** )a;
const char *s2 = *( const char ** )b;
while ( *s1 && tolower( ( unsigned char )*s1 ) == tolower( ( unsigned char )*s2 ) )
{
++s1;
++s2;
}
return tolower( ( unsigned char )*s1 ) - tolower( ( unsigned char )*s2 );
}
int main(void)
{
enum { size = 3, len = 255 };
char **linesArr = malloc( size * sizeof( char * ) );
for ( size_t i = 0; i < size; i++ )
{
linesArr[i] = malloc( len * sizeof( char ) );
}
char line[len];
for ( size_t i = 0; i < size; i++ )
{
fgets( line, sizeof( line ), stdin );
line[ strcspn( line, "\n" ) ] = '\0';
strcpy( linesArr[i], line );
}
qsort( linesArr, size, sizeof( *linesArr ), compFunc );
for ( size_t i = 0; i < size; i++ )
{
puts( linesArr[i] );
}
for ( size_t i = 0; i < size; i++ )
{
free( linesArr[i] );
}
free( linesArr );
return 0;
}
The program output might look like
Bob
James
Alice
Alice
Bob
James
I need help to write a code that gets an array of unknown size and bubble sort it, every word between the spaces, ( only one space)
for example
bad dba = abd abd;
I wrote a code that gets a known size of strings,and I try to modify it and I can't think of anything.
Thanks in advance.!
my code so far is:
gets(strB);
do
{
flag = 0;
for
(q = 0; 'dont know what to put here'-J ; q++) {
if
(strB[q] > strB[q + 1])
{
// Swap
temp2 = strB[q];
strB[q] = strB[q + 1];
strB[q + 1] = temp2;
flag = 1;
}
}
j++;
} while
(flag != 0);
puts(strB);
We beginners should help each other.:)
If I have understood correctly you need to sort each word delimited by white spaces within a string.
You should write two functions. The first function splits a string into substrings and call a bubble sort function for each substring. The second function is a bubble sort function.
It can be done the following way
#include <stdio.h>
#include <ctype.h>
void bubble_sort( char *first, char *last )
{
for ( size_t n = last - first, sorted = n; !( n < 2 ); n = sorted )
{
for ( size_t i = sorted = 1; i < n; i++ )
{
if ( first[i] < first[i-1] )
{
char c = first[i];
first[i] = first[i-1];
first[i-1] = c;
sorted = i;
}
}
}
}
char * sort( char *s )
{
for ( char *p = s; *p; )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
if ( *p )
{
char *q = p;
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
bubble_sort( q, p );
}
}
return s;
}
int main(void)
{
char s[] = "bad dba";
puts( s );
puts( sort( s ) );
return 0;
}
The program output is
bad dba
abd abd
Take into account that the function gets is an unsafe function and is not supported any more by the C Standard. Instead use the C standard function fgets.
To remove the appended new line character by the function fgets use the following trick
#include <string.h>
//...
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '\0';
//...
Imagine I have the following string:
char input[] = "this is an example";
I want to take this string and make each word an entry in an array,
how could I get this into an array like this:
char inputArray[] = {"this","is","an","example"};
Either you do not know exactly what you want or you want the following:)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char input[] = "this is an example";
size_t n = 0;
for ( char *p = input; *p; )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
if ( *p )
{
++n;
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
}
}
char * inputArray[n];
size_t i = 0;
for ( char *p = strtok( input, " \t" ); p != NULL; p = strtok( NULL, " \t" ) ) inputArray[i++] = p;
for ( i = 0; i < n; i++ ) puts( inputArray[i] );
return 0;
}
The program output is
this
is
an
example