Trying to remove substring from string in C, keep failing - c

I know this question has been asked many times before but I simply cannot get my head around what I am doing wrong. Everytime I make some progress I get a new error. The code I am using is really basic because I am a newbie and our professor requires the usage of scanf and gets. This is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
int identify(char[], char[]);
int remove(char[], char[], int);
int scan(choice)
{
while(choice < 0 || choice > 7)
{
printf("Invalid input, choose again\n");
scanf("%d", &choice);
}
return choice;
}
int main()
{
char sentence[MAX_SIZE], word[MAX_SIZE];
int choice, i, j, k, deikths;
printf("Choose one of the following:\n");
printf("1. Give sentence\n");
printf("2. Subtract a word\n");
printf("3. Add a word\n");
printf("4. Count the words\n");
printf("5. Count the sentences\n");
printf("6. Count the characters\n");
printf("7. Is the phrase a palindrome?\n");
printf("0. Exit\n");
scanf("%d", &choice);
if(scan(choice) == 1)
{
printf("Give sentence:\n");
gets(sentence);
gets(sentence);
printf("%s\n", sentence);
}
else(scan(choice) == 2);
{
printf("Give word you want to subtract\n");
gets(word);
printf("%s", word);
deikths = identify(sentence, word);
if(deikths != -1)
{
remove(sentence, word, deikths);
printf("Sentence without word: %s\n", sentence);
}
else
{
printf("Word not found in sentence.\n");
}
}
}
int identify(char sentence[], char word[])
{
int i, j, k;
for(k = 0; word[k] != '\0'; k++);
{
for(i = 0, j = 0; sentence[i] != '\0'; i++)
{
if(sentence[i] == word[j])
{
j++;
}
else
{
j = 0;
}
}
}
if(j == 1)
{
return(i - j);
}
else
{
return -1;
}
}
int remove(char sentence[], char word[], int deikths)
{
int i, k;
for(k = 0; word[k] != '\0'; k++)
{
for(i = deikths; sentence[i] != '\0'; i++)
{
sentence[i] = sentence[i + k + 1];
}
}
}
The error I am getting, is that the remove function has conflicting types. Any help with fixing my code will be greatly appreciated, or even an alternative solution to my problem would bre great.

As established in the comments, the compiler error is generated because remove is already defined in the stdio.h. After changing, the name the code compiles successfully, but still doesn't work as expected.
identify is the function which is meant to find whether a substring exists in a string and return its position. This is very similar to how strstr from the standard library works - I'd suggest having a look at an implementation of that function, to better understand how this is done.
The function you implemented only correctly finds substrings of length 1, at the end of the string. I have highlighted errors in the code below which cause this.
int identify(char sentence[], char word[])
{
int i, j, k;
for(k = 0; word[k] != '\0'; k++); // <- this loops is never actually ran because of the trailing semicolon - this is however a good thing as it is redundant
{
for(i = 0, j = 0; sentence[i] != '\0'; i++)
{
if(sentence[i] == word[j])
{
j++;
}
else
{
j = 0; // <- this makes it so only matches at the end can be found - otherwise, j is just reset back to 0
}
}
}
if(j == 1) // <- this makes it so only matches of length 1 can be found
{
return(i - j); // <- this is only correct if the match is at the end of the sentence
}
else
{
return -1;
}
}
strremove is inefficient due to the nested loops and the range of characters copied needs to be shortened - right now data is access beyond the end of the array.
int strremove(char sentence[], char word[], int deikths)
{
int i, k;
for(k = 0; word[k] != '\0'; k++) // <- this loop is redundant
{
for(i = deikths; sentence[i] != '\0'; i++) // <- you need to add range checking to make sure sentence[i+k+1] doesn't go beyond the end of the string
{
sentence[i] = sentence[i + k + 1];
}
}
}
I will leave the problems in main as an exercise to you - this is an assignment after all.

Related

gets before printf is not taking input correctly and printf is not showing output as expected

I am trying to check if a string is a sub-string of another string. I have wrote my code so that the big string is compared with the smaller strings, so that i can find out if the smaller strings are sub-strings of the big string. But when i try to run my code, its acting wrong and not taking input as it's supposed to.i think it might be printf problem. But Don't know what the actual problem is. Any help is highly appreciated.
Here's a link to the problem i am trying to solve:
https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=18&page=show_problem&problem=1620
#include<stdio.h>
#include<string.h>
int main()
{
int k,i,j,l,m;
scanf("%d ",&k);
for(i = 1; i <= k; i++)
{
char S[100001];
int q;
fgets(S,100000,stdin);
scanf("%d",&q);
char T[q][1000];
for(j = 0; j < q; j++)
{
fgets(T[j],999,stdin);
for(m = 0,l = 0; m < strlen(T[j]);)
{
if(l >= strlen(S))
{
printf("n\n");
fflush(stdout);
break;
}
if(S[l] == T[j][m])
{
if(m == (strlen(T[j]) - 1))
{
printf("y\n");
fflush(stdout);
break;
}
m++;
l++;
}
else
{
l++;
m = 0;
}
}
}
}
return 0;
}

String Sort and remove Duplicates

First I apologize for any mistype, for I am Brazilian and English is not my native language.
I am a freshman at my college and I got this algorithm to solve, from my teacher:
Make a program that creates a vector of n words, n being a size entered by the user (maximum 100). Your program should remove all duplicate words from the input vector and sort the words. Print the final vector without repeated and ordered words.
E.g. with 7 words to sort:
Input: 7 [enter]
hand ear leg hand hand leg foot
Output: ear foot hand leg
Note: Comment the program prints so that the output of the program is as shown in the example above (the numbers are separated by a spacebar, without space after last digit).
Note2: In case of invalid entry the program should print: "invalid entry" (all lower case).
Ok, I got it working but the I got confused with the notes and I can't find a way to fix the possible bugs, here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char word[100][100], aux[100];
int i, j, num;
printf("Type how many words you want to order: ");
do
{
scanf("%d", &num);
}while (num>100 || num<=0);
for(i=0; i<num; i++)
scanf("%s",&word[i]);
for (i = 0; i < num; i++) //loop to sort alphabetically
{
for (j = i+1; j < num; j++)
{
if ((strcasecmp(word[i], word[j]) > 0)) //swapping words
{
strcpy(aux, word[j]);
strcpy(word[j], word[i]);
strcpy(word[i], aux);
}
}
}
for (i = 0; i < num; i++) //loop to remove duplicates
{
if ((strcasecmp(word[i], word[i+1]) == 0)) //finding the duplicates
{
for (j = i+1; j < num; j++) //loop to delete it
strcpy(word[j], word[j+1]);
num--;
i--;
}
}
printf("\nWords sorted and without duplicates:\n");
for(i=0; i<num-1; i++)
printf("%s ", word[i]); //output with spacebar
printf("%s", word[num-1]); //last output without spacebar
return 0;
}
When I type a word with more than 100 characters, the Code::Blocks closes with an error, else it works fine. What do you think I should change?
The teacher uses a Online Judge (Sharif Judge) to evaluate if the code is right, and I got error in 3 of the tests (that are not specified), all of them were "Time Limit Exceeded". Maybe it has do to with the size of the matrix, or the problem with words >100.
Thanks in advance, Vinicius.
I guess you input sanity check is causing the issue.
As mentioned in the comment section.
If n is always < 100. Definitely your sorting is not causing any time limit exceeded.
Looks like the n is given something greater than 100 and your scanf is waiting and causing the issue. Also, make sure your input numbers are taken properly. If the input is > 100 print 'invalid entry'.
Something like below should work.
scanf("%d", &num);
if (num > 100)
printf("invalid entry");
for (i = 0; i < num; i++) {
scanf("%s", word[i]);
if (strlen(word[i])>100)
printf("invalid entry");
}
Hope it helps!
of course you will get an error if you use woerds more than 100 length casue you
have this line: char word[100][50], aux[100];
that means that you word length limit is set to 50. use word[100][100];
also you may not delete duplicates, just skip them in output
lol of course if youre using judge , you should not output any symbols except the answer, this means you should delete all lines, like :
printf("Type how many words you want to order: ");
and check the input format, and check limitations, i mean max word length , max amounts of words
try smth like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max_word_length = 101;
#define max_amount_of_words = 101;
int main() {
char word[max_amount_of_words][max_word_length] = {};
char aux[max_word_length];
int i, j, num;
scanf("%d", &num);
if (num < 0 || num > 100) {
printf("invalid entry");
return 0;
}
for (i = 0; i < num; i++) {
scanf("%s", word[i]);
}
for (i = 0; i < num; i++) {//loop to sort alphabetically
for (j = i + 1; j < num; j++) {
if ((strcasecmp(word[i], word[j]) > 0)) { //swapping words
strcpy(aux, word[j]);
strcpy(word[j], word[i]);
strcpy(word[i], aux);
}
}
}
bool is_joint = false;
for (i = 0; i < num; i++) { //loop to skip duplicates
if ((strcasecmp(word[i], word[i + 1]) != 0)) { //if there is a duplicate , we willnot output it
if(is_joint) printf(" ");
printf("%s ", word[i]);
is_joint = true;
}
}
return 0;
}
I got 100% on Judge, I fixed the code and looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char word[101][101],aux[101]; //a number higher than the limit to comparisons
int i,j,num;
scanf("%d",&num);
if(num<=0||num>100){ // if words < 0 or >100
printf("invalid input");
return 0;
}
for(i=0;i<num;i++){
scanf("%s",&word[i]); //read n words
if(strlen(word[i])>100){ //if word >100 caracters
printf("invalid input");
return 0;
}
for(j=0;j<strlen(word[i]);j++){
if (word[i][j]>=65&&word[i][j]<=90){
word[i][j]= word[i][j]+32; // if word is uppercase, make them lowcase
}
else if (word[i][j]>122||word[i][j]<97){// if word is different from alphabet lowercase
printf("invalid input");
return 0;
}
}
}
for(i=0;i<num;i++){
for(j=i+1;j<num;j++){
if((strcmp(word[i],word[j])>0)){ //loop to sort words
strcpy(aux,word[j]);
strcpy(word[j],word[i]);
strcpy(word[i],aux);
}
}
}
for(i=0;i<num-1;i++){
if((strcmp(word[i],word[i+1])!=0)){ // output words with spacebar, without the last one
printf("%s ",word[i]);
}
}
printf("%s",word[num-1]); // last word without spacebar
return 0;
}
Thank you everyone who tried to help, I've learned a lot with your suggestions!
This project is actually pretty tough assignment for a programmer who just
started in C.
Run this program in your computer.
Before running against the Judge, make sure you run many times with your manual inputs. Once you are happy with the tests, try against the Judge.
Like I said, the hardest part is storing the user's inputs according to spec (accepting space or newline characters in multiple lines).
#include <stdio.h>
#include <string.h>
int
main(void)
{
int iNumW, iIndex;
int iWCnt = 0;
int iC;
char caTemp[100];
char caWords[100][100];
char *cpDelimeter = " \n";
char *cpToken;
char *cp;
short sIsWord = 1;
char caGarbage[100];
scanf("%d", &iNumW );
fgets(caGarbage, sizeof caGarbage, stdin); //Remove newline char
//Get word inputs
while( iWCnt < iNumW )
{
fgets(caTemp, sizeof caTemp, stdin );
for( cpToken = strtok( caTemp, cpDelimeter ); cpToken != NULL; cpToken = strtok( NULL, cpDelimeter)){
cp = cpToken;
while( *cp ){
sIsWord = 1;
//Check if alphabet
if( !isalpha(*cp) ){
sIsWord = 0;
break;
}
cp++;
}
if( sIsWord ){
strcpy( caWords[iWCnt], cpToken );
//printf( "%s\n", caWords[iWCnt]);
iWCnt++;
if( iWCnt >= iNumW ) break;
} else {
printf("invalid entry.\n");
}
//printf("%d\n", iWCnt);
}
}
int i,j ;
for (i = 0; i < iWCnt; i++) {//loop to sort alphabetically
for (j = i + 1; j < iWCnt; j++) {
if ((strcasecmp(caWords[i], caWords[j]) > 0)) { //swapping words
strcpy(caTemp, caWords[j]);
strcpy(caWords[j], caWords[i]);
strcpy(caWords[i], caTemp);
}
}
}
for (i = 0; i < iWCnt; i++) { //loop to skip duplicates
if ((strcasecmp(caWords[i], caWords[i + 1]) != 0)) { //if there is a duplicate , we willnot output it
printf("%s ", caWords[i]);
}
}
return 0;
}

Checking if all elements in array are zero

I'm having trouble determining if two words entered are anagrams.
#include <stdio.h>
#include <string.h>
int main() {
char ch;
int letter_count[26] = {0};
int i;
int sum = 0;
printf("Enter first word: ");
do
{
scanf("%c", &ch);
letter_count[ch - 'a']++;
} while (ch != '\n');
for(i = 0; i < 26; i++)
printf("%d ", letter_count[i]);
printf("\n");
printf("Enter second word: ");
do
{
scanf("%c", &ch);
letter_count[ch - 'a']--;
} while (ch != '\n');
for(i = 0; i < 26; i++)
printf("%d ", letter_count[i]);
for(i = 0; i < 26; i++)
if(letter_count[ch] != 0)
sum++;
if (sum == 0)
printf("anagrams");
else
printf("not anagrams");
}
I have to use the do while part of the code. I can enter the two words, and it prints out the elements in the array, so that "Mattress" and "Smartest" together would have all the elements be zero. However, I'm having trouble with the last part, which is to use a third loop to check whether all the elements are zero.
I figured I could declare an int before hand and have it increment whenever an element wasn't zero, and I could just have any sum greater than zero not be an anagram. However, it always prints out anagram for me.
In your third loop, using letter_count[ch] will not check the entire array. You should iterate through the array using the loop variable i. That part of the code should be:
for (i=0; i<26; i++)
if (letter_count[i] != 0)
sum++;
To handle both upper case and lower case letters, use topper() or to lower() in <ctype.h> to avoid out-of-bound access.
#include <stdio.h>
#include <string.h>
#include <ctype.h> // <---
int main() {
char ch;
int letter_count[26] = {0};
int i;
_Bool bad = 0;
printf("Enter first word: ");
do
{
scanf("%c", &ch);
if(!isalpha(ch)) // <---
{
puts("Not a letter");
continue;
}
letter_count[tolower(ch) - 'a']++; // <---
} while (ch != '\n');
for(i = 0; i < 26; i++)
printf("%d ", letter_count[i]);
printf("\n");
printf("Enter second word: ");
do
{
scanf("%c", &ch);
if(!isalpha(ch)) // <---
{
puts("Not a letter");
continue;
}
letter_count[tolower(ch) - 'a']--; // <---
} while (ch != '\n');
for(i = 0; i < 26; i++)
printf("%d ", letter_count[i]);
printf("\n"); // <---
for(i = 0; i < 26; i++)
if(letter_count[i] != 0)
{
bad = 1;
break; // <---
}
if (bad == 0)
printf("anagrams");
else
printf("not anagrams");
}
Take a look at all places marked // <---.

making a word search puzzle?

I've made a program that allows you to choose the size of the grid and it allows you to enter up to 20 words. Now I have to insert the entered words horizontally into the original array using a function. The function must return a value for success and a value for failure to enter the word into the puzzle board. I need help getting started with what the actual function should look like along with the function prototype. Pseudocode would be helpful. I'm a fairly new programmer so any help is great. Thank you
#include<stdio.h>
#include<string.h>
void printmatrix(char matrix[][20],int);
void inserthor(char matrix[][20],int);
int main(void)
{
//declare variables
char matrix[20][20];
char words[20][100];
int x;
int a,b;
int i=0;
int n=0;
for (a=0;a<20;a++)
{
for (b=0;b<20;b++)
{
matrix[a][b] = '+';
}
}
while (x<10 || x>20)
{
printf("How large would you like the puzzle to be (between 10 and 20):\n");
scanf("%d",&x);
}
printmatrix(matrix,x);
//part 3
printf("Enter up to 20 words to hide in the puzzle.\n");
printf("Enter the word 'done' after your last word if entering less than 20 words.\n");
for (i = 0; i < 20; i++)
{
printf("Enter word %2d:\n", i+1);
if (scanf("%99s", words[i]) != 1 || strcmp(words[i], "done") == 0)
break;
}
n = i;
printf("%d words entered\n", n);
for (i = 0; i < n; i++)
printf("Word %2d = [%s]\n", i+1, words[i]);
return 0;
}
void printmatrix(char matrix[][20],int x)
{
int i,j;
printf("Empty Puzzle:\n");
for (i=0;i<x;i++)
{
for (j=0;j<x;j++)
{
printf(" %c ", matrix[i][j]);
}
printf("\n");
}
}
Your function prototype
void inserthor(char matrix[][20],int);
lacks the parameter with the word to be entered and the value to be returned. You could use
char *inserthor(char matrix[][20], int order, char *word)
{
int i, j, l = strlen(word);
for (i = 0; i < order; ++i)
for (j = 0; j <= order-l; ++j)
if (matrix[i][j] == '+') return memcpy(&matrix[i][j], word, l);
return NULL;
}
which returns the address of the inserted word for success and NULL for failure.

Comparison of strings for Mastermind game

I am writing a program that simulates the game Mastermind, but I am struggling with how to compare guessed pattern to key pattern.
The game conditions are a little bit changed:
patterns consist of letters.
if an element of guessed pattern is equal to element of key pattern, and also index is equal, then print b.
if an element of guessed pattern is equal to element of key pattern, but index is not, then print w.
if an element of guessed pattern is not equal to element of key pattern, print dot.
in feedback about guessed pattern, 'b's come first, 'w's second, '.'s last.
Original key vs guess pattern match code
for (i=0; i<patternlength; i++)
{
for (x=0; x<patternlength; x++)
{
if (guess[i]==key[x] && i==x)
printf("b");
if (guess[i]==key[x] && i!=x)
printf("w");
if (guess[i]!=key[x])
printf(".");
}
}
Revised code
This is using some of the answer provided by Jonathan Leffler. Unfotunately, it isn't working correctly yet; can you help me?
The functions length() and guessnum() are defined already.
#include<stdio.h>
#include<string.h>
int length()
{
int length;
printf("Enter the pattern length: ");
scanf("%d", &length);
return length;
}
int guessnum()
{
int guessnum;
printf("Enter the number of guesses: ");
scanf("%d", &guessnum);
return guessnum;
}
int main(void)
{
int patternlength = length();
char key[patternlength+1];
char keyc[patternlength+1];
int numguess = guessnum();
char guess[patternlength+1];
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1];
guessc[0] = '\0';
int ind;
char output[patternlength];
for (ind=0; ind<(patternlength+1); ind++)
output[ind]='\0';
char outputc[patternlength+1];
char guessold[patternlength+1];
for (ind=0; ind<(patternlength+1); ind++)
guessold[ind]='\0';
while (strcmp(key, guess) !=0 && count<=numguess)
{
if(count>1)
strcpy(guessold, guess);
strcpy(keyc, key);
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
if (count>1)
printf("%d: %s %s\n", count-1, output, guessold);
strcpy(guessc, guess);
wcount = 0;
bcount = 0;
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
if (keyc[i] == guessc[i])
{
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
for (ind=0; ind<patternlength; ind++)
output[ind]='b';
}
}
if (bcount != patternlength)
{
for (i = 0; i < patternlength; i++)
{
if (guessc[i] != '.')
{
for (j = 0; j < patternlength; j++)
{
if (guessc[i] == keyc[j])
{
wcount++;
putchar('w');
for (ind=0; ind<patternlength; ind++)
if (output[ind]!='b')
output[ind]='w';
keyc[j] = guessc[i] = '.';
break;
}
}
}
}
for (i = bcount + wcount; i < patternlength; i++)
putchar('.');
for (ind=bcount+wcount; ind<patternlength; ind++)
output[ind]='.';
}
count++;
printf(" %s\n", guess);
strcpy(outputc, output);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
output of code above:
Enter the pattern length: 3
Enter the number of guesses: 3
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: acb
1: bww acb
Input a guess pattern with no spaces: abb
1: bbb acb
2: bb. abb
Input a guess pattern with no spaces: abc
2: bb. abb
3: bbb abc
You guessed the pattern!
required output:
Enter the pattern length: 3
Enter the number of guesses: 3
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: acb
1: bww acb
Input a guess pattern with no spaces: abb
1: bww acb
2: bb. abb
Input a guess pattern with no spaces: abc
1: bww acb
2: bb. abb
3: bbb abc
You guessed the pattern!
I tried to use one more string, which will store in it feedback of the guess, but when there are several guesses, i think i should use some kind of loop to print feedback of all previous guesses each time new guess is made. but it is difficult to me figure out how should i write this loop with the structure suggested by Jonathan Leffler.
I added my last correction to the code, so I almost reached the desired output. does anyone have an idea what is possible to do here?
I assume that there is a structure (for easy copying of the array contained within it), and that the input validation ensures that the key and the guess are the same length, and that the key and the guess only contain alphabetic characters.
typedef struct pattern
{
char pattern[8];
} pattern;
size_t print_scoring(pattern key, pattern guess)
{
size_t n = strlen(key.pattern);
assert(n == strlen(guess.pattern));
size_t bcount = 0;
for (size_t i = 0; i < n; i++)
{
if (key.pattern[i] == guess.pattern[i])
{
putchar('b');
key.pattern[i] = guess.pattern[i] = '.';
bcount++;
}
}
if (bcount != n)
{
size_t wcount = 0;
for (size_t i = 0; i < n; i++)
{
if (guess.pattern[i] != '.')
{
for (size_t j = 0; j < n; j++)
{
if (guess.pattern[i] == key.pattern[j])
{
wcount++;
putchar('w');
guess.pattern[i] = key.pattern[j] = '.';
break;
}
}
}
}
for (size_t i = bcount + wcount; i < n; i++)
putchar('.');
}
return bcount;
}
The function works on copies of the key and the pattern (the structures are passed by value, not by pointer). It returns the number of correct guesses in the correct position; it assumes the calling code knows how long the pattern is, so the calling code can tell when the pattern is correct. It marks guess and key characters as 'used' by replacing them with a '.'. This is important to prevent a key of "aba" and a guess of "aaa" being incorrectly marked as bbw rather than correctly as bb.. This would be more important in keys/guesses of length 4 or more.
Test Harness
#include <assert.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
enum { NUM_KEYS = 3, NUM_GUESSES = 5 };
pattern k[] = { { "abc" }, { "aba" }, { "aaa" } };
pattern g[] = { { "aaa" }, { "aab" }, { "abc" }, { "cba" }, { "bab" } };
for (int i = 0; i < NUM_KEYS; i++)
{
for (int j = 0; j < NUM_GUESSES; j++)
{
printf("Key: %s; Guess %s; Score: ", k[i].pattern, g[j].pattern);
size_t n = print_scoring(k[i], g[j]);
if (n == 3)
printf(" -- Correct!");
putchar('\n');
}
}
return(0);
}
Test Output
Key: abc; Guess aaa; Score: b..
Key: abc; Guess aab; Score: bw.
Key: abc; Guess abc; Score: bbb -- Correct!
Key: abc; Guess cba; Score: bww
Key: abc; Guess bab; Score: ww.
Key: aba; Guess aaa; Score: bb.
Key: aba; Guess aab; Score: bww
Key: aba; Guess abc; Score: bb.
Key: aba; Guess cba; Score: bb.
Key: aba; Guess bab; Score: ww.
Key: aaa; Guess aaa; Score: bbb -- Correct!
Key: aaa; Guess aab; Score: bb.
Key: aaa; Guess abc; Score: b..
Key: aaa; Guess cba; Score: b..
Key: aaa; Guess bab; Score: b..
From the comments
Why is my code not working? Can you have a look at it please?
The problem is that I cannot go the next step after entering a guess pattern. Maybe I don't see some mistakes in my code.
Instant response:
One of the key points in my answer is that the comparison code is working on copies of the data entered. It is a destructive comparison algorithm, writing dots over the data. Your attempt to merge my code into your program did not retain the separate function working on separate copies of the data which were a crucial part of this answer. The use of a structure was there to make it easy to pass copies of the data around (it's the one time C copies arrays for you automatically). The comparison code should be in a function of its own, not inline in main().
However, we can get the code given to work. There were some transcription errors (marked BUG below), and some other problems (also identified below).
Working version of revised code in question
This is a working version of your program annotated with the crucial changes. Non-crucial changes include spacing around operators and using an indent level of 4 spaces.
#include <string.h>
#include <stdio.h>
static int length(void) { return 3; } // Dummy function
static int guessnum(void) { return 5; } // Dummy function
int main(void)
{
int patternlength = length();
char key[patternlength+1]; // Buffer overflow
char keyc[patternlength+1]; // Copy of key
int numguess = guessnum();
char guess[patternlength+1]; // Buffer overflow
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1]; // Buffer overflow
guessc[0] = '\0'; // Initialize!
while (strcmp(key, guess) != 0 && count <= numguess)
{
strcpy(keyc, key); // Copy key too
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
strcpy(guessc, guess);
wcount = 0; // Reinitialize
bcount = 0; // Reinitialize
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
if (keyc[i] == guessc[i])
{
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
}
}
if (bcount != patternlength) // Extraneous semi-colon excised! ;
{
for (i = 0; i < patternlength; i++)
{
if (guessc[i] != '.')
{
//for (j = 0; i < patternlength; j++) BUG
for (j = 0; j < patternlength; j++)
{
//if (guessc[i] == keyc[i]) BUG
if (guessc[i] == keyc[j])
{
wcount++;
putchar('w');
//guessc[i] = keyc[i]; BUG
keyc[j] = guessc[i] = '.';
break;
}
}
}
}
for (i = bcount + wcount; i < patternlength; i++)
putchar('.');
}
count++;
printf(" %s\n", guess);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
The compiler told me about the stray semi-colon:
ss2.c: In function ‘main’:
ss2.c:36:37: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
If your compiler didn't tell you about that, you aren't using enough warnings (or you need a better compiler). I routinely use:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition ss2.c -o ss2
The working code passes that without a whimper.
Sample output
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: aaa
1: b.. aaa
Input a guess pattern with no spaces: bbb
2: b.. bbb
Input a guess pattern with no spaces: ccc
3: b.. ccc
Input a guess pattern with no spaces: cab
4: www cab
Input a guess pattern with no spaces: abc
5: bbb abc
You guessed the pattern!
Final debug-laden code
This is mainly to show the level of printing that I used to see what was going wrong. Using stderr for the diagnostic output meant the diagnostics did not interfere with the buffering of stdout as the output line was built up. That and the use of no indentation on the debug code also meant it was easy to strip the debug code out.
#include <string.h>
#include <stdio.h>
static int length(void) { return 3; }
static int guessnum(void) { return 5; }
int main(void)
{
int patternlength = length();
char key[patternlength+1]; // Buffer overflow
char keyc[patternlength+1]; // Copy of key
int numguess = guessnum();
char guess[patternlength+1]; // Buffer overflow
printf("Input the key pattern with no spaces: ");
scanf("%s", key);
int i,j,count = 1;
int bcount = 0, wcount = 0;
char guessc[patternlength+1]; // Buffer overflow
guessc[0] = '\0'; // Initialize!
while (strcmp(key, guess) != 0 && count <= numguess)
{
strcpy(keyc, key); // Copy key too
printf("Input a guess pattern with no spaces: ");
scanf("%s", guess);
strcpy(guessc, guess);
fprintf(stderr, "B1: (%s) vs (%s)\n", key, guess);
fprintf(stderr, "B2: (%s) vs (%s)\n", keyc, guessc);
wcount = 0; // Reinitialize
bcount = 0; // Reinitialize
printf("%d: ", count);
for (i = 0; i < patternlength; i++)
{
fprintf(stderr, "L1a: %d\n", i);
if (keyc[i] == guessc[i])
{
fprintf(stderr, "L1b: B (%c = %c)\n", keyc[i], guessc[i]);
putchar('b');
keyc[i] = guessc[i] = '.';
bcount++;
}
}
fprintf(stderr, "M1: (%s) vs (%s)\n", keyc, guessc);
if (bcount != patternlength) // Extraneous semi-colon excised! ;
{
fprintf(stderr, "L2a: b = %d (%s) vs (%s)\n", bcount, keyc, guessc);
for (i = 0; i < patternlength; i++)
{
fprintf(stderr, "L2b: %d (%c)\n", i, guessc[i]);
if (guessc[i] != '.')
{
fprintf(stderr, "L2c: %d (%c)\n", i, guessc[i]);
//for (j = 0; i < patternlength; j++) BUG
for (j = 0; j < patternlength; j++)
{
fprintf(stderr, "L2d: %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
//if (guessc[i] == keyc[i]) BUG
if (guessc[i] == keyc[j])
{
fprintf(stderr, "L2e: W %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
wcount++;
putchar('w');
keyc[j] = guessc[i] = '.';
//guessc[i] = keyc[i]; BUG
break;
}
}
}
}
fprintf(stderr, "L3a: %d + %d vs %d\n", bcount, wcount, patternlength);
for (i = bcount + wcount; i < patternlength; i++)
fprintf(stderr, "L3b: D %d\n", i),
putchar('.');
}
count++;
printf(" %s\n", guess);
}
if (strcmp(key, guess) != 0)
{
printf("You did not guess the pattern!\n");
}
else
{
printf("You guessed the pattern!\n");
}
return 0;
}
Note the trick with the comma operator after the last fprintf() function call.
Keeping a record of previous guesses and marks
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void err_exit(const char *msg, ...);
static void prompt_str(const char *prompt, int bufsiz, char *buffer);
static int prompt_int(const char *prompt);
int main(void)
{
int patternlength = prompt_int("Length of key");
int numguess = prompt_int("Number of guesses");
char key[patternlength+1];
char guesses[numguess][patternlength+1];
char marks[numguess][patternlength+1];
int count = 0;
prompt_str("Input the key pattern with no spaces", patternlength, key);
while (count < numguess)
{
char guess[patternlength+1];
char keyc[patternlength+1];
char mark[patternlength+1];
char *marker = mark;
int wcount = 0;
int bcount = 0;
strcpy(keyc, key);
prompt_str("Input a guess pattern with no spaces", patternlength, guess);
strcpy(guesses[count], guess);
for (int i = 0; i < patternlength; i++)
{
if (keyc[i] == guess[i])
{
*marker++ = 'b';
keyc[i] = guess[i] = '.';
bcount++;
}
}
if (bcount == patternlength)
break;
for (int i = 0; i < patternlength; i++)
{
if (guess[i] == '.')
continue;
for (int j = 0; j < patternlength; j++)
{
if (guess[i] == keyc[j])
{
wcount++;
*marker++ = 'w';
keyc[j] = guess[i] = '.';
break;
}
}
}
for (int i = bcount + wcount; i < patternlength; i++)
*marker++ = '.';
*marker = '\0';
strcpy(marks[count], mark);
count++;
for (int i = 0; i < count; i++)
printf("Guess: %d [%s] marks [%s]\n", i, guesses[i], marks[i]);
}
if (count >= numguess)
printf("You did not guess the pattern (which was [%s])!\n", key);
else
printf("You guessed the pattern!\n");
return 0;
}
static void prompt_str(const char *prompt, int bufsiz, char *buffer)
{
char fmt[8];
int c;
sprintf(fmt, "%%%ds", bufsiz);
printf("%s: ", prompt);
if (scanf(fmt, buffer) != 1)
err_exit("Unexpected input failure\n");
while ((c = getchar()) != EOF && c != '\n')
;
}
static int prompt_int(const char *prompt)
{
int number;
printf("%s: ", prompt);
if (scanf("%d", &number) != 1)
err_exit("Unexpected input failure\n");
if (number <= 0 || number > 9)
err_exit("Number should be in the range 1..9 (not %d)\n", number);
return(number);
}
static void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
Introduced functions prompt_int() and prompt_str() to get data. The prompt_str() function is reasonably resilient against overflows. There's an error reporting function. The dummy functions are replaced. Here is some sample output. From here on, you're on your own!
Length of key: 4
Number of guesses: 8
Input the key pattern with no spaces: abcd
Input a guess pattern with no spaces: aaaa
Guess: 0 [aaaa] marks [b...]
Input a guess pattern with no spaces: dcba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Input a guess pattern with no spaces: cdba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Guess: 2 [cdba] marks [wwww]
Input a guess pattern with no spaces: abcd
You guessed the pattern!
You are basically matching all the elements of key with all elements of guess, which is not what you want.
You need to iterate on guess and differentiate the three cases
Element guessed correctly
Element not guessed correctly but present in the key
Element not guessed correctly and not present in the key
int i,k;
bool found;
for (i=0; i<patternlength; i++)
{
if (key[i] == guess[i])
{
printf("b");
}
else
{
found = false;
for (k=0; k<patternlength && !found; k++)
{
if (key[k] == guess[i])
{
found = true;
printf("w");
}
}
if (!found)
{
printf(".");
}
}
}
Note that in the internal loop, I stop when I find an element with && !found. Otherwise, I'd fall into a problem similar to yours (It will print w for every element that matches my guess present in key)

Resources