Checking two character arrays for equality in C - c

I am trying to write a program that checks to see if a word inputed to a program matches one of the predefined keywords. Input is going to be coming from a text file and the text file will have a single word in it. So far the text file I have just has the word 'crackerjack' which means the program should clearly print 'Match Found' but it is not currently doing that. Here is my code, does anything stand out to you guys? Thanks
#define NUM 4
#define SIZE 11
int isAlpha(char);
//Returns 1 if it is an Alphabetical character, 0 if it is not
int isAlpha(char c) {
return (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z');
}
int main() {
char message[141];
int charCount = 0, c = 0, matchCheck = 0;
char keywords[NUM][SIZE] = {
"crackerjack",
"Hey",
"dog",
"fish"
};
//Removes non alphabetical characters
while((c = getchar()) != EOF && charCount <= 140) {
if(isAlpha(c)){
message[charCount] = c;
charCount++;
}
printf("%d", isAlpha(c));
}
//checks if message matches keyword
for (int i = 0; i < NUM; i++) {
for (int j = 0; j < SIZE; j++) {
//Check if current two characters match
if (message[j] == keywords[i][j]) {
//Check if the two matched characters are the null terminator character
if (message[j] == '\0' && keywords[i][j] == '\0')
matchCheck = 1;
break;
}
//if characters are not the same, break from loop
else {
break;
}
}
}
//prints "Match Found!" if there was a match
if (matchCheck == 1) {
printf("Match Found!\n");
}
}

There are 3 problems in your code. Two of them have already been addressed:
Ensure that SIZE is big enough to include a '\0' at the end of the longest keyword
Ensure that the text file includes a '\0' at the end of the word. If it is not the case or it is out of your control, you can always manually end the string with a '\0' after reading it.
You are missing brackets on your second if statement. This causes the break statement to be executed every time the first if statement is entered.

SIZE is too small. Make room for '\0'.
#define SIZE 12
char keywords[NUM][SIZE] = {
"crackerjack",
...
};
I see now this is effectively what #user3121023 said. Credit to #user3121023.

Related

Trying to break out of fgets while loop

#include <stdio.h>
#include <string.h>
int main(){
char c[20], result[50];
int bool = 0, count = 0, i;
while(fgets(c,20,stdin) != NULL){
int stringSize = strlen(c);
if(stringSize == 11){
int ascii = (int)(c[i]);
for(i = 0; i < stringSize; i++){
if(ascii >= 'A' && ascii <= 'Z'){
bool = 1;
}
}
}
}
if(bool == 1){
count++;
strcat(result,c);
}
printf("%d", count);
printf("%s",result);
}
Good morning, I am fairly new to programming, and I've spent quite a while Googling and searching around for this issue already, but I can't seem to wrap my head about it.
Basically I'm trying to filter an fgets so that it reads each string, and if they're capital letters, they're "valid". However, I can't even get the fgets to stop accepting more input.
Edit: The idea is to store in result every String that has 10 capital letters, and for the fgets while loop to break once the user gives no input ('\0')
If you are entering strings from the standard input stream then it is better to rewrite the condition of the while loop the following way
while( fgets(c,20,stdin) != NULL && c[0] != '\n' ){
In this case if the user just pressed the Enter key without entering a string then the loop stops its iterations.
Pay attention to that fgets can append the new line character '\n' to the entered string. You should remove it like
c[ strcspn( c, "\n" ) ] = '\0';
Then you could write
size_t n = strlen( c );
if ( n == 10 )
{
size_t i = 0;
while ( i != n && 'A' <= c[i] && c[i] <= 'Z' ) ++i;
bool = i == 10;
}
Pay attention to that it is a bad idea to use the name bool because such a name is introduced as a macro in the header <stdbool.h>.
Also it seems this if statement
if(bool == 1){
count++;
strcat(result,c);
}
must be within the while loop. And the array result must be initially initialized
char c[20], result[50] = { '\0' };

C program to capitalize a word inside quotation marks

I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}

How may I count the number of words in a paragraph? I keep miscounting

I am trying to code a program that count the number of letters, words, and sentences in a text. I may assume that a letter is any lowercase character from a to z or any uppercase character from A to Z, any sequence of characters separated by spaces should count as a word, and that any occurrence of a period, exclamation point, or question mark indicates the end of a sentence.
So far, I could count both the number of letters and sentences correctly, but I miss out on the number of words:
e.g.
yes!
The output should be:
3 letter(s)
1 word(s)
1 sentence(s)
What I get is:
3 letter(s)
0 word(s)
1 sentence(s)
UPDATE: It works fine now after typing out another (words++) in the end right before the printf function. Thanks for the help guys :).
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string text = get_string("Enter text: ");
printf("Output:\n");
int lettercount;
int words = 0;
int sentences = 0;
int letters = 0;
int length = strlen(text);
for(lettercount = 0; lettercount < length; lettercount++)
{
if(isalpha(text[lettercount]))
{
letters++;
}
else if(text[lettercount] == ' ' || text[lettercount] == '\t' || text[lettercount] == '\n' || text[lettercount] == '\0')
{
words++;
}
else if(text[lettercount] == '.' || text[lettercount] == '!' || text[lettercount] == '?')
{
sentences++;
}
}
words++;
printf("%i letter(s)\n", letters);
printf("%i word(s)\n", words);
printf("%i sentence(s)\n", sentences);
}
The main problem with your code is that it does not count any 'final' word in your input text if that does not have a space after it (the terminating '\0' character will not be part of the tested string, as the strlen function does not include that.
Further, you will have problems if you have words that are separated by more than one space; to address this, you could use an inWord flag to keep track of if the current character is already inside a word and, if not, set that flag whenever we find a letter.
Also, your sentence count will be problematical if you have things like "..." in your input; the commented-out line after your sentences++; line will fix that (if you want to).
And, finally, just to be precise, you should not assume that the letters "a" thru "z" and "A" thru "Z" will be in a continuous sequence. They probably will be (most systems these days use ASCII encoding) but you should use the isalpha function for more portability (and the isspace function, too).
int main(void)
{
string text = get_string("Enter text: ");
printf("Output:\n");
int lettercount;
int words = 0;
int sentences = 0;
int letters = 0;
int inWord = 0;// Set to 1 if we are inside a (new) word!
int length = (int)(strlen(text)); // Don't evaluate length on each loop!
for (lettercount = 0; lettercount < length; lettercount++) {
int testChar = text[lettercount]; // Get a local copy of the current character
if (isalpha(testChar)) { // Don't assume that 'a' ... 'z' and 'A' ... 'Z' are in contiguous sequences
letters++;
if (!inWord) words++; // Any letter means that we're in a (possibly new) word...
inWord = 1; // ... but now set this 'flag' so as not to count others!
}
else if (testChar == '.' || testChar == '!' || testChar == '?') {
sentences++;
// if (inWord) sentences++; // Check that we're in a word, or stuff like "..." will be wrong
inWord = 0; // Now we are no longer inside our current word
}
else if (isspace(testChar)) { // We could also just assume ANY other character is a non-word
inWord = 0; // Now we are no longer inside our current word
}
}
printf("%i letter(s)\n", letters);
printf("%i word(s)\n", words);
printf("%i sentence(s)\n", sentences);
return 0;
}
Feel free to ask for any further clarification and/or explanation.
You will always have words -1 because you only add new word to your counter after space or new line but what about the last word !? always the last word will not be counted so after counting any paragraph add 1 to your word counter ..
Ex : Yes! --> 3 letters 1 Sentence 0 word ! so you add one and solved
another Ex : Hello World! --> 10 letters 1 sentence 1 word ! adding one and it's solved

How do I count the number of sentences in C using ".", "?", "!"?

I'm fairly new to coding. I'm having trouble with my "CountSentences" function. I compare the string to "." , "?" , and ! to count a sentence. It only adds one to the sentence counter no matter how many of the punctuation marks I have in the string. Am I using strcmp wrong to get my desired result and is there another way I can approach this?
#include<cs50.h>
#include<ctype.h>
#include<string.h>
#include<math.h>
//function for letter count
int count_letters(string s)
{
int numberofLetters = 0; // counter
//loop as long as string length
for(int i = 0, n = strlen(s); i < n; i++)
{
//if character is alphanumeric
if(isalnum(s[i]) != 0)
{
numberofLetters++; //increase counter
};
};
return numberofLetters; //return new counter number
};
//function for word count
int count_Words(string w)
{
int numberofWords = 0;//counter for words declared
int i = 0; // counter for character in string
if(w == NULL) // if nothing
{
return numberofWords; // return Wordcount of 0
};
bool spaces = true; //truth value for space
//if character is not null terminating character
while(w[i] != '\0')
{
if(isblank(w[i]) != 0) //if character is blank
{
spaces = true; //its a space
}
else if(spaces) //if no more space and a letter is present add to words
{
numberofWords++; //add to number of words counter
spaces = false;
};
i++;// increase chracter count in string w
};
return numberofWords; //return total word counter
};
//function to count sentences
int count_Sentences(string l)
{
//variable counter for marks
int countMarks = 0;
//loop iteration using the number of characters in string
for(int i = 0, n = strlen(l); i < n; i++)
{
//check if character is ?, . , or !
if(strcmp(&l[i], "!") == 0 || strcmp(&l[i], ".") == 0 || strcmp(l, "?") == 0)
{
countMarks++;// sentence counted
};
};
// return the total number of marks
return countMarks;
};
int main (void)
{
string text = get_string ("Text: ");
//to check the functions bug checker
printf("Number of letters: %i\n", count_letters(text));
printf("Number of words: %i\n", count_Words(text));
printf("Number of sentences: %i\n", count_Sentences(text));
//Coleman Liau Index
int grade = round(0.0588 * (100 * (count_letters(text)) / (count_Words(text))) - 0.296 * (100 *(count_Sentences(text)) / (count_Words(text))) - 15.8 );
if(grade <= 1)
{
printf("Before Grade 1\n");
}
else if(grade < 16)
{
printf("Grade %i\n", grade);
}
else
{
printf("Grade 16+\n");
};
};
if(strcmp(&l[i], "!") == 0 || strcmp(&l[i], ".") == 0 || strcmp(l, "?") == 0)
strcmp compares two strings. In C, our "string" is essentially "the char-sized data starting at the place this pointer points to, and continuing until a null terminator". The cs50 library does not change this and does not give you a real string type; it only provides a typedef and some helper functions for reading input. (It also, sadly, does not and realistically cannot give you a real text character type, which char also is not; but that is beyond the scope of this answer.)
&l[i] is a pointer into the middle of the l string, starting at offset i. When that pointer is used by strcmp, it will treat the "string" as everything from that character to the end of the original string - because that's where the null terminator is. It will, in particular, not treat the single l[i] char as a separate string, in general, because the next char is in general not a null terminator. So,
It only adds one to the sentence counter no matter how many of the punctuation marks I have in the string.
In fact, it only even adds one because your string ends with one of those marks.
To compare individual chars, don't use strcmp. It is not intended nor fit for the purpose. A char is a single entity, so it can be compared just fine with ==. You just need to have something appropriate on both sides of the comparison.
Recall, in C single quotes are used for char literals, and indexing into the char array (equivalently, "indexing" into a char pointer, which performs the equivalent pointer arithmetic) gives you a char. Thus:
if (l[i] == '!' || l[i] == '.' || l[i] == '?')
You indeed need to see if the one character l[i] is any of ., ? or !. To do that, you can test if that is equal to any of these character constants, i.e. l[i] == '!' || l[i] == '.' || l[i] == '?'
Or you can use the function strchr that will look for a given character in a given string and return a pointer to that character, or a null pointer if the character is not found. A null pointer will be considered as falsy in if, and and a non-null pointer truthy. So we can look for l[i] in the string ".?!":
if (strchr(".?!", l[i])) {
...
}

No output given when executing a program on C

When I compile this program with gcc:
#include <stdio.h>
/* This program accepts some text as an input and gives the output
* of longest word and shortest word lengths*/
int main(){
int c, i, wordcount, symbolcount, longestword, shortestword;
wordcount = symbolcount = longestword = shortestword = 0;
int wlength[1];
while((c = getchar()) != EOF){
++symbolcount;
if(c == ' ' || c == '\n' || c == '\t'){
++wordcount;
wlength[wordcount];
wlength[wordcount - 1] = symbolcount;
symbolcount = 0;
}
}
for(i = 0;i <= wordcount;)
wlength[0] = longestword;
wlength[i] = shortestword;
while(shortestword < 1){
if(shortestword == longestword){
continue;
++i;
}else if(shortestword < longestword && shortestword > 0){
shortestword = wlength[i];
break;
}
}
for(i = 0; i <= wordcount - 1; ++i){
if(wlength[i] > longestword){
longestword = wlength[i];
}else if(wlength[i] < longestword && wlength[i] > shortestword){
continue;
}else{
wlength[i] = shortestword;
}
}
printf("%d\t%d", longestword, shortestword);
return 0;
}
There are no errors or warnings. But when I try to run it, it accepts the input, but there is no output at all. Even when I press Ctrl + D(I work on a debian based distro), current terminal session is not suspended and the program just keeps running. What can be the problem?
The problem is that
int wlength[1];
only declares an array with one element, but you access out of bounds with
shortestword = wlength[i];
This is undefined behavior in C parlance, anything can happen, including what you observe.
To fix this, declare the array with as many elements as you expect i to be.
Make sure your loops over i only take values that do not exceed the array element count.
You have declared an integer array wlength whose size is 2 i.e.,
int wlength[1];
and within the if condition you increment wordcount.
Now assume you have 4 words in a line and wordcount keep on increasing and will be assigned to wlength index but as you have defined the array size 2 , where it overflows. Thus when that is used further in
shortestword = wlength[i];
and
longestword = wlength[i];
it causes junk values to be assigned.
There are several things wrong with your program.
You don't allocate space for only one word.
You have an infinite loop over i. That's acutally why you don't see any output: The program is stuck in this loop.
The second while loop doesn't look as if you knew what you were doing there. I doubt that the condition shortestword < 1 will ever be true. A contunue before other statements makes those statements useless. And what exactly is i here. (Okay, perhaps the while is supposed to be inside the for loop? If so, you need curly braces on the loop body.)
Most of the errors stem from a misunderstanding of the problem. You do not need to store the lengths of all words in order to find the sortest and longest words. Just keeping track of the length of the current word is enough. The algorithm goes like this:
set longest to 0.
set shortest to a large number.
set length to 0.
for each character in the input:
if it is a white-space character:
update longest and shortest if necessary.
reset length to 0.
otherwise:
increase length
This lets you find the longest word in Moby-Dick without having to store more than the current word length. in C, it may look like this:
#include <stdio.h>
int main(void)
{
int longest = 0; // length of currently longest word
int shortest = 0; // length of currently shortest word
int length = 0; // length of current word
int c = getchar();
while (c != EOF) {
if (c == ' ' || c == '\n' || c == '\t') {
if (length) {
if (longest == 0 || length < shortest) shortest = length;
if (length > longest) longest = length;
length = 0;
}
} else {
length++;
}
c = getchar();
}
printf("max: %d\nmin: %d\n", longest, shortest);
return 0;
}

Resources