Stuck Finding Bug in LeetCode Question Solution - c

The problem is simple: take a string, and reverse the position of ONLY letters (lower or uppercase). Leave any special characters where they are. My solution:
char * reverseOnlyLetters(char * S){
int Len = strlen(S);
char *StrBeg, *StrEnd, tempCh;
bool FoundStart = 0, FoundEnd = 0;
StrBeg = S;
StrEnd = S + (Len - 1);
for (int i = 0; i < (Len/2); i++)
{
if (((*StrBeg>= 'A') && (*StrBeg <= 'Z')) || ((*StrBeg >= 'a') && (*StrBeg <= 'z')))
{
FoundStart = 1;
}
else
{
StrBeg++;
}
if (((*StrEnd >= 'A') && (*StrEnd <= 'Z')) || ((*StrEnd >= 'a') && (*StrEnd <= 'z')))
{
FoundEnd = 1;
}
else
{
StrEnd--;
}
if(FoundStart && FoundEnd)
{
tempCh = *StrEnd;
*StrEnd = *StrBeg;
*StrBeg = tempCh;
StrBeg++;
StrEnd--;
FoundStart = 0;
FoundEnd = 0;
}
}
return S;
}
The issue is a testcase like "a-bC-dEf-ghIj" fails; the "E" and the "f" in the middle either don't get swapped at all, or (as I suspect), get swapped, but then get swapped BACK. Anyone see what I'm doing wrong?

Problem is this for (int i = 0; i < (Len/2); i++).
If lenght of string is even, it's ok, but in case it's even it doesn't go through the middle character. E in this "a-bC-dEf-ghIj" case, so it can't switch it with f.

The approach using this for loop
for (int i = 0; i < (Len/2); i++)
is incorrect. Let's assume that the string is "#AB". The result string will look like "#BA"
But using your loop you will have (as Len / 2 is equal to 1)
for (int i = 0; i < 1; i++)
In the first and single iteration of the loop the pointer StrBeg will be incremented
StrBeg++;
because the pointed character is not a letter.
So nothing will be reversed.
The function can be written simpler the following way
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * reverse_letters( char *s )
{
for ( char *first = s, *last = s + strlen( s ); first < last; ++first )
{
while ( first != last && !isalpha( ( unsigned char )*first ) ) ++first;
while ( last != first && !isalpha( ( unsigned char )*--last ) );
if ( first != last )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main( void )
{
char s[] = "one, two, three";
puts( s );
puts( reverse_letters( s ) );
char s1[] = "#AB";
puts( s1 );
puts( reverse_letters( s1 ) );
}
The program output is
one, two, three
eer, hto, wteno
#AB
#BA

Related

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

How to remove even occurences of a substring in a string

i am trying to remove even occurences of a substsring, for example if i have A11B11C11 and i want to remove 11, it will remove the ones on position 0 and 2, so it should look like AB11C.
This is the function i have thus far, it removes all the occurences.
void removeSubstr(char* s, char* c)
{
int poz = -1;
int i = 0;
int string_length = strlen(s);
int number_length = strlen(c);
while (i < string_length) {
if (strstr(&s[i], c) == &s[i]) {
poz++;
if (poz % 2 == 0) {
string_length -= number_length;
for (int j = i; j < string_length; j++) {
s[j] = s[j + number_length];
}
}
}
else {
i++;
}
}
printf("'%d'", poz);
s[i] = '\0';
}
My approach was that whenever i find one occurence i should add it to a counter, and whenever the counter is divisible with 2, i remove the substring, but it always removes all the substrings.
edit:
if (strstr(&s[i], c) == &s[i]) {
poz++;
if (poz % 2 == 0) {
string_length -= number_length;
for (int j = i; j < string_length; j++) {
s[j] = s[j + number_length];
}
}
else {
i++; //added this
}
}
As was told in comment, i had to increment the i as well when there was an odd occurence, and now it works.
For starters the function should return the modified source string. Also as the substring is not changed within the function then the corresponding function parameter should be declared with the qualifier const
char * removeSubstr( char *s1, const char *s2 );
Calling the function strstr starting from each character of the source string as you are doing
while (i < string_length) {
if (strstr(&s[i], c) == &s[i]) {
is not efficient. The substring initially can be absent in the source string.
Also if you have the source string like this "A11111" then it seems the result string should look like "A111" because after the first substring "11" is removed when in this string "A111" the substring "11" is odd and must not be removed.
However using your approach you will get the result string "A1". That is in the else statement you should write
else {
i += number_length;
}
I would write the function the following way as it is shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
char * removeSubstr( char *s1, const char *s2 )
{
size_t pos = 0;
size_t n1 = strlen( s1 ), n2 = strlen( s2 );
for ( char *prev = s1, *next = s1 ; ( next = strstr( prev, s2 ) ) != NULL; prev = next )
{
n1 -= next - prev - n2;
if ( pos++ % 2 == 0 )
{
memmove( next, next + n2, n1 + 1 );
}
else
{
next = prev + n2;
}
}
return s1;
}
int main( void )
{
char s1[] = "A11B11C11";
const char *s2 = "11";
printf( "\"%s\"\n", s1 );
printf( "\"%s\"\n", removeSubstr( s1, s2 ) );
}
The program output is
"A11B11C11"
"AB11C"

How to write function that return dynamic allocated string?

I have assignment that to use function char *slova(const char *s) which returns dynamically allocated string that is only made of small and big letters. It's forbidden to use string.h library.
char *slova(const char *s)
{
char *new;
int br = 0;
new = (char *)malloc(sizeof(s));
for (int i = 0; i != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z')
{
new[br] = s[i];
br++;
}
return new;
}
I know there are some other characters other than small and big letters between A and z in ASCII code, so don't worry about that. For some reason this code doesn't work and I don't know why.
sizeof(s) will return not the buffer size but the size of the pointer s.
i != '\0' is wrong. This means i != 0 and prevent it from entering the loop because initial value of i is 0.
You forgot to terminate the resulting string by adding a terminating null-character.
Casting the result of malloc() in C is discouraged.
Fixed code:
char *slova(const char *s){
char *new;
int br = 0;
// calculate the length
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
br++;
}
// allocate buffer
new = malloc(br + 1);
if (new == NULL) return NULL;
// actually create the string
br = 0;
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
new[br] = s[i];
br++;
}
new[br] = '\0';
return new;
}
Look carefully at your function declaration
char *slova(const char *s){
^^^^^^^^^^^^^
Its parameter has the pointer type const char *. Thus in this statement
new = (char *)malloc(sizeof(s));
the expression sizeof(s) yields the size of a pointer that usually is equal to 8 or 4 bytes depending on the used system. That is this expression does not provide the length of the passed string.
Also the body of this loop
for (int i = 0; i != '\0'; i++)
never gets the control because the condition i != '\0' at once evaluates to false because the variable i was initialized by zero.
The function can look the following way as it is shown in the demonstrative program below. It does not use functions from the header <string.h>.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char * slova( const char *s )
{
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
if ( isalpha( ( unsigned char )*t ) ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
if ( isalpha( ( unsigned char )*s ) )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
The program output is
HelloWorld
If you are not allowed also to use functions from the header <ctype.h> then the function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
char * slova( const char *s )
{
const char *upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *lower_case = "abcdefghijklmnopqrstuvwxyz";
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
const char *letter = lower_case;
if ( *t < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *t ) ++letter;
if ( *letter == *t ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
const char *letter = lower_case;
if ( *s < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *s ) ++letter;
if ( *letter == *s )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
Again the program output is
HelloWorld

Replacing several characters in string with one in C

I need to replace several characters with one (depending if their count is even or odd). If it's even i should replace + with P, if it's odd with p.
Input: kjlz++zux+++
while(p[i])
{
j=i;
k=i;
length=strlen(p);
if(p[i]=='*')
{
position=i;
}
printf("Position is: %d", position);
while(p[j]=='*')
{
counter++;
j++;
}
}
Output: kjlzPzuxp
Im not sure how to remove several characters I know how to input one.
Basically you can leave the text variable intact until you find a +. In that case you start counting how many consecutive plusses there are. Once you know this, it can be decided if you should add a letter P or p. Keep a separate index to write back to your text variable! Otherwise it would start writing to the wrong index after 2 or 3 plusses are found, try to figure out why ;).
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char text[] = "kjlz++zux+++";
int len = sizeof(text) / sizeof(text[0]);
int index = 0, count = 0;
for(int i = 0; i < len; i++)
{
if(text[i] == '+')
{
count = 0;
while(text[i] == '+') i++, count++;
i--;
text[index++] = count % 2 ? 'p' : 'P';
}
else
{
text[index++] = text[i];
}
}
text[index] = 0;
printf(text);
}
You could allocate space for the text variable with malloc so that you can use realloc afterwards to shrink the array to the size of the output text. This way some memory is saved, this is especially important when you start working with bigger chunks of data.
If I have understood correctly you do not know how to implement a corresponding function.
It can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
char * replace_pluses( char *s )
{
const char plus = '+';
const char odd_plus = 'p';
const char even_plus = 'P';
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == plus )
{
int odd = 1;
while ( *++src == plus ) odd ^= 1;
*dsn++ = odd ? odd_plus : even_plus;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_pluses( s ) );
return 0;
}
The program output is
kjlz++zux+++
kjlzPzuxp
Or you can write a more generic function like this
#include <stdio.h>
char * replace_odd_even_duplicates( char *s, char c1, char c2, char c3 )
{
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == c1 )
{
int odd = 1;
while ( *++src == c1 ) odd ^= 1;
*dsn++ = odd ? c2 : c3;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_odd_even_duplicates( s, '+', 'p', 'P' ) );
return 0;
}

how to compare two 2 d string without using strcmp

I have data file in which some data is kept.
example: welcome user HII if while
I have made 2D character array to store all the keywords in c.
now I want two know if the data file contain the keyword or not.
enter code here
for(i=0;i<32;i++)
for(j=0;j<no_of_words_in_file;j++)
if(k[i]==t[j])
printf("%s is keyword",t[j]);
here the k[i] represents the 2D character array where all the keywords in c are stored and t[i] represents the 2D character array where all the words of file are stored.
I want to compare these 2D arrays without using strcmp.
To compare two strings without using standard C functions you can use a loop like that
#include <stdio.h>
int main(void)
{
char key[] = "while";
char word1[] = "while";
char word2[] = "when";
size_t i = 0;
while ( key[i] != '\0' && key[i] == word1[i] ) ++i;
int equal = key[i] == word1[i];
printf( "key == word1: = %d\n", equal );
i = 0;
while ( key[i] != '\0' && key[i] == word2[i] ) ++i;
equal = key[i] == word2[i];
printf( "key == word2: = %d\n", equal );
return 0;
}
The program output is
key == word1: = 1
key == word2: = 0
Or you can write a separate function. For example
#include <stdio.h>
int equal( const char *s1, const char *s2 )
{
while ( *s1 != '\0' && *s1 == *s2 )
{
++s1; ++s2;
}
return *s1 == *s2;
}
int main(void)
{
enum { N = 10 };
char key[][N] ={ "if", "while" };
const size_t N1 = sizeof( key ) / sizeof( *key );
char words[][N] = { "welcome", "user", "HII", "if", "while" };
const size_t N2 = sizeof( words ) / sizeof( *words );
for ( size_t i = 0; i < N2; i++ )
{
for ( size_t j = 0; j < N1; j++ )
{
if ( equal( key[j], words[i] ) )
{
printf( "\"%s\" == \"%s\"[%zu]\n", key[j], words[i], i );
}
}
}
return 0;
}
the program output is
"if" == "if"[3]
"while" == "while"[4]

Resources