Reverse a string without strtok in C - c

Working on a program that uses RPN (Reverse Polish Notation).
I have a function that reverses all the words of string without using strtok or triggering printf (unlike all the solutions found online and here).
The function actually works partially as it prints all the words of a given string except the last one and I need help figuring out what's going on.
char *extract(char s[]) {
if (s[0] == '\0')
return NULL;
int i = 0;
char *p = NULL;
while (s[i] != '\0') {
if (s[i] == ' ')
p = s + i;
i++;
}
if (p != NULL) {
*p = '\0';
return p + 1;
}
}
And then it's called in main like this:
char s[MAX] = "5 60 +";
while(s != NULL){
printf("%s\n", extract(s));
}
The output is + 60 with the cursor endessly waiting for something
but the expected output should be + 60 5

A standard approach is to reverse each word within a string and then to reverse the whole string.
Here you are.
#include <stdio.h>
#include <string.h>
static char * reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[ i ];
s[ i ] = s[ n - i - 1 ];
s[ n - i - 1 ] = c;
}
return s;
}
char * reverse_by_words( char *s )
{
const char *delim = " \t";
char *p = s;
while ( *p )
{
p += strspn( p, delim );
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
reverse( q, p - q );
}
}
return reverse( s, p - s );
}
int main(void)
{
char s[] = "5 60 +";
puts( s );
puts( reverse_by_words( s ) );
return 0;
}
The program output is
5 60 +
+ 60 5
If you want to keep leading and trailing spaces as they were in the original string then the functions can look the following way
#include <stdio.h>
#include <string.h>
static char *reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i -1 ];
s[n - i - 1] = c;
}
return s;
}
char * reverse_by_words( char *s )
{
const char *delim = " \t";
char *first = s, *last = s;
for ( char *p = s; *p; )
{
p += strspn( p, delim );
if ( last == s ) first = last = p;
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
last = p;
reverse( q, p - q );
}
}
reverse( first, last - first );
return s;
}
int main(void)
{
char s[] = "\t\t\t5 60 +";
printf( "\"%s\"\n", s );
printf( "\"%s\"\n", reverse_by_words( s ) );
return 0;
}
The program output is
" 5 60 +"
" + 60 5"

Related

C: outputs the total number of times the first word occurs

when I enter a sentence, this code should get the first word and count the how many times repeated.
firstWord(): This function gets the string as a parameter. Then, outputs the total number of times the first word occurs.
(this code consisting of 4 functions and in this func(firstWord()) I should use 'string' as a parameter, in main function I just call the firstWord func. )
number of times the first word occurs.
for ex: sentence is no changes and no suprises
first word no repeated 2 times.
here is the code.
void firstWord(char st3[]){
char firstw[20];
char *ptr;
int i=0;
int count=0;
ptr=strstr(st3,firstw);
while (ptr = '\0')
{
count++;
ptr++;
ptr = strstr(ptr, firstw);
}
printf("First word %s is repeated %d times\n", firstw, count);
}
The function does not make a sense.
You are using the uninitialized array firstw in a call of strtsr as for example
char firstw[20];
//..
ptr=strstr(st3,firstw);
that invokes undefined behavior.
Also there is a typo in the condition of the while statement
while (ptr = '\0')
Instead of using the equality operator == you are using the assignment operator = after which the pointer ptr becomes a null pointer.
At first you need to find the first word in the source string and then count how many times it is present in the source string.
Pay attention to that the function strstr can find a substring that does not form a word that is that is not delimited by white space characters.
Also at least the parameter of the function firstWord should be declared with the qualifier const because the source string is not changed within the function. And the return type of the function should not be void. The function should return the counter and the position and the length pf the first word in the source string as for example by using an object of a structure type.
The function can be implemented for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
struct Word
{
char *pos;
size_t length;
size_t counter;
};
struct Word firstWord( const char *s )
{
const char *delim = " \t\n";
struct Word word = { .pos = NULL, .length = 0, .counter = 0 };
while ( *s )
{
s += strspn( s, delim );
if ( *s )
{
size_t n = strcspn( s, delim );
if ( word.pos == NULL )
{
word.pos = ( char * )s;
word.length = n;
word.counter = 1;
}
else
{
if ( n == word.length && strncmp( word.pos, s, n ) == 0 )
{
++word.counter;
}
}
s += n;
}
}
return word;
}
int main( void )
{
const char *s = " A AB A ABC A";
struct Word word = firstWord( s );
if ( word.pos != NULL )
{
printf( "The first word \"%.*s\" is found %zu time(s)\n",
word.length, word.pos, word.counter );
}
}
The program output is
The first word "A" is found 3 time(s)
Using that function you can for example sort an array of strings in the lexicographical order of first words and if the words are equal in the ascending order of their counters in strings.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Word
{
char *pos;
size_t length;
size_t counter;
};
struct Word firstWord( const char *s )
{
const char *delim = " \t\n";
struct Word word = { .pos = NULL, .length = 0, .counter = 0 };
while ( *s )
{
s += strspn( s, delim );
if ( *s )
{
size_t n = strcspn( s, delim );
if ( word.pos == NULL )
{
word.pos = ( char * )s;
word.length = n;
word.counter = 1;
}
else
{
if ( n == word.length && strncmp( word.pos, s, n ) == 0 )
{
++word.counter;
}
}
s += n;
}
}
return word;
}
int cmp( const void *a, const void *b )
{
const char *s1 = *( const char * const * )a;
const char *s2 = *( const char * const * )b;
struct Word word1 = firstWord( s1 );
struct Word word2 = firstWord( s2 );
size_t n = word1.length;
if ( word2.length < n ) n = word2.length;
int result = strncmp( word1.pos, word2.pos, n );
if ( result == 0 )
{
result = ( word2.length < word1.length ) - ( word1.length < word2.length );
if ( result == 0 )
{
result = ( word2.counter < word1.counter ) - ( word1.counter < word2.counter );
}
}
return result;
}
int main( void )
{
const char * s[] =
{
"CCC CCC CCC",
"CCC CCC",
"BB BB",
"A A",
"CC",
"BB",
"CCC",
"A"
};
const size_t N = sizeof( s ) / sizeof( *s );
for ( size_t i = 0; i < N; i++ )
{
puts( s[i]);
}
putchar( '\n' );
qsort( s, N, sizeof( const char * ), cmp );
for ( size_t i = 0; i < N; i++ )
{
puts( s[i]);
}
putchar( '\n' );
}
The program output is
CCC CCC CCC
CCC CCC
BB BB
A A
CC
BB
CCC
A
A
A A
BB
BB BB
CC
CCC
CCC CCC
CCC CCC CCC
If you need to write a function that just determines the first word in a string then it can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
struct Word
{
char *pos;
size_t length;
};
struct Word firstWord( const char *s, const char *delim )
{
struct Word word = { .pos = NULL, .length = 0 };
while ( *s && word.pos == NULL )
{
s += strspn( s, delim );
if ( *s )
{
size_t n = strcspn( s, delim );
word.pos = ( char * )s;
word.length = n;
s += n;
}
}
if ( word.pos == NULL )
{
word.pos = ( char * )s;
}
return word;
}
int main( void )
{
const char *s = " A AB BA A";
struct Word word = firstWord( s, " \t\n" );
char first_word[word.length + 1];
strncpy( first_word, word.pos, word.length );
first_word[word.length] = '\0';
printf( "The first word is \"%s\" at position %zu\n",
first_word, word.pos - s );
}
The program output is
The first word is "A" at position 3
You don't consider that "cat can catch mice" should report only 1 occurrence of "cat".
Try this (or something like it):
void firstWord( char st3[] ) {
char *firstw = "EMPTY STRING";
int count = 0;
for( char *ptr = st3; ( ptr = strtok( ptr, " .,-" ) ) != NULL; ptr = NULL )
if( count == 0 ) {
firstw = ptr;
count++;
} else if( strcmp( ptr, firstw ) == 0 )
count++;
printf( "First word %s is repeated %d times\n", firstw, count );
}
Update
With the feedback "didn't work", I've added a few printf's to show that it does work...
void firstWord( char st3[] ) {
char *firstw = "EMPTY STRING";
int count = 0;
printf( "Using: '%s'\n", st3 );
for( char *ptr = st3; ( ptr = strtok( ptr, " .,-" ) ) != NULL; ptr = NULL )
if( count == 0 ) {
firstw = ptr;
count++;
} else if( strcmp( ptr, firstw ) == 0 )
count++;
printf( "First word %s occurs %d times\n\n", firstw, count );
free( st3 );
}
void my_main(void) {
firstWord( strdup( "cat can catch mice" ) );
firstWord( strdup( "cat cat catch cat" ) );
firstWord( strdup( " cat cat catch cat" ) );
firstWord( strdup( "dog dog dog dog dog" ) );
firstWord( strdup( "" ) );
}
Output:
Using: 'cat can catch mice'
First word cat occurs 1 times
Using: 'cat cat catch cat'
First word cat occurs 3 times
Using: ' cat cat catch cat'
First word cat occurs 3 times
Using: 'dog dog dog dog dog'
First word dog occurs 5 times
Using: ''
First word EMPTY STRING occurs 0 times

How to return a new string in a function in c?

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;
}

How to Reverse a sentence word by word?

I was trying to reverse a sentence word by word. (how are you -> you are how) First of all I create a char sentence and reverse and temp. Sentence given by user to reverse. Temp catches the word to change the location in the sentence.Then I use strcat to concatenate each word. Here is the problem. I can find the word which is end of the sent(takes input) but when I'm trying to concatenate to reverse, it add this word to sentence and an error occurs. What's the problem?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* subs(char* temp, char* src, int start, int end);
int main() {
char sent[15]; //input sentence
char rev[15]; // output sentence
char *temp=(char*)calloc(1,sizeof(char)); //for the word
scanf(" %[^\n]%*c", &sent); // takin' input
int i, end, start;
i = strlen(sent);
//find the beggining and ending of the indexes of the word in sentence
while (i > 0) {
while (sent[i] == ' ') {
i--;
}
end = i-1;
while (sent[i] != ' ') {
i--;
}
start = i + 1;
//add the word to temp and concatenate to reverse
temp=subs(temp, sent, start, end);
strncat(rev, temp,end-start+3);
}
rev[strlen(sent)] = '\0';
printf("%s", rev);
return 0;
}
char* subs(char* temp, char* src, int start, int end) {
int i = 0, control;
// resize the temp for the wırd
temp = (char*)realloc(temp,end-start+3);
for (; i < (end - start) + 1; i++) {
control = (start + i);
temp[i] = src[control];
}
//adding blank and null character to end of the word.
temp[i] = ' ';
temp[++i] = '\0';
return temp;
}
I will just copy my good answer from this question that was not yet closed Reverse a string without strtok in C
. So I can not use this reference to close your question as a duplicate.
A standard approach is to reverse each word within a string and then to reverse the whole string.
The standard C function strtok is not appropriate in this case. Instead use the standard C functions strspn and strcspn.
Here you are.
#include <stdio.h>
#include <string.h>
static char * reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[ i ];
s[ i ] = s[ n - i - 1 ];
s[ n - i - 1 ] = c;
}
return s;
}
char * reverse_by_words( char *s )
{
const char *delim = " \t";
char *p = s;
while ( *p )
{
p += strspn( p, delim );
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
reverse( q, p - q );
}
}
return reverse( s, p - s );
}
int main(void)
{
char s[] = "5 60 +";
puts( s );
puts( reverse_by_words( s ) );
return 0;
}
The program output is
5 60 +
+ 60 5
If you want to keep leading and trailing spaces as they were in the original string then the functions can look the following way
#include <stdio.h>
#include <string.h>
static char *reverse( char *s, size_t n )
{
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i -1 ];
s[n - i - 1] = c;
}
return s;
}
char * reverse_by_words( char *s )
{
const char *delim = " \t";
char *first = s, *last = s;
for ( char *p = s; *p; )
{
p += strspn( p, delim );
if ( last == s ) first = last = p;
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
last = p;
reverse( q, p - q );
}
}
reverse( first, last - first );
return s;
}
int main(void)
{
char s[] = "\t\t\t5 60 +";
printf( "\"%s\"\n", s );
printf( "\"%s\"\n", reverse_by_words( s ) );
return 0;
}
The program output is
" 5 60 +"
" + 60 5"

How to get substring of char* [duplicate]

This question already has answers here:
How to get substring in C
(4 answers)
Closed 7 years ago.
I have the following
char* str = "Some string";
How can I get a substring, from n to m symbols of str?
As following code:
int m = 2, n = 6;
char *p = (char *)malloc(sizeof(char) * (n - m));
for (size_t i = m; i < n; i++)
{
p[i - m] = str[i];
}
if(p)
printf("Memory Allocated at: %x/n",p);
else
printf("Not Enough Memory!/n");
free(p);
Here is a demonstrative program that shows how the function can be written.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char * substr( const char *s, size_t pos, size_t n )
{
size_t length = strlen( s );
if ( !( pos < length ) ) return NULL;
if ( length - pos < n ) n = length - pos;
char *t = malloc( ( n + 1 ) * sizeof( char ) );
if ( t )
{
strncpy( t, s + pos, n );
t[n] = '\0';
}
return t;
}
int main(void)
{
char* s = "Some string";
char *t = substr( s, 0, strlen( s ) );
assert( strlen( s ) == strlen( t ) && strcmp( t, s ) == 0 );
puts( t );
free( t );
size_t n = 5, m = 10;
t = substr( s, n, m - n + 1 );
assert( strlen( t ) == m - n + 1 && strcmp( t, "string" ) == 0 );
puts( t );
free( t );
return 0;
}
The program output is
Some string
string
Try using this code
char *str = "Some string"
char temp[100];
char *ch1, *ch2;
ch1 = strchr(str,'m');
ch2 = strchr(str,'n');
len = ch2-ch1;
strncpy(temp,ch1,len);
char destStr[30];
int j=0;
for(i=n;i<=m;i++)
destStr[j++] = str[i];
destStr[j] = '\0';
Just copy the required characters using the loop as shown above. If you opt not to use the existing string family functions.
You can use strscpn function. Try this
int start, end;
start = strcspn(str, "m"); // start = 2
end = strcspn(str, "n"); // end = 9
char *temp = malloc(end-start + 2); // 9 - 2 + 1 (for 'n') + 1(for '\0')
strncpy(temp, &str[start], end-start + 1);
temp[end-start + 1] = '\0';

Why do I get a segmentation fault when trying to map a string to its tokens?

I need to map string to arrays such that "hacker" maps to [ "h", "ack", "er" ]. That is, I need to find the largest sets of contiguous characters in a string that are in increasing order.
I have to write a function that takes
a string
a pointer to an array of strings
a pointer to the size of the latter
such that
f("hacker") = ([ "h", "ack", "er"], 3)
A typical call and use of this function would be
char **tokens = NULL;
size_t tokens_length = 0;
tokenize("hacker", &tokens, &tokens_size)
printf("[ ");
for (int i = 0; i < tokens_length; i++) {
printf("\"%s\", " tokens[i]);
}
printf("]");
Here's the body of the function that I wrote
void tokenize (const char *s, char ***tokens, size_t *tokens_length) {
char *current_ptr = NULL;
char *previous_ptr = NULL;
size_t characters_read = 0;
current_ptr = previous_ptr = s;
for (; current_ptr < s + strlen(s);) {
characters_read = characters_read + 1;
if (*(current_ptr + 1) < *current_ptr) {
*tokens_length = *tokens_length + 1;
*tokens = (char**)realloc((void*)*tokens, *tokens_length * sizeof(char*));
*tokens[*tokens_length - 1] = (char*)calloc(characters_read + 1, sizeof(char));
strncpy(*tokens[*tokens_length - 1], previous_ptr, characters_read * sizeof(char));
previous_ptr = current_ptr + 1;
characters_read = 0;
}
current_ptr = current_ptr + 1;
}
}
And here's the typical output ...
[1] 4789 segmentation fault (core dumped)
Do you have a clue about why I'm failing to manage the memory?
Here is the source that I'm trying to make it work.
Catch!:) At least I did not get a segmentation fault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t tokenize( const char *s, char ***tokens )
{
size_t n = 0;
const char *p;
*tokens = NULL;
p = s;
while ( *p )
{
for ( const char *q = p; !( *++p < *q ); ++q );
++n;
}
if ( n != 0 )
{
size_t i = 0;
*tokens = ( char ** )malloc( n * sizeof( char * ) );
p = s;
do
{
const char *q = p++;
while ( !( *p < *( p - 1 ) ) ) ++p;
( *tokens )[i] = malloc( p - q + 1 );
strncpy( ( *tokens )[i], q, p - q );
( *tokens )[i][p-q] = '\0';
++i;
} while ( *p );
}
return n;
}
int main(void)
{
char s[] = "hacker";
char **tokens;
size_t n;
n = tokenize( s, &tokens );
printf( "[ " );
for ( size_t i = 0; i < n; i++ )
{
printf( "\"%s\", ", tokens[i] );
}
printf( "]\n" );
free( tokens );
return 0;
}
The program output is the following
[ "h", "ack", "er", ]

Resources