cs50 readability doesn't compile - c

Can someone explain me why it doesn't compile?
what did I forget?
Something went wrong when I wrote the condition statements.
most of time I had comparison pointer integer(char and char *) error or comparison a string literal is unspecified error()
compiler error
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
//Getting input from user
string s = get_string("Text: ");
printf("%s\n", s);
int letters = 0; // count letter
int words = 1; // count words, words +1 because 5 spaces = 6 words
int sentences = 0; // count sentences
for( int i = 0; i < strlen(s); i++)
{
if((s[i] >= "a" && s[i] <= "z") || (s[i] >= "A" && s[i] <= "Z"))
{
letters++;
}
if(s[i] == " ")
{
words++;
}
if(s[i] == "!" || s[i] == "?" || s[i] == ".")
{
sentences++;
}
}
printf("letters %i\n", letters);
printf("words %i\n", words);
printf("sentences %i\n", sentences);
}

When you use s[i] you are extracting the character (type char) which is an element of the string, so you have to compare it to characters.
In C you have to use single quotes for them:
s[i] == 'a'

Related

Program to count the total number of vowels, consonants and words and ask for a user again for check for a letter for a string

Program to count the total number of vowels, consonants, words and ask for a user again to check how many times a word has been used in that sentence checking in a string.
At this point my code does checks vowels and consonants and after this program has to ask for a word to the user to input a word and check how many times ıts been used in that sentence.
#include <stdio.h>
void main() {
char sentence[80];
int i, vowels = 0, consonants = 0, special = 0;
printf("Enter a sentence \n");
gets(sentence);
for (i = 0; sentence[i] != '\0'; i++) {
if ((sentence[i] == 'a' || sentence[i] == 'e' ||
sentence[i] == 'i' || sentence[i] == 'o' ||
sentence[i] == 'u') ||
(sentence[i] == 'A' || sentence[i] == 'E' ||
sentence[i] == 'I' || sentence[i] == 'O' ||
sentence[i] == 'U')) {
vowels = vowels + 1;
} else {
consonants = consonants + 1;
}
if (sentence[i] == '\t' ||sentence[i] == '\0' || sentence[i] == ' ') {
special = special + 1;
}
}
consonants = consonants - special;
printf("No. of vowels in %s = %d\n", sentence, vowels);
printf("No. of consonants in %s = %d\n", sentence, consonants);
}
Here are some problems in your code:
void main() is invalid: you should write int main()
gets(sentence); is risky as input longer than 79 bytes will cause a buffer overflow. This function is a security flaw and has been removed from current versions of the C Standard. You should use fgets() instead and check the return value.
you only test for TAB and SPACE as special characters, so any punctuation will be counted as consonant letters.
you do not count the number of words
you only implement the first part of the assignment.
Here is a modified version using ancillary functions:
#include <stdio.h>
#include <string.h>
int is_letter(char c) {
// Assuming ASCII
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
int is_vowel(char c) {
return c != '\0' && strchr("aeiouAEIOU", c) != NULL;
}
int main() {
char sentence[80];
printf("Enter a sentence \n");
if (fgets(sentence, sizeof sentence, stdin)) {
int i, vowels = 0, consonants = 0, words = 0;
char c, lastc = 0;
for (i = 0; sentence[i] != '\0'; i++) {
c = sentence[i];
if (is_letter(c)) {
if (is_vowel(c)) {
vowels = vowels + 1;
} else {
consonants = consonants + 1;
}
if (!is_letter(last)) {
words = words + 1;
}
}
last = c;
}
printf("No. of vowels = %d\n", vowels);
printf("No. of consonants = %d\n", consonants);
printf("No. of words = %d\n", words);
// implement the rest of the assignment...
}
return 0;
}

Make first letter of every word capital after removing vowels

My code works to delete any vowels and prints the first letter of the word as a capital letter.
How can I get my expected output to work?
If the value is " I am Iron Man" (with a leading space), it works and prints "M Rn Mn".
However, without the space at the beginning of the string, my output is "m Rn Mn" but
the expected output is "M Rn Mn".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char str[] = "I am Iron Man";
int i, j, len = 0;
len = strlen(str);
// Accepting input.
for (i = 0; i < len; i++) {
// Check vowels.
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' ||
str[i] == 'A' || str[i] == 'E' || str[i] == 'I' || str[i] == 'O' || str[i] == 'U') {
// delete vowel syntax
for (j = i; j < len; j++) {
// Store after removing vowels
str[j] = str[j + 1];
}
i--;
len--;
}
str[len + 1] = '\0';
}
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 space
{
//if space is found, check next character
++i;
//check letter if lowercase
if(str[i]>='a' && str[i]<='z')
{
str[i]=str[i]-32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
}
printf("%s", str);
return 0;
}
Your problem lies with excessive use of the continue statement in the second for loop. The second continue is just plain pointless, as control reaches the end of the loop, anyway, after the point where you have that.
But the first continue is actually causing the fault: after removal of the vowels, the first character in the modified string will be a space – so, the first if block inside the second loop will be entered, and that will skip the check for a lowercase letter following the space.
Removing those continue statement will fix your code.
Also, note that you can use the islower and toupper functiosn to check for lowercase letters and convert to uppercase:
#include <stdio.h>
#include <string.h>
#include <ctype.h> // For islower and toupper
int main()
{
char str[] = "I am Iron Man";
size_t i, j, len = 0;
len = strlen(str);
// Accepting input.
for (i = 0; i < len; i++)
{
// Check vowels.
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' ||
str[i] == 'A' || str[i] == 'E' || str[i] == 'I' || str[i] == 'O' || str[i] == 'U') {
// delete vowel syntax
for (j = i; j < len; j++)
{
// Store after removing vowels
str[j] = str[j + 1];
}
i--;
len--;
}
str[len + 1] = '\0';
}
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if (islower(str[i])) {
str[i] = toupper(str[i]);
}
// A "continue" here is wrong ... it will skip the following check for a lowercase letter
}
if (str[i] == ' ') //check space
{
//if space is found, check next character
++i;
//check letter if lowercase
if (islower(str[i]))
{
str[i] = toupper(str[i]);
// No need for a "continue" here ... we're already at the end of the loop
}
}
}
printf("%s\n", str);
return 0;
}
I have another solution for you, that may be a bit easier to comprehend:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char str[] = "I am Iron Man";
char *in;
char *out;
int up = 1; // very simple state, if "up" then next character should be made upper
for (in = str, out = str; *in; in++) {
if (strchr("aeiouAEIOU", *in) != NULL) {
// do nothing
} else if (*in == ' ') {
*out++ = *in;
up = 1; // we see a space, so next letter should be upper
} else if (up) {
*out++ = toupper(*in);
up = 0; // we see a letter (or other character), ignore case
} else {
*out++ = *in;
}
}
*out = '\0';
printf("%s\n", str);
}
Or, if you don't like/understand the pointer syntax:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char str[] = "I am Iron Man";
int i;
int o;
int up = 1; // very simple state, if "up" then next character should be made upper
for (i = 0, o = 0; str[i]; i++) {
if (strchr("aeiouAEIOU", str[i]) != NULL) {
// do nothing
} else if (str[i] == ' ') {
str[o++] = str[i];
up = 1; // we see a space, so next letter should be upper
} else if (up) {
str[o++] = toupper(str[i]);
up = 0; // we see a letter (or other character), ignore case
} else {
str[o++] = str[i];
}
}
str[o] = '\0';
printf("%s\n", str);
}
In both cases, a very simple state is used. For more complex conditions, you should learn about state machines. In this case, the up state indicates that the next letter should be capitalised.
Note that if you want to remove leading spaces, after "removing" the vowels, you need to modify the logic a bit:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char str[] = "I am Iron Man";
char *in = str; // we initialize in and out here already
char *out = str;
int up = 1; // very simple state, if "up" then next chacter should be made upper
// we skip leading vowels AND spaces, this is a special case
while (*in && (strchr("aeiouAEIOU ", *in) != NULL)) {
in++;
}
// now we are at the first character that is not a vowel or space
for ( ; *in; in++) {
if (strchr("aeiouAEIOU", *in) != NULL) {
// do nothing
} else if (*in == ' ') {
*out++ = *in;
up = 1; // we see a space, so next letter should be upper
} else if (up) {
*out++ = toupper(*in);
up = 0; // we see a letter (or other character), ignore case
} else {
*out++ = *in;
}
}
*out = '\0';
printf("%s\n", str);
}
Well now you have a few examples to study that take a bit of a different approach. See if you understand the logic, and try to make it so that other characters like e.g. ( and ) also delimit words.
One of the problems is that you've got too much code. It iterates through the entire array once to strip out vowels, then again to adjust the case of the first letter of each word. Imagine this is processing data that is measured in Gb. A second pass is unnecessary.
(And, there are standard library functions like isalpha() and toupper() that you should use. Don't write code with "magic numbers".)
It's worth studying a program's 'flow control', without resorting to arbitrary 'continue' statements to affect that flow.
It's also worth starting from scratch with a minimal block of code in main(), then developing your algorithm in a function (or several). Avoid the tendency to have one long, linear program all inside main(). If you can put functionality into 'compartments', each can be developed and tested and forgotten about as the program grows more complex.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// A single pass "compacts" the data (no vowels) while also using some single operations
//tracking changing from one word to the next (first letter to uppercase.)
char *func( char *str ) {
for ( int d = 0, s = 0, up = 0; (str[d] = str[s]) != '\0'; s++)
if( !strchr( " aeiouAEIOU" + !!up, str[d] ) ) {
if( str[d] == ' ' )
up = 1;
else if( up++ < 2 )
up++, str[d] = (char)toupper( (unsigned char)str[d] );
d++; // 'd'estination idx only increments here!
}
return str;
}
int main(void) {
// sample test strings
char *strs[] = {
"I am Iron Man",
" I am Iron Man ",
"Iron Man am I",
" Iron Man am I",
"The man of steel",
" The man of steel",
};
for( size_t i = 0; i < sizeof strs/sizeof strs[0]; i++ )
puts( func( strs[i] ) );
return 0;
}
M Rn Mn
M Rn Mn
Rn Mn M
Rn Mn M
Th Mn F Stl
Th Mn F Stl

Can C presume which array I want to store my characters?

I'm writing code which checks if an array is palindrome or not:
Write a program that reads a message, then checks whether it's a palindrome
(the letters in the message are the same from left to right as from right to left):
Enter a message: He lived as a devil, eh?
Palindrome
Enter a message: Madam, I am Adam.
Not a palindrome
When I have entered He lived as a devil, eh?,
it gives me the output Not a palindrome,
but the real output should be palindrome.
Below code is what I have tried so far.
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void) {
char message[MAX_LEN];
char c, *p = message, *q;
printf("Enter a message: ");
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
if (isalpha(c))
*p++ = c;
}
p--;
for (q = message; q < p; q++, p--) {
if (*p != *q) {
printf("Not a palindrome\n");
return 0;
}
}
printf("Palindrome\n");
return 0;
}
For starters you should declare the variable c as having the type int. The user can interrupt the input process in which case the function getchar returns integer value EOF and you should check whether this occurred.
char *p = message, *q;
int c;
There is a bug in the condition of the while statement
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
Instead of the bitwise operator & you have to use the logical AND operator &&.
As I already have said you should check in the condition of the while statement whether the user interrupted the input. For example
while ( p < message + MAX_LEN && ( c = toupper(getchar())) != EOF && c != '\n') {
if (isalpha(c))
*p++ = c;
}
The argument of a call of toupper or isalpha should be converted to the type unsigned char. Otherwise in general without the casting such a call can invoke undefined behavior.
It is desirable not to exclude from an entered string numbers. SO it is better at least to call the function isalnum instead of the function isalpha.
The user can enter an empty string in this case this decrement of the pointer
p--;
also can invoke undefined behavior.
And it is better when a program has one point to exit.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void)
{
char message[MAX_LEN];
printf( "Enter a message: " );
char *p = message;
for ( int c; p < message + MAX_LEN && ( c = getchar() ) != EOF && c != '\n'; )
{
if( isalnum( ( unsigned char )c ) )
{
*p++ = toupper( ( unsigned char )c );
}
}
int palindrome = 1;
if ( p != message )
{
for ( char *q = message; palindrome && q < --p; ++q )
{
palindrome = *q == *p;
}
}
printf( "The entered message is %spalindrome\n",
palindrome ? "" : "not " );
return 0;
}
Its output might look for example like
Enter a message: He lived as a devil, eh?
The entered message is palindrome
or like
Enter a message: Madam, I am Adam
The entered message is not palindrome
Pay attention to that instead of using a loop with numerous calls of the function getchar you could use only one call of the function fgets
fgets( message, sizeof( message ), stdin );
or
if ( fgets( message, sizeof( message ), stdin ) != NULL )
{
// check whether the entered string is a palindrome
}
Before check the palindrome you have to remove white spaces and punctuation marks. For an example if you use civic?, it is not palindrome because of ?. In the other hand if you use civ ic, it is not palindrome because of white space. There for
Convert all letters to uppercase or lowercase.
Remove white spaces.
remove punctuation marks.
Check palindrome or not.
You can do it by using # include <string.h>
First thing is you have to use scanf() which accept string with white space.
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
Then you have to convert that string to Uppercase or Lowercase because a != A. We know civic is a palindrome but Civic is not a palindrome('Civic != civiC) because Uppercase letters have different ASCII values and Lowercase letters have different ASCII values.
(a - z) -: 97 - 122
(A - Z) -: 65 - 90
In my case I have converted lowercase to uppercase.
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
Another case is your if you enter civ ic with white space, it's palindrome word is ci vic. You can see civ ic != ci vic. There for you have to remove white spaces in your program. And also you have to remove punctuation marks because if you use civic, it's reversed word is ,civic'. You can seecivic, != ,civic`.
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
Final thing is we have to revers our string and need to check if our reversed string is equal to our original string. If it is true our String is palindrome. If it is false our String is not a palindrome.
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
This the full code after you merging above parts
# include <stdio.h>
# include <string.h>
int main (void)
{
char word[100];
int i = 0;
int j, x = 0;
int a = 0;
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
printf("After converting it to uppercase = %s\n", word);
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
printf("After removing spaces = %s\n", word);
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
return 0;
}
First test Output -:
Enter a string = He lived as a devil, eh?
After converting it to uppercase = HE LIVED AS A DEVIL, EH?
After removing spaces = HELIVEDASADEVILEH
HELIVEDASADEVILEH is a palindroeme
Second test Output -:
Enter a string = Madam I am Adam.
After converting it to uppercase = MADAM I AM ADAM.
After removing spaces = MADAMIAMADAM
MADAMIAMADAM is not a palindrome

How to fix problem counting letters,symbols,numbers in string using function to check number

I want to count letters,numbers,symbols using function password Seems like it doesn't count out numbers correctly because i get 0 for every printf in the end
#include <stdio.h>
void password(char * str[],int together,int numbers,int symbols,int i,int uppercase,int lowercase);
int main()
{
char str[100];
int together, numbers, symbols, i,uppercase,lowercase;
together = numbers = symbols = i = uppercase = lowercase = 0;
printf("password : ");
gets(&str);
printf(" %s", str);
password(&str,together,numbers,symbols,i,uppercase,lowercase);
printf("Number of letters = %d\n", together);
printf("number uppercase = %d\n", uppercase);
printf("Number lowecase = %d\n", lowercase);
printf("numbers = %d\n", numbers);
printf("Simboli = %d", symbols);
if (together >= 8 && numbers >= 2){
printf("\nPassword is correct");
}else{
printf("\nPassword isn't correct");
}
return 0;
}
void password(char * str[],int together,int numbers,int symbols,int i,int uppercase,int lowercase){
while(*str[i]!='\0')
{
if((*str[i]>='a' && *str[i]<='z') || (*str[i]>='A' && *str[i]<='Z'))
{
together++;
}
else if(*str[i]>='0' && *str[i]<='9')
{
numbers++;
}
else if(*str[i] >= 'A' && *str[i] <= 'Z') {
uppercase++;
}
else if(*str[i] >= 'a' && *str[i] <= 'z'){
lowercase++;
}
else
{
symbols++;
}
i++;
}
}
I get zeroes for every number,letter & symbol program runs without any error I tried changing some stuff but I am currently learning C so it is hard for me!
Few points : 1) There is no need to pass i as argument since you can get the length of your string with strlen from string.h (which returns a size_t type and not an int). 2) You passed your arguments as value, which means that they'll only change locally to your function. 3) Don't use the gets function that is not safe, you may want to use fgets or scanf.
#include <string.h>
#include <stdio.h>
void password(char *str, int *together, int *numbers, int *symbols, int *uppercase, int *lowercase){
for(size_t i=0; i<strlen(str); i++){
if(str[i] >= '0' && str[i] <= '9') (*numbers)++;
if(str[i] >= 'A' && str[i] <= 'Z') (*uppercase)++;
if(str[i] >= 'a' && str[i] <= 'z') (*lowercase)++;
if(str[i] >= '!' && str[i] <= '/') (*symbols)++;
}
*together = (*uppercase) + (*lowercase);
}
int main(void){
char str[100] = "Pa$$w0/2d";
int together = 0;
int numbers = 0;
int symbols = 0;
int uppercase = 0;
int lowercase = 0;
password(str, &together, &numbers, &symbols, &uppercase, &lowercase);
printf("Letters = %d\n", together);
printf("Uppercase = %d\n", uppercase);
printf("Lowercase = %d\n", lowercase);
printf("Numbers = %d\n", numbers);
printf("Symbols = %d\n", symbols)
return 0;
}

C language - return a value from function as function parameter

I have a problem with my homework. I need to count quantity of upper case and quantity of vowels in string. Unfortunately, it always returns number 0 which looks as it doesn't change in function. Everything works until this one.
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[40];
int upper, chars;
puts("Type a string");
gets(text);
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white spece to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d", chars);
getch();
return 0;
}
char *StringChange(char *text, int *upper, int *chars) {
int i, length;
length = strlen(text);
for (i = 1; i <= length; i++) {
if (text[i - 1] == '*' && (text[i] >= 'a' && text[i] <= 'z')) {
text[i] = text[i] - 32;
}
if (text[i] == ' ') {
text[i] = '*';
}
if (text[i] >= 'A' && text[i] <= 'Z') {
*upper = *upper + 1;
/* *upper++; that also doesn't work */
}
if (text[i] == 'a' || text[i] == 'e' || text[i] == 'i' || text[i] == 'o' || text[i] == 'u' || text[i] == 'y') {
*chars = *chars + 1;
/* *chars++; that also doesn't work */
}
}
if (text[0] >= 'a' && text[0] <= 'z') {
text[0] = text[0] - 32;
}
return (text);
}
I tried your code and I do get non-zero results -- depending on the input, of course, so maybe you are only testing on strings that produce zero.
However, the results are not always correct. There are two problems I found in the code:
1) As pointed out in a comment, you should initialize upper and chars to 0.
2) You are starting the loop at index 1, not index 0. I think you did this so you could look at text[i-1] inside the loop, but it is causing you to exclude the first character from your totals. You should start the loop index and 0 and figure out a different way to handle it within the loop. (Hint - note that the first if within the loop and the one following the loop have similar conditions and the same body.)
There are multiple issues in your code:
you should never use gets().
the variables upper and chars are not initialized
the function StringChange make a special case of text[0] but does not update the counts for this initial byte.
you hard code the conversion of lowercase to uppercase for ASCII.
you should stop at the end of the string
all white space is not replaced, on whitespace followed by a lowercase letter.
uppercase vowels should be counted too.
Here is a modified version:
#include <stdio.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[200];
int upper, vowels;
puts("Type a string");
if (fgets(text, sizeof text, stdin)) {
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white space to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d\n", vowels);
}
getchar();
return 0;
}
char *StringChange(char *text, int *upper, int *vowels) {
int i, at_start = 1;
*upper = *vowels = 0;
for (i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (at_start && c >= 'a' && c <= 'z') {
c += 'A' - 'a';
text[i] = c;
}
if (c == ' ') {
c = '*';
text[i] = c;
at_start = 1;
} else {
at_start = 0;
}
if (c >= 'A' && c <= 'Z') {
(*upper)++; // *upper++ would just increment the pointer, leading to undefined behavior
}
if (strchr("aeiouyAEIOUY", c) {
(*vowels)++;
}
}
return text;
}

Resources