Decrease nested loops quantity - c

Below is the code where I have to check a specific character in substring of string. How can I decrease its complexity, as I use three for loops but want to do it in two or one loop?
int main(void) {
int i, j, k, t, n;
scanf("%d", &t);
while (t--) {
int count = 0;
scanf("%d", &n);
char a[n], ch;
scanf("%s %c", a, &ch);
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
for (k = i; k <= j; k++) {
if (a[k] == ch) {
count++;
break;
}
}
}
}
printf("%d", count);
}
}

So what it looks like from your code is that your trying to generate a set of substrings, so if your array was abc then the substrings would be a, ab, abc, b, bc, c. You then try and count the number of times a character appears, so if ch = 'b' then the result would be 4. So you are counting the number of strings that contain ch.
So one way to solve this problem with fewer loops would be to recognise for each value of i you create the strings by adding a character to the last string, and if the previous string contained n copies of ch then the next string contains n or n+1 copies depending on the actual value.
Another possible approach to get down to just one loop would be loop through the array once and each time you find the character ch calculate how many sub-strings will contain the character at that position. So for the abc example 2 of the 3 strings starting at position 0 and 2 of the strings starting at position 1 will contain the value.

You can use memchr instead of the most inner loop.
Substitute
for (k = i; k <= j; k++) {
if (a[k] == ch) {
count++;
break;
}
}
for
if (memchr(&a[i], ch, j - i + 1) != NULL) {
count++;
}
This will make you use two loops in your code.

Related

comparing a char to a string in C

I'm quite new to C and I'm wondering why in the code below, the char I'm comparing to each letter of the string word is showing that it's equal everytime.
For example
If I've inputted the word
apple
and I'm looking for any repeating char in "apple" my function. I pass in to the function each char of apple such as a, p, p etc. It should return 1 when I pass in p since it's repeated, but instead, for every char of apple, my function says a == word[0], a == word[1] even though word[1] for "apple" is 'p'.
I know char is ASCII, so each char has a number value, but I'm not sure why this is not working. Perhaps, I'm using the pointer *word in the functions arguments incorrectly?
My code is below for my function, rpt_letter:
int rpt_letter(char *word, char c)
{
int i;
int count = 0;
i = 0;
printf("This is the WORD %s\n", word);
while(count < 2)
{
if(word[i] == c)
{
count++;
printf("the count is %d\n the char is %c and the string is %c\n", count, c, word[i]);
}
i++;
}
if (count<2)
{
// printf("letter %c was not found in the array. \n", c);
return 0;
}
else
{
//printf("letter %c was found at index %d in the array.\n", c, mid);
repeats[rpt_counter] = c;
rpt_counter++;
return 1;
}
return 0;
}
I'll include the main method just in case -- but I believe the main method is working well
int main(void)
{
//! showArray(list, cursors=[ia, ib, mid])
//int n = 51;
char word[51];
scanf("%s", word);
//length of string
for (n=0; word[n] != '\0'; n++); //calculate length of String
printf("Length of the string: %i\n", n);
int count = 0;
//sort words
int i;
char swap = ' ';
for(int k = 0; k < n; k++)
{
for (i=0; i<n-1; i++)
{
//if prev char bigger then next char
if (word[i] > word[i+1])
{
//make swap = prev char
swap = word[i];
//switch prev char with next char
word[i] = word[i+1];
//make next letter char
word[i+1] = swap;
}
}
}
printf("%s\n", word);
for (i=0; i<n-1; i++)
{
int rpt = rpt_letter(word, word[i]);
if(rpt == 1)
{
count++;
}
}
printf("%d", count);
return 0;
}
I've tried a number of things such as using the operator !=, also <, > but it gives me the same result that each word[ia] == c.
You are getting this issue because in your code rpt_letter() the while loop has a terminating condition count >= 2. Now consider input apple and character a. As a appears in apple only once, the count after traversing the whole word remains 1. But the loop doesn't terminate. So, the index i becomes greater than the length of string and tries to check the character appearing after that.
The loop terminates eventually when it gets another a this way. You need to add a check for the terminating null character in your loop so that it doesn't cross the length of the string .
Change the while loop condition to something like -
while((count < 2) && (word[i] != '\0'))

C Unwanted random characters being printed

I have written some code in C, what it does is take an input of 2 strings A, B Where A is a normal string and B is a Sub string inside B. The program will "cut" out all the appearances of the sub sting B inside the string A. For example: A = "asdLEONasd", B = "asd" => C(Result) = "LEON".
everything seems to be working fine except after the output stage where it prints out a few unwanted characters.
Here are 2 examples for this: (the unwanted characters are underlined with a red pen)
Example 1
Example 2
The code:
#include <stdio.h>
#include <string.h>
void main()
{
int len1, len2;
puts("Input a length for a");
scanf("%d",&len1);
// Initializing A
char a[len1 + 1];
puts("Input a");
scanf("%s" ,a);
puts("Input length for b");
scanf("%d",&len2);
//Initializing B
char b[len2 + 1];
puts("Input b");
scanf("%s" ,b);
int i, j , k, count1 = 0, count2;
for(i = 0; i < len1; i++) //Loop that goes over string a
{
count2 = 0, k = 0;
for(j = i; j < len2 + i; j++) //Loop that goes over a part of a (from i to i + len2)
{
if(a[j] == b[k])
{
count2++; //Counting how many characters match with the sub string B
}
k++;
}
if(count2 == len2) //If counted characters = len2 then we know that we found the Sub string B in A
{
count1++; //Counting each appearance of B in A
for(j = i; j < len2 + i; j++) //Loop that marks cells that represent the sub string B in A
{
a[j] = '0'; //Marking cells that are the sub string b
}
}
}
if(!count1) //If count1 remained as 0 then B does not appear in A, which means the result is A
{
puts(a);
}
else
{
j = 0;
int len3 = len1 - count1 * len2; //Determining resulting array size
char c[len3]; // Initializing array C
//Filling array C accordingly
for(i = 0; i < len1; i++)
{
if(a[i] != '0')
{
c[j] = a[i];
j++;
}
}
puts(c);
}
}
What I find most weird is when my output array has a size of 4 for example, and it still prints the extra characters regardless the size.
I'm very curious as of why this happening and how can it be fixed?
You should think of a dumb implementation of puts as follows:
void puts(char *s)
{
while (*s) //if the current character isn't 0
{
putchar(*s); //print the character
++s; //move to the next character
}
putchar('\n');
}
Therefore, if the last character in your array isn't 0, the above loop will continue until there happens to be a 0 somewhere in the memory that follows.
If you're unable to add this terminating zero (as already mentioned by Bathsheba and yourself), you could use printf.
When using the printf family of functions, you can use the %s specifier to format a string (such as padding and limiting it's length).
char x[] = {'a', 'b', 'c', 'd'};
//print just abc
printf("%.*s\n", 3, x);
//print just abc
printf("%.3s\n", x);
//print just bcd
printf("%.*s\n", 3, x+1);
The problem was in the array C.
Changing char c[len3]; to char c[len3 + 1]; and adding an initialization c[len3] = '\0'; fixed this.
Before the third lines in the reciprocal of the program,that's right in front of this statement puts(c), if you add c[j]='\0', the problem you said will be solved.

C Program Printing Duplicate Char

I'm trying to make a program in C that reads a word and prints if there are any duplicates and if so the number of occurrences. It works (as you can see in the attached pic) but once a letter has been printed I don't want it to reprint the same letter.
I've tried storing the duplicate chars in an array and then comparing the new duplicate to the duplicate array but it doesn't seem to be working.
Anyone know a simple way to not reprint?
#include <stdio.h>
#include <string.h>
int main(void) {
char word[100];
int x, i, j, freq, duplicates;
printf("Enter a word>\n");
scanf("%s", word);
x = strlen(word);
duplicates = 0;
freq = 1;
for(; i < x; i++) {
j = 0;
for(; j < x; j++) {
if ((word[i] == word[j]) && (i != j)) {
freq = freq + 1;
}
}
if (freq >= 2) {
printf("Duplicate letter: %c, Occurences: %d\n", word[i], freq);
duplicates = 1;
freq = 1;
}
}
if (duplicates < 1) {
printf("No duplicates found\n");
}
return 0;
}
Your problem here is in fors that look for the duplicate letter
The first one should go throw the string to look for all letters:
for (i = 0; i < x; i++) {
The second should look for the occurrence of the same character:
for (j = i; j < x; j++) {
Its because it runs once on each time it finds t and e respectively. One solution would be to find all occurrences of that char in the char array after printing the duplicate notification and removing it.
char * removeLetterFromArray(int toBeRemoved, char* string, int stringLength){
char * newString = malloc(stringLength * sizeof(char));
for(int i = 0; i < toBeRemoved; i++){
newString[i] = string[i];
}
for(int i = toBeRemoved; i < stringLength; i++){
newString[i] = string[i + 1];
}
return newString;
}
that code should remove the letter that you define the index of with toBeRemoved
So after you find a letter that has a duplicate loop through the code to find all places that letter occurs and pass them indexs to the above method.
If you do not wish to use the above method another option would be to create an array of letters that have already been output and ignore these letters in the future.

How to find number of times that a given word occurs in a sentence [C code]?

Here is my code. I need to find out the number of times a given word(a short string) occurs in a sentence(a long string).
Sample Input: the
the cat sat on the mat
Sample Output: 2
For some reason the string compare function is not working and my output is coming as zero. Kindly ignore the comments in the code as they have been put to debug the code.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
char word[50];
gets(word);
int len = strlen(word);
//printf("%d",len);
char nword[len];
char s[100];
strcpy(nword,word);
puts(nword);
printf("\n");
gets(s);
//printf("%d",strlen(s));
char a[50][50];
int i,j,k;
j = 0;
for(i=0;i<strlen(s);i++)
{
a[i][j] = s[i];
printf("%c",a[i][j]);
if(s[i] == ' ')
{
j++;
printf("\n");
}
}
printf("%d",j);
k = j;
//printf("\nk assigned\n");
j = 0;
//printf("j equal to zero\n");
int count = 0;
int temp = 0;
//printf("count initialized.\n");
for(i=0;i<k;i++)
{
if(strcmp(a[i],nword) == 0)
count++;
}
printf("\n%d",count);
return 0;
}
Your main problem is with this loop for numerous reasons
int i,j,k;
j = 0;
for(i=0;i<strlen(s);i++)
{
a[i][j] = s[i];
printf("%c",a[i][j]);
if(s[i] == ' ')
{
j++;
printf("\n");
}
}
Firstly you've got your indexes into a backwards - a[i][j] means the i-th string and the j-th character, but since you're incrementing j for each word you want it the other way around - a[j][i].
Secondly you can't use i for both indexing into s and a. Think about what happens when you are building the second string. In your example input the second word starts when i is 4 so the first character will be stored as a[1][4]=s[4] which leaves a[1][0] to a[1][3] uninitialised. So you have to use a 3rd variable to track where you are in the other string.
When you hit a space, you don't want to add it to your word as it won't match later on. You also need to add in a null-terminator character to the end of each string or else your code won't know where the end of the string is.
Putting the above together gives you something like this:
int i,j,k;
k = j = 0;
for(i=0;i<strlen(s);i++)
{
if(s[i] == ' ')
{
a[j][k] = '\0';
j++;
k=0;
printf("\n");
}
else
{
a[j][k] = s[i];
printf("%c",a[j][k]);
k++;
}
}
a[j][k]='\0';
The problem is that a is a two-dimentional array and you reference it as a one dimention. Maby you use a 2-dimentional array to represent i=line, j=character. If you keep this idea then you'll have to do this:
j=0;
for(i=0;i<k;i++)
{
if(strcmp(a[i][j],nword) == 0)
count++;
j++;
}
But then it will be difficult to detect words that are split in half. I'd recommend keeping a as a one dimentional array. Copy the contents of s[i] serially and when you want to distinguish lines use the \r\n operator.
I think you use your 2-dimensional array wrong. a[0][j] should be the first word from s[i]. But what you are doing is a[i][0] = s[i] which makes no sense to me.
Best regards
I would implement this using the functions strtok() and strcmp():
int main(void)
{
char word[] = "the"; /* the word you want to count*/
char sample[] = "the cat sat on the mat"; /* the string in which you want to count*/
char delimiters[] = " ,;.";
int counter;
char* currentWordPtr;
/* tokenize the string */
currentWordPtr = strtok(sample, delimiters);
while(currentWordPtr != NULL)
{
if(strcmp(word, currentWordPtr) == 0)
{
counter++;
}
/* get the next token (word) */
currentWordPtr = strtok(NULL, delimiters);
}
printf("Number of occurences of \"%s\" is %i\n", word, counter);
return 0;
}

Finding Prefix as Suffix in a string

I already posted this question but I'm still struggling to get it properly working. Dreamlax tried to help me out by giving the following steps -
starting with n = 1, Take the first n characters from the string.
Compare it to the last n characters from the string
Do they match?
If yes, print out the first n characters as the suffix and stop processing.
If no, increment n and try again. Try until n is in the middle of the string.
Here's my code which doesn't work:
#include <stdio.h>
#include <string.h>
void main()
{
int i, T, flag, j, k, len = 0, n;
char W[20], X[20], A[20], B[20];
scanf("%d", &T);
for (i = 0; i < T; i++)
{
scanf("%s", W);
for (len = 0; W[len] != '\0'; len++)
X[len] = W[len];
X[len] = '\0';
len--;
n = 1;
while (n < len / 2)
{
for (k = 0; k < n; k++)
A[k] = W[k];
for (k = 0, j = len - n; W[j] != '\0'; j++, k++)
B[k] = W[j];
if (!strcmp(A, B))
{
printf("YES\n");
break;
}
else
{
n++;
}
}
printf("NO\n");
}
}
Help me in pin pointing the error please.
There are several things going on in your code:
You should null-terminate your auxiliary strings A and B. Alternatively, yopu could compare just then n first characters with strncmp instead of strcmp.
strcmp is a comparison function. It returns zero if the strings match. (Comparison function means it can be used in sorting to determine whether a string is lexically greater or smaller than another string. The nomenclature for such functions is to return a negative number for lexically smaller, a positive number for lexically greater and zero means equality.)
You don't use the auxiliary string X excapt to find the length. You can easily find the length of a string with strlen, which, like strcmp, is declared in <string.h>
The calculation of your index for the suffix is off. Your length len is one less than the actual length and W[len] is the last character. Don't subtract one from your length.
Here's your code, refactored into a function, so that input and program logic are separated as they ought to be:
int is_nice(const char *W)
{
char A[20], B[20];
int len = strlen(W);
int j, k, n = 1;
while (n < len / 2) {
for (k = 0; k < n; k++) A[k] = W[k];
A[k] = '\0';
for (k = 0, j = len - n; W[j] != '\0'; j++, k++) B[k] = W[j];
B[k] = '\0';
if (strcmp(A, B) == 0) return 1;
n++;
}
return 0;
}
Above, I've said that you could use strncmp to compare ony a certain number of characters in the string. If you think about it, you can omit the auxiliary strings A and B and compare just slices of your original string:
int is_nice(const char *W)
{
int len = strlen(W);
int n = 1;
while (n < len / 2) {
if (strncmp(W, W + len - n, n) == 0) return 1;
n++;
}
return 0;
}
This saves a lot of copying, some temporary variables and has one other significant benefit: Because the code doesn't have to guess a maximum size for the auxiliary buffers, it now works for strings of any size.
You have three errors in your code.
The first is when you compute the length of the input string. Subtracting 1 from len after the loop is not necessary (simulate this loop for a small n to see why).
In this line:
if (!strcmp(A, B))
you are comparing non null-terminated strings which is undefined behavior. You should either terminate strings A and B or use strncmp(A, B, n) to compare at most n characters.
The third error is a logical error. If a string is "nice", your program will output both YES and NO. But this one should be easy to fix.

Resources