String Sort and remove Duplicates - c

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

Related

Letter guessing game in C using if else statements

I'm new to programming and am trying to do this guessing game by a simple C program below. When I input letters from the word "apple", every letter (p,l,e) executes the wrong guess try again statement except for the letter 'a'. I can't seem to understand what I'm doing wrong here. Any insights is highly appreciated.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define size 10
int main() {
// initialize variables
char word[size] = "apple";
char guess;
char arrayofdashes[size] = "_____";
printf("guess a letter \n");
// input loop
for (int i = 0; i < strlen(word); i++)
{
scanf(" %c", &guess);
for (int j = 0; j< strlen(word); j++ )
{
if (guess == word[j])
{
arrayofdashes[j] = guess;
printf("%s \n", arrayofdashes);
}
else
{
printf("wrong guess. Try again \n");
break;
}
}
}
}
Remove the break and add a flag variable to check the correctness of the input letter. And you need a better way to check if the word spelling is complete.
char flag;
int count = 0;
// input loop
while (count < strlen(word))
{
scanf(" %c", &guess);
flag = 0;
for (int j = 0; j< strlen(word); j++ )
{
if (guess == word[j] && guess != arrayofdashes[j])
{
arrayofdashes[j] = guess;
count++;
flag = 1;
}
}
if (flag)
printf("%s \n", arrayofdashes);
else
printf("wrong guess. Try again \n");
}
the problem is that you're using break - this drops out of your inner for-loop after comparing your input against the first character, and prevents it from being compared with subsequent characters.
What strategies have you tried for debugging this yourself? You'll have a few more changes to make aside from removing break, but figuring them out is part of the fun
for (int j = 0; j < strlen(word); j++)//no two loop
{
scanf(" %c", &guess);
if (guess == word[j])
{
arrayofdashes[j] = guess;
printf("%s \n", arrayofdashes);
}
else
{
printf("wrong guess. Try again \n");
j--;
}
}
You don't need the input loop. And if the answer is not correct you should subtract one from j.

Trying to remove substring from string in C, keep failing

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.

Integer array with whitespace characters output

I am trying to write a c program. It have to enter two arrays and input should be space seperated. I tried somehow to eliminate the '\n'.
#include <stdio.h>
int main()
{
char temp;
int alc[3]={0}, bob[3]={0}, i=0;
//enter alice
do
{
scanf("%d%c", &alc[i], &temp);
i++;
} while(temp != '\n');
i=0;
//enter bob
do
{
scanf("%d%c", &bob[i], &temp);
i++;
} while(temp != '\n');
//print alice
for(i = 0; i < 3 ; i++)
{
printf("%d ", alc[i]);
}
//print bob
for(i = 0; i < 3 ; i++)
{
printf("%d ", bob[i]);
}
return 0;
}
output ./a.out
5 6 7
3 6 10
5 6 7 3 6 10
Is there a better way to do same?
The idea is get the line as input and then parse it to get the integers using strtol etc. The line you will get using fgets. And then you will store it in array. There are two options now,
If you get more elements than you can hold in the array then you will show error when the array is full.
Or use dynamically allocated memory which will grow as the number you enter increase.
I am afraid, using scanf until you get integers is an option - but that is not the good idea and scanf is not the easy way to go about this.
the following proposed code:
cleanly compiles
follows the axiom: only one statement per line and (at most) one variable declaration per statement.
is consistently indented
eliminates unneeded variables
limits the scope of variables
performs the desired functionality
properly checks for error indications from system functions
documents why each header file was included
all 'magic' numbers given meaningful names (via #define statement)
and now the proposed code:
#include <stdio.h> // scanf(), fprintf(), stderr, printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
#define MAX_NUMS_PER_PERSON 3
int main( void )
{
int alice[ MAX_NUMS_PER_PERSON ]={0};
int bob[ MAX_NUMS_PER_PERSON ]={0};
//enter alice
for( int i=0; i< MAX_NUMS_PER_PERSON; i++ )
{
if( 1 != scanf("%d", &alice[i]) )
{
fprintf( stderr, "failed to input nums for Alice\n" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
}
//enter bob
for( int i=0; i< MAX_NUMS_PER_PERSON; i++ )
{
if( 1 != scanf("%d", &bob[i]) )
{
fprintf( stderr, "failed to input nums for Bob\n" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
}
//print alice
for( int i = 0; i < MAX_NUMS_PER_PERSON; i++)
{
printf("%d ", alice[i]);
}
//print bob
for( int i = 0; i < MAX_NUMS_PER_PERSON; i++)
{
printf("%d ", bob[i]);
}
return 0;
}
Changed my C program according to this answer
Putting numbers separated by a space into an array
#include <stdio.h>
#include <ctype.h>
#define ARRAY_SIZE 3
#define BOB_SIZE 5
#define ALICE_SIZE 4
int main()
{
int tmp, i=0;
char follow;
int count;
int a[ALICE_SIZE]={0}, b[BOB_SIZE]={0};
if((ALICE_SIZE < ARRAY_SIZE) || (BOB_SIZE < ARRAY_SIZE))
{
printf("Not sufficient space in array, check the sizes.\n");
return -1;
}
while ((i < ARRAY_SIZE) && (count = scanf("%d%c", &tmp, &follow)) > 0)
{
if ((count == 2 && isspace(follow)) || (count == 1))
{
a[i++] = tmp;
}
else
{
printf ("Bad character detected: %c\n", follow);
break;
}
}
i=0;
while ((i < ARRAY_SIZE) && (count = scanf("%d%c", &tmp, &follow)) > 0)
{
if ((count == 2 && isspace(follow)) || (count == 1))
{
b[i++] = tmp;
}
else
{
printf ("Bad character detected: %c\n", follow);
break;
}
}
for(i = 0; i < ARRAY_SIZE ; i++)
printf("%d ", a[i]);
printf("\n");
for(i = 0; i < ARRAY_SIZE ; i++)
printf("%d ", b[i]);
return 0;
}
Tried to make input as general as possible while using scanf
looks like too much effort but its required to make it robust,and put corner cases and errors.
More problems with scanf comes with strings or %s specifier. So better get used to fgets, strtol and dynamic arrays in parsing while giving inputs.

While loop runs once

I am trying to run a program that will repeatedly read a letter from the user, with the most being entered as 12. If the user enters a sentinel value that they input, the loop should terminate. However, as soon as the first character is read in the loop, it terminates.
Also, the program will place the same word in the reverse order in another array, then check them to see if the first array (read forward), is the same as the other array (read backward). If it is, it displays that the word is a palindrome.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main()
{
int charCount, counter, i, temp, check,check2;
char letter[12], letter2[12];
charCount = 0;
counter = 10;
check = 0;
i = 1;
check2 = 0;
printf("Enter your sentinel value.:");
scanf_s(" %c", &letter[check2]);
while ((i<13) && (letter[i] != letter[check2]))
{
printf("Enter individual letters in word (in order).:");
scanf_s(" %c", &letter[i]);
charCount++;
if (letter[i] == letter[check2])
{
break;
}
i++;
}
printf("Letters entered:%i\n", charCount);
for (i = 0; i < charCount; i++)
{
letter2[i] = letter[i];
}
for (i = 0; i <= (charCount / 2); i++)
{
temp = letter2[counter];
letter2[counter] = letter2[i];
letter2[i] = temp;
counter--;
}
for (i = 0; i <= charCount; i++)
{
if (letter[i] = letter2[i])
{
check++;
}
}
if (check = charCount)
{
printf("Word is a palindrome.\n");
}
system("PAUSE");
return 0;
}
the letter[1] value will be unassigned when the while loop enters for the first time right ? I think you can take that condition out of the while loop since you are considering it in the if statement inside the while loop

Get a little help to my program: infinite loop in the scanf

my programe gets 5 grades and calculates average and max values.but when i enter a letter first instead of a grade, it continuously prints "invalid". when i enter a letter after entering a int value it stops further getting remaining values.can someone explain where i am wrong? thank you
#include <stdio.h>
#include <stdlib.h>
int main()
{
int grade[5];
int temp;
int temp2 = 0;
for(int i = 0; i <= 4; i++) //getting inputs
{
printf("enter grade= ");
scanf("%i", &temp);
if(temp <= 100 && temp >= 0)
grade[i] = temp;
else
{
printf("invalid\n");
i--;
}
}
//print array
for(int i = 0; i <= 4; i++)
printf("%i\n", grade[i]);
//Average
for(int i = 0; i <= 4; i++)
{
temp2 = temp2 + grade[i];
}
printf("avg is= %i\n", temp2 / 5);
//Max
int mx = grade[0];
for(int i = 1; i <= 4; i++)
if(mx < grade[i])
{
mx = grade[i];
}
printf("max is= %i", mx);
return 0;
}
From the scanf man page:
These functions return the number of input items successfully
matched and assigned, which can be fewer than provided for, or
even zero in the event of an early matching failure.
So when the scan fails, you have to read and throw the offending characters, or it will still be in the buffer.
you can use the following macro instead of using scanf() directelly
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
and in your code you call the macro in this way
for(int i = 0; i <= 4; i++) //getting inputs
{
printf("enter grade= ");
SCAN_ONEENTRY_WITHCHECK("%i",&tmp,(temp <= 100 && temp >= 0));
grade[i] = temp;
}
for more details concerning the macro and concerning the reason of getting infinite loop in your code, please refer to Common macro to read input data and check its validity

Resources