Count all characters in a string but spaces - c

I have so far, in my C code where it counts everything in a user given string, however, I only want it to count letters.
Whenever I try and take out or change the spaces counter my code ends up breaking and forces me to manually stop it.
I would like to use the spaces sometime later as a method to count words but I'd rather try and get the letters done first.
What I mean by it breaks is that the code will proceed to infinitely do nothing. I found this out when instead of putting something down I had it printed and it constantly repeated what was given with no stopping.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string s = get_string("Text: ");
int n = 0;
while (s[n] != '\0')
{
if (isalpha(s[n])) //counts letters
{
n++;
}
else
{
}
}
I would like to try and keep the code similar, but if its easier, a different way.
Also I would like to keep it to where it will be able to process a string given by the user.

If you look closely at the cycle:
while (s[n] != '\0')
{
if (isalpha(s[n])) //counts letters
{
n++;
}
}
you will notice that when s[n] is not alpha, n is not incremented, so you're stuck in an infinite loop.
The counter and the iterator should be different variables:
int count = 0;
//...
while (s[n] != '\0')
{
if (isalpha(s[n]))
{
count++; //counts letters
}
n++; //increment iterator
}

You have an infinite loop as soon as a non letter character is encountered due to the else statement
int n = 0;
while (s[n] != '\0')
{
if (isalpha(s[n])) //counts letters
{
n++;
}
else
{
}
}
You have to use two variables. The first one is to store the number of letters and the second one is to traverse a character array.
In such a case it is better to use the for loop instead of the while loop.
For example
size_t n = 0;
for ( size_t i = 0; s[i] != '\0'; i++ )
{
if ( isalpha( ( unsigned char )s[i] ) ) //counts letters
{
n++;
}
}
Pay attention to that there is no sense to declare the variable n as having the signed integer type int. It is better to declare it as having the unsigned integer type size_t. It is the type that for example the string function strlen has.

Related

How can I fix my program to not crash if I run any character that is not alphabetical?

So I am trying to write code that will allow me to count the number of letters a user has entered.
My code runs well if I simply type one word.
The moment that I include any character that is not a letter, my terminal stops working.
What can I do to fix it?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
int count_letters(string text);
int main(void)
{
string text = get_string("text? ");
int letters = count_letters(text);
printf("%i letters\n", letters);
}
int count_letters(string text)
{
int i = 0;
do
{
if (isalpha(text[i]))
{
i++;
}
else if (isspace(text[i]))
{
i = + 0;
}
else
{
i = +0;
}
} while (text[i] != 0);
return i;
}
i is the do ... while counter, do not use it to count the number of letters, use another variable, something like:
int count_letters(string text)
{
int i = 0, letters = 0;
do
{
if (isalpha((unsigned char)text[i]))
{
letters++;
}
i++;
}
while (text[i] != 0);
return letters;
}
Notice that with your approach the loop is also testing the NUL terminator in an empty string, use a while loop instead to exit the loop as soon as the NUL is found:
int count_letters(string text)
{
int letters = 0;
while (*text)
{
if (isalpha((unsigned char)*text))
{
letters++;
}
text++;
}
return letters;
}
Consider what happens in your loop: i only increments when the character at text[i] is an alphabetic character. Otherwise it resets to zero.
Thus, the loop will never complete for a string that is not entirely alphabetic characters because the loop will "reset" to the beginning with ever non-alphabetic character.
We can increment an index from zero until the character at that index in the string is the null-terminator of zero (which is false in C).
int count_letters(string text) {
int count = 0;
for (int i = 0; text[i]; i++) {
if (isalpha(text[i])) count++;
}
return count;
}
We can however, use pointers to iterate over your string, taking advantage of the detection of the null terminator to terminate the loop. If each character is an alphabetic character, increment a counter. A for loop can handle giving you a temp pointer and initializing it, testing for termination of the loop and incrementing the pointer.
int count_letters(string text) {
int count = 0;
for (char *ch = text; *ch; ch++) {
if (isalpha(*ch)) count++;
}
return count;
}
As text is a pointer passed by value (being hidden by CS50's string typedef), it can be modified without affecting the original string as long as we don't dereference and modify the individual characters, so we can avoid the extra char pointer.
int count_letters(string text) {
int count = 0;
for (; *text; text++) {
if (isalpha(*text)) count++;
}
return count;
}
As pointed out in the comment, i cannot serve two purposes (index and counter) except for the special case of a string comprised of only letters.
Below is a compact function that counts 'hits' when isalpha() has returned a non-zero value (indicating the current letter is in the range "A-Za-z").
The unusual "!!" transforms the non-zero positive value into C's true (or false) having values of 1 (or 0) respectively. Thusly, the value of 1 or 0 is appropriately added to the accumulator to be returned to the caller.
int count_letters( string text ) {
int i = 0, cnt = 0;
if( text != NULL ) // trust is good, testing is better
while( text[i] )
cnt += !!isalpha( (unsigned char)text[i++] );
return cnt;
}
EDIT and Credit: #Aconcagua for pointing out the need for casting each char to unsigned char to avoid UB.

Why is my code outputting random numbers even though they are just counts?

I am starting to learn c. I am trying to make a code that will count the amount of a's and A's in a sentence but the code gives me random numbers every time it is executed even if it is the same sentence.
#include <stdio.h>
#include <string.h>
int main()
{
char words[10000000000];
int i;
int acount = 0;
int Acount = 0;
char A[0]="A";
char a[0]="a";
printf("Input your sentence to be counted.");
scanf("%s",words);
printf("%s",words);
for (i=0;i<=sizeof(words);i++)
{
if (words[i]==a[0]){
acount++;
}else if (words[i]==A[0]){
Acount++;
}
}
printf ("\nThe number of A's is %i. The number of a's is %i.",Acount,acount);
return 0;
}
Why is my code outputting random numbers even though they are just
counts?
Because you're counting uninitialized memory, given the code you posted.
This is uninitialized:
char words[10000000000];
(If 10 GB fits....)
This only sets the memory in words for the string that's read, plus the terminating '\0' character:
scanf("%s",words);
Assuming it works, anyway. You don't check the return value, so maybe it didn't work...
Now what will this loop do? (Ignoring the fact that int likely isn't big enough to index a 10GB array...)
for (i=0;i<=sizeof(words);i++)
{
if (words[i]==a[0]){
acount++;
}else if (words[i]==A[0]){
Acount++;
}
}
That loop will check every char in the array word and compare it to either 'A' or 'a'. Every last 10 billion or so of them, many if not most of them likely containing unknown values.
It will also check one char past the end of word. That's not good. This will not check past the end of word:
size_t i;
...
for (i=0;i<sizeof(words);i++)
{
if (words[i]==a[0]){
acount++;
}else if (words[i]==A[0]){
Acount++;
}
}
Note the change to < instead of <=, and the use of size_t for i instead of int.
Even better, so you don't try counting random data:
size_t i;
...
for (i = 0; words[i]; i++) {
if (words[i] == a[0]) {
acount++;
} else if (words[i] == A[0]) {
Acount++;
}
}
Since a string ends in a '\0' char value, the loop will now end when words[i] has a zero value.

Counting the number of times a character appears in a string in c programming?

The for loop below continues until the end of the string, while the if branch checks to see how many times the character 'u' appears in the string, "yuzuf Oztuk", which is 3 times. Meanwhile, the variable count counts the number of u's in the string. When i compile the code, I get 15 for the number of times u appears in the string, which is wrong.
int numTimesAppears(char* mystring, char ch)
{
int i;
int count;
for(i = 0; mystring[i] != '\0' ; ++i)
{
if (mystring[i] == ch)
{
count++;
}
}
return count;
}
I get 15 for the number of times u appears in the string, which is wrong.
Key issue: Code needs to initialize the value of count. #BLUEPIXY
// int count;
int count = 0;
Corner case: As the null character is in the string, a result of 1 "for number of times a character appears in a string" would be expected for any numTimesAppears(some_string, '\0'). A do loop fixes that. A similar standard library function is strchr(), which looks for the first match and considers the null character part of the search-able string: "... terminating null character is considered to be part of the string." As with all corner cases, various results could be inferred - best to document the coding goal in this case.
i = 0;
do {
if (mystring[i] == ch) {
count++;
}
} while (mystring[i++]);
As the function does not modify the inspected string, making it const increases the function's applicability and perhaps performance. #Vlad from Moscow
Array indexing best uses size_t rather than int. int may be too narrow.
size_t numTimesAppears(const char* mystring, char ch) {
size_t count = 0;
size_t i = 0;
do {
if (mystring[i] == ch) {
count++;
}
} while (mystring[i++]);
return count;
}

Checking if a string is a palindrome - when I compile the program shuts down

I'm trying to write a C program which eats a string of a priori bounded length and returns 1 if it's a palindrome and 0 otherwise. We may assume the input consists of lower case letters.
This is a part of a first course in programming, so I have no experience.
Here's my attempt. As soon as I try to build/run it on CodeBlocks, the program shuts down. It's a shame because I thought I did pretty well.
#include <stdio.h>
#define MaxLength 50
int palindrome(char *a,int size) /* checks if palindrome or not */
{
int c=0;
for(int i=0;i<size/2;i++) /* for every spot up to the middle */
{
if (*(a+i)!=*(a+size-i-1)) /* the palindrome symmetry condition */
{
c++;
}
}
if (c==0)
{
return 1; /*is palindrome*/
}
else
return 0; /*is not palindrome*/
}
int main()
{
char A[MaxLength]; /*array to contain the string*/
char *a=&A[0]; /*pointer to the array*/
int i=0; /*will count the length of the string*/
int temp;
while ((temp=getchar())!='\n' && temp != EOF) /*loop to read input into the array*/
{
A[i]=temp;
i++;
}
if (palindrome(a,i)==1)
printf("1");
else
printf("0");
return 0;
}
Remark. I'm going to sleep now, so I will not be responsive for a few hours.
Your approach is ok, though you have a number of small errors. First,#define MaxLength=50 should be #define MaxLength 50 (the text to replace, space, then its replacement).
You should also provide a prototype for your palindrome() function before main():
int palindrome(char *a,int size);
...or just move the whole palindrome() function above main(). Either a prototype or the actual function definition should appear before any calls to the function happen.
Next issue is that you're looking for a null character at the end of the input string. C strings are usually null terminated, but the lines coming from the console aren't (if there's a terminator it would be added by your program when it decides to end the string) -- you should probably check for a newline instead (and ideally, for errors as well). So instead of
while ((temp=getchar())!='\0')
try
while ((temp=getchar())!='\n' && temp != EOF)
When you print your results in main(), you should have a newline at the end, eg. printf("1\n"); instead of printf("1");, to ensure the output buffer gets flushed so you can see the output as well as to end that output line.
Then in your palindrome() function, your for loop sytax is wrong -- the three parts should be separated with semicolons, not commas. So change:
for(int i=0,i<size/2,i++)
...to:
for(int i=0; i<size/2; i++)
You also have an extra closing brace for the loop body to remove.
After fixing all that, it seems to work...
This directive
#define MaxLength=50
is invalid. There should be
#define MaxLength 50
Change the loop in main the following way
int temp;
^^^
while ( i < MaxLength && ( temp = getchar () )!= EOF && temp != '\n' )
{
A[i] = temp;
i++;
}
Otherwise if to use the original loop you have to place the zero into the buffer directly using the alt key and the numeric keypad.
The function itself can be written simpler
int palindrome( const char *a, int size) /* checks if palindrome or not */
{
int i = 0;
while ( i < size / 2 && *( a + i ) == *( a + size - i - 1 ) ) ++i; {
return i == size / 2;
}

Compiler Error in C -- Expected ')' before '!' token.

I'm coding a basic program to check if a string is a palindrome or not.
#include <stdio.h>
#include <string.h> //Has some very useful functions for strings.
#include <ctype.h> //Can sort between alphanumeric, punctuation, etc.
int main(void)
{
char a[100];
char b[100]; //Two strings, each with 100 characters.
int firstchar;
int midchar;
int lastchar;
int length = 0;
int counter = 0;
printf(" Enter a phrase or word for palindrome checking: \n \n ");
while ((a[length] == getchar()) !10 ) //Scanning for input ends if the user presses enter.
{
if ((a[length -1]), isalpha) // If a character isalpha, keep it.
{
b[counter] = a[length-1];
counter++;
}
length--; //Decrement.
}
makelower(b, counter); //Calls the function that changes uppercase to lowercase.
for( firstchar = 0; firstchar < midchar; firstchar++ ) //Compares the first and last characters.
{
if ( a[firstchar] != a[lastchar] )
{
printf(", is not a palindrome. \n \n");
break;
}
lastchar--;
}
if( firstchar == midchar )
{
printf(", is a palindrome. \n \n");
}
return 0;
}
//Declaring additional function "makelower" to change everything remaining to lowercase chars.
int makelower (char c[100], int minicount)
{
int count = 0;
while (count <= minicount)
{
c[count] = tolower(c[count]);
}
return 0;
}
And I'm getting the following compiler error on the line with the first while loop, immediately after the printf statement:
p5.c: In function 'main':
p5.c:30: error: expected ')' before '!' token
I've looked up and down, but I haven't found any out-of-place or nonpartnered parenthesis. The only thing I can think of is that I'm missing a comma or some kind of punctuation, but I've tried placing a comma in a few places to no avail.
Sorry if this is too specific. Thanks in advance.
while ((a[length] == getchar()) !10 )
What it looks like you're trying for is assigning to a[length] the result of getchar() and verifying that that is not equal to 10. Which is spelled like so:
while ((a[length] = getchar()) != 10)
= is assignment, == is the test.
Further, your counters are confused. length is initialized to 0 and is only decremented, which will lead to falling off the front of the array after the first decrement. This doesn't get a chance to happen, because you attempt to access a[length-1], which will also fail. This looks like a off-by-one error, also known as a fencepost error, in accessing the character you just read from getchar().
Also, since nothing is checking that the length of recorded input doesn't exceed the length of your buffer a[100], you could fall off the end there as well.
The counters for your palindrome check function are also off. midchar and lastchar are never initialized, midchar is never set, and lastchar is decremented without ever having a value set. You would probably be better off testing a[firstchar] == a[(counter-1)-firstchar].

Resources