What is wrong with my squeeze() function? - c

Right now I'm working my way through "The C Programming Language" book and boy has it been a humbling experience. Right now I'm working on exercise 2-3 in the book and I can't figure out where I've gone wrong with my squeeze() function. The purpose of the function is to delete any characters in string 1 that are found in string 2. Right now all my function does is delete the first char of string1 if it's found in string2 and then acts strangely after that.. I looked in the answer book and the answer given is very confusing to me. It's hard to make sense of what is being done, so instead of following the logic in the answer book I sort of want to know where I'm going wrong in my own code... Here's the code below:
/* Write an alternate version of squeeze(s1, s2) that deletes each char in s1 that matches
* any char in string s2 */
/* Here's a reference for squeeze(s1, s2):
* squeeze: delete all c from s
*
* void squeeze(char s[], int c)
* {
* int i, j;
*
* for(i = j = 0; s[i] != '\0'; i++)
* if(s[i] != c)
* s[j++] = s[i];
* s[j] = '\0';
* }
*******************************************/
#include <stdio.h>
#include <string.h>
#define MAX_INPUT 100
void squeeze(char string1[], char string2[]);
int main()
{
int c, i = 0, j = 0;
char s1[MAX_INPUT + 2], s2[MAX_INPUT + 2];
printf("\nPlease enter string1\n");
while((c = getchar()) != '\n')
{
s1[i] = c;
i++;
}
s1[i] = '\0';
/* test to see if above worked */
printf("\ns1 = %s\n", s1);
printf("\nPlease enter string2\n");
while((c = getchar()) != '\n')
{
s2[j] = c;
j++;
}
s2[j] = '\0';
/* test to see if above worked */
printf("\ns2 = %s\n", s2);
printf("\nWe will now apply the squeeze function to remove any chars");
printf(" found in string2 from string1\n");
squeeze(s1, s2);
printf("Squeeze(s1, s2) = %s\n", s1);
}
void squeeze(char s1[], char s2[])
{
int i = 0, j = 1; /* for counters */
char temp; /* for char comparison */
temp = s2[0];
while(s2[i] != '\0')
{
if(s1[i] == temp)
{
s1[i] = s1[i+1];
j++;
}
else
{
j++;
}
temp = s2[j];
i++;
}
s1[i+1] = '\0';
}
My output is the following:
Please enter string1
hello
s1 = hello
Please enter string2
help
s2 = help
We will now apply the squeeze function to remove any chars found in string2 from string1
Squeeze(s1, s2) = eello
Can anyone spot what's wrong with my logic? From the answer book I'm guessing I need a third counter, k, somewhere but I can't see a reason for it with the way I programmed the function.. I know I'm missing something though! Thanks so much everyone :)
Answer ( thank you Vlad!) :
void squeeze(char s1[], char s2[])
{
int i = 0, j = 0;
do
{
int k = 0;
while(s2[k] != '\0' && s2[k] != s1[i])
++k;
if (s2[k] == '\0')
{
if ( j != i)
s1[j] = s1[i];
++j;
}
} while (s1[i++] != '\0');
}

Your function does not make a sense.
The while loop is executed according to the length of s2
while(s2[i] != '\0')
However you are using the same index i for checking the string s1.
if(s1[i] == temp)
But the string s1 can be in general shorter or larger than the string s2. So the function can invoke undefined behavior.
Also each character in s1 shall be checked in the string s2 starting from its beginning.
The function can be declared and defined (without using standard C string functions) as it is shown in the demonstrative program below.
#include <stdio.h>
char * squeeze( char s1[], const char s2[] )
{
if ( *s2 != '\0' )
{
size_t i = 0;
size_t j = 0;
do
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[i] ) ++k;
if ( s2[k] == '\0' )
{
if ( j != i ) s1[j] = s1[i];
++j;
}
} while ( s1[i++] != '\0' );
}
return s1;
}
int main(void)
{
char s1[] = "Hello World!";
const char *s2 = "aeiou";
puts( s1 );
puts( squeeze( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Hll Wrld!

I used tmp buffer to copy not containing characters. It is simpler and you can check it.
void squeeze(char s1[], char s2[]){
int i, j, k = 0;
char* tmp;
// tmp buffer initial size can be maximum s1 length
tmp = malloc(strlen(s1) + 1);
// loop until s1 character is null
i = 0;
while(s1[i] != '\0'){
// loop until character is found or to the end.
// break if s2 reached to the end or s1[i] == s2[j]
j = 0;
while(s2[j] != '\0' && s2[j] != s1[i]){
j++;
}
// if j reached to the end, add into tmp buffer
if(s2[j] == '\0'){
// set current character
tmp[k] = s1[i];
// increase index
k++;
} else {
printf("Found %c\n", s1[i]);
}
// next character
i++;
}
// last character must be null
tmp[k] = '\0';
// tmp copy to s1
strcpy(s1, tmp);
// free tmp buffer
free(tmp);
}

Related

Doubling all occurrences of a specific character in a string

I want to write a C program, that returns a new string allocated on the heap. This string is obtained by doubling all occurrences of “c” in a string (“abcdc” becomes “abccdcc” after doubling “c”).
This is my code and I don't really see where the problem is to fix it!
size_t taille = stringLength(str);
size_t k=0;
size_t q=0;
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
char *nouvelle=malloc(taille+1+k);
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
nouvelle[j]=str[i];
}
else
{
j=i;
++q;
nouvelle[j]=str[i];
j=i+q;
nouvelle[j++]=str[i];
}
++i;
}
nouvelle[taille+1+k]='\0';
return nouvelle;
}
There are two problems with your code.
The first one is that after this while loop
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
the pointer str points to the end of the string that is to the terminating zero character '\0'.
The second one is that you are using the uninitialized variable i
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
//..
This declaration
int i,j= 0;
is not the same as
int i = 0,j= 0;
That is only the variable j is initialized by 0.
And the statement
j = i;
does not make sense.
Also it is unclear whether c denotes a variable or the character 'c'. If you mean the character 'c' then you need to write at least like
if (*str == 'c')
You could define the function for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * duplicate_char( const char *s, char c )
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p == c) ++n;
}
char *nouvelle = malloc( strlen( s ) + n + 1 );
if (nouvelle)
{
if (n == 0)
{
strcpy( nouvelle, s );
}
else
{
char *p = nouvelle;
while (*s)
{
*p++ = *s++;
if (p[-1] == c) *p++ = c;
}
*p = '\0';
}
}
return nouvelle;
}
int main( void )
{
char *nouvelle = duplicate_char( "abcdc", 'c' );
if (nouvelle != NULL) puts( nouvelle );
free( nouvelle );
}
The program output is
abccdcc
If you want to use your own function stringLength instead of the standard C function strlen then it can look like
size_t stringLength( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}

Reverse of words of a given string in C using user defined functions

The code is not working it didn't give accurate results. I don't know where is the problem or miss coding?
My input and output:
Enter a sentence :
hello im here to help you
heleh im here to help you
I used the following code,
int main()
{
/*
Enter a sentence to get reverse of each word
hello this is CPROGRAM Enjoy Programming
olleh siht si MARGORPC yojnE gnimmargorP
*/
char str[100];
printf("Enter a sentence : \n");
fgets(str, 100, stdin);
revwords(str);
fputs(str, stdout);
return 0;
}
void revwords(char* str){
int i = 0;
for(int j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
}
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
}
}
Your rev function is broken in multiple ways:
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
}
}
First: Your swapping is broken. You assign to str[to-i] twice and never in the other direction.
void rev(char* str, int from, int to){
char temp;
for(int i=from;i<= to/2;i++){
temp = str[i];
str[i] = str[to-i];
str[to-i] = temp;
}
}
Then your index is not calculated correct.
You seem to try to reverse from from to to but you treat to as if it was a length.
You need to use a separate index:
void rev(char* str, int from, int to){
char temp;
for(int i=0; i <= (to-from)/2; i++){
temp = str[from+i];
str[from+i] = str[to-i];
str[to-i] = temp;
}
}
Otherwise if you reverse from 10..15 you will copy to index 5..0 instead of 15..10
#include<stdio.h>
int main()
{
/*
Enter a sentence to get reverse of each word
hello this is CPROGRAM Enjoy Programming
olleh siht si MARGORPC yojnE gnimmargorP
*/
char str[100];
printf("Enter a sentence : \n");
//fgets(str, 100, stdin);
scanf("%[^\n]s", str);
revwords(str);
//fputs(str, stdout);
printf("%s\n",str);
return 0;
}
void revwords(char* str){
int i = 0;
for(int j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
}
void rev(char* str, int from, int to){
char temp;
while(from <= to){
temp = str[from];
str[from] = str[to];
str[to] = temp;
from++;
to--;
}
}
You can try this code. In your code in rev function swap is not done with correct way. And for input a line you can use scanf("%[^\n]s", str);.
Another bug in your code you are not reverse the last word. so outside the for loop in your revwords function need to reverse the last word. which is not fix this code, try yourself and if not able to find then please comment.
void revwords(char* str){
int i = 0;
int j;
for(j=1;str[j] != '\0';j++){
if( str[j] == ' ' || str[j] == '\t' || str[j] == '\n'){
rev(str, i, j-1);
i = j+1;
j++;
}
}
rev(str,i,j-1);
}
Change with this block of code and hope it will solve. it's just a modified version of your code.
The both functions, rev and revwords, are incorrect.
For example in general the user can pass an empty string. In this case the function revwords invokes undefined behavior due to the initial condition in the for loop
for(int j=1;str[j] != '\0';j++){
Also if the passed string does not contain white spaces that is it contains only one word then nothing will be reversed.
In the function rev the condition of the loop is incorrect
for(int i=from;i<= to/2;i++){
For example if form is equal to 3 and to is equal to 5 then the expression i <= to/2 yields 2 and the loop will never be executed.
Apart from this the code that swaps characters
temp = str[i];
str[to-i] = str[i];
str[to-i] = temp;
is also incorrect.
And at least the function revwords should have the return type char * following the convention of standard C string functions.
Take into account that the function fgets can append the new line character to the entered string. You should remove it.
Here is a demonstration program that shows how the functions can be implemented. I only renamed the function names.
#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\n";
char *p = s;
while ( *p )
{
p += strspn( p, delim );
if ( *p )
{
char *q = p;
p += strcspn( p, delim );
reverse( q, p - q );
}
}
return s;
}
int main(void)
{
enum { N = 100 };
char s[N];
printf( "Enter a sentence: " );
fgets( s, N, stdin );
// remove the appended new line character '\n'
s[ strcspn( s, "\n" ) ] = '\0';
puts( s );
puts( reverse_by_words( s ) );
return 0;
}
The program output might look like
Enter a sentence: hello im here to help you
hello im here to help you
olleh mi ereh ot pleh uoy

If a string is rotation of other. All test cases Not running

I am using the logic of concatenation the 2nd string and then searching first string in it.
But for some reason, the code does not run for all test cases.
example
s1 = rahul , s2 = hulra
s2.s2 = hulrahulra
and then search s1 in s2.s2 using strstr() function.
#include <stdio.h>
#include <string.h>
int ifRotation(char *s1, char *s2)
{
int l1 = strlen(s1);
int l2 = strlen(s2);
char str1[l1], str2[l2+ l2];
int i;
i = 0;
while(*s1 != '\0')
{
str1[i] = *s1;
i++;
s1++;
}
i = 0;
while(*s2 != '\0')
{
str2[i] = *s2;
i++;
s2++;
}
strcat(s2, s2);
if(strstr(s2, s1))
{
return 1;
}
return 0;
}
int main() {
//code
int queries;
scanf("%d", &queries);
int array[queries];
char str1[100];
char str2[100];
int i = 0;
while(i < queries)
{
scanf("%s", &str1);
scanf("%s", &str2);
array[i] = ifRotation(str1, str2);
i++;
}
i = 0;
while(i < queries)
{
printf("%d\n", array[i]);
i++;
}
return 0;
}
Please tell me what's wrong with the code?
You are just copying from one string to another, and the copy routine has several problems.
char str1[l1] is not large enough. It should be char str1[l1 + 1]. The extra 1 is for the null character.
The string should always end with null character '\0'.
s1 and s2 are incremented until they reach the null character, so by that time s1 and s2 are empty.
Try the following code for copying the strings, you will see s1/s2 will be empty, str1/str2 are just copies of the original s1/s2.
You can fix the copying as follows:
char str1[l1 + 1], str2[l2 + 1];
int i;
i = 0;
while(*s1 != '\0')
{
str1[i] = *s1;
i++;
s1++;
}
str1[i] = '\0';
i = 0;
while(*s2 != '\0')
{
str2[i] = *s2;
i++;
s2++;
}
str2[i] = '\0';
printf("s1=%s, s2=%s, str1=%s, str2=%s\n", s1, s2, str1, str2);
//output: s1=, s2=, str1=old_s1, str2=old_s2
But this doesn't really achieve anything. If you just want to check "rahul" is the reverse of "hulra", keep s1 as it is, copy s2 to reverse_s2 in reverse order, and compare the two strings as follows:
#include <stdio.h>
#include <string.h>
int ifRotation(const char *s1, const char *s2)
{
if(!s1 || !s2)
return 0;
int len2 = strlen(s2);
char reverse_s2[len2 + 1];
//copy s2 to reverse_s2 in reverse order:
int i = 0;
for(i = 0; i < len2; i++)
reverse_s2[i] = s2[len2 - i - 1];
reverse_s2[i] = '\0'; //add null character
int result = strcmp(s1, reverse_s2) == 0;
return result;
}
int main(void)
{
printf("%d\n", ifRotation("rahul", "hulra"));
printf("%d\n", ifRotation("rahul", "luhar"));
return 0;
}

c- finding how many times a character occurs in a string

#include <stdio.h>
#include <string.h>
#define SIZE 40
int main(void)
{
char buffer1[SIZE] = "computer program";
char *ptr;
int ch = 'p', j = 0, i;
for (i = 0; i<strlen(buffer1); i++)
{
ptr = strchr(buffer1[i], ch);
if (ptr != 0) j++;
printf(" %d ", j);
}
}
I want to count how many times a character occurs in a string.
In my program I chose the character 'p'.
I know Pascal, I am learning C now. In pascal is a function called Pos(x,y) which is searching for x in y. Is something familiar to this? I think what I used here is not.
The function signature of strchr is
char *strchr(const char *s, int c);
You need to pass a char* but you have passed a char. This is wrong.
You have used the strlen in loop - making it inefficient. Just calculate the length of the string once and then iterate over it.
char *t = buffer;
while(t!= NULL)
{
t = strchr(t, ch);
if( t ) {
t++;
occurences++;
}
}
And without using standard library functions you can simply loop over the char array.
size_t len = strlen(buffer);
for(size_t i = 0; i < len; i++){
if( ch == buffer[i]) occurences++;
}
Or alternatively without using strlen
char *p = buffer;
while(*p){
if( *p == ch ){
occurences++;
}
p++;
}
Or
for(char *p = buffer; *p; occurences += *p++ == ch);
Try this example :
int main()
{
char buffer1[1000] = "computer program";
char ch = 'p';
int i, frequency = 0;
for(i = 0; buffer1[i] != '\0'; ++i)
{
if(ch == buffer1[i])
++frequency;
}
printf("Frequency of %c = %d", ch, frequency);
return 0;
}

Trying to count how many characters there are in a string in C

void reverse(char s[]) {
int i;
int len = 0;
for (i=0; s[i] != '0'; i++) {
len = len + 1;
}
Here is my code above. s[] is the string I am trying to reverse; Please help! Thanks
Use '\0' to test for the null terminating character.
for (i=0; s[i] != '\0'; i++) {
len = len + 1;
}
There isn't a strrev in standard C, but there are many implementations available around the net. Here's one I found here:
#include <string.h>
char *strrev(char *str)
{
char *p1, *p2, c;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
c = *p1;
*p1 = *p2;
*p2 = c;
}
return str;
}
Note that this modifies the given string and performs the reverse in place.
void reverse(char s[]) {
size_t i,j;
for(i=0; s[i] != '\0'; ++i)
;
if(i < 2)
return ;
for(j=0; j < --i; ++j){
char c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Strings in C are just an array of characters terminated with the null or the \0 character.
change your condition s[i] != '0' to that that checks whether the character at index i is of null or not.
Use
strrev(string1,string2)
in the string.h header. You can also use the
strlen(string1)
from the same header to find the length.

Resources