Why is there an extra line after my output? - c

#include <stdio.h>
#include <ctype.h>
int main()
{
char str[100];
char splitStrings[10][10];
int i, j, cnt;
printf("Enter a sentence, up to 255 charcters: \n");
fgets(str, sizeof str, stdin);
j = 0; cnt = 0;
for (i = 0; i <= (strlen(str)); i++)
{
if (!ispunct(str[i]) == ' ' || isalpha(str[i]) == '\0')
{
splitStrings[cnt][j] = '\0';
cnt++; //for next word
j = 0; //for next word, init index to 0
}
else
{
splitStrings[cnt][j] = str[i];
j++;
}
}
for (i = 0; i < cnt; i++)
printf("\n%s %d \n", splitStrings[i], strlen(splitStrings[i]));
return 0;
}
Here is my code, I am trying to input a sentence and it will spilt up the string by words and count the number of letter. But it appear there an additional 0 in my output? And how do I get rid of it
output

fgets() will put a newline character it read into the buffer when the input is short enough to fit (as in the example data).
The newline character is not an alphabet, so isalpha(str[i]) == '\0' will become true and it moves on next word.
Then, the next charcter is terminating null-character. (it is processed because the loop condition is i <= (strlen(str)))
It is also not an alphabet, so it also moves on next word.
There are no characters between the newline character and the terminating null-character, so it is printed as zero-character word.

Related

Find most frequent letter in C

Here is my code to find the most frequent letter in an string. I need to store the most frequent letters in the most_freq string and they should be in alphabetical order too.
I don't know how to handle the situation where there are more letters with the same frequency and they are also the most frequent.
char text[200];
char most_freq[27];
int freq[26];
int i;
int counter;
int temp = 0;
int max_freq;
fgets(text, sizeof(text), stdin);
size_t len = strlen(text);
if (text[len - 1] == '\n') {
text[len - 1] = '\0';
len--;
}
for (i = 0; i < 26; i++) {
freq[i] = 0;
}
for (i = 0; i < len; i++) {
if (text[i] >= 'a' && text[i] <= 'z') {
counter = text[i] - 'a';
freq[counter]++;
}
}
int max = 0;
for (i = 0; i < 26; i++) {
if (freq[i] > temp) {
temp = freq[i];
max_freq = temp;
}
printf("%c occurs %d times.\n", i + 'a', freq[i]);
if (freq[i] > freq[max]) {
max = i;
}
}
printf("Highest frequency: %d \n", max_freq);
//printf("%c \n",max+'a');
sprintf(most_freq, "%c", max + 'a');
puts(most_freq);
#include <stdio.h>
#include <ctype.h>
#define SIZE 99
int main() {
char s[SIZE];
int freq[26] = {0}, i, max = 0;
fgets(s, SIZE, stdin);
for(i = 0; s[i]; i++) {
if( isalpha((unsigned char)s[i]) ) ++freq[s[i] - ( islower((unsigned char)s[i]) ? 'a' : 'A')];
}
for(i = 0; i < 26; i++) {
if( max < freq[i] ) max = freq[i];
}
for(i = 0; i < 26; i++) {
if( freq[i] == max ) putchar('a'+i);
}
return 0;
}
I've done it by first calculating all of the letter frequencies, then finding the maximum letter frequency, and finally find printing all the characters to have that maximum frequency.
Here is my solution. I commented it to make it clearer:
#include <stdio.h>
#include <ctype.h>
int main() {
char text[200] = { 0 };
size_t freq[26] = { 0 };
// get the user's text
fgets(text,sizeof(text),stdin);
const size_t len = strlen(text);
// calculate frequencies
for (size_t i = 0; i < len; ++i)
if (text[i] >= 'a' && text[i] <= 'z')
++freq[text[i]-'a'];
size_t maxCount = 0;
// find the maximum frequency and print each letter's frequency
for (size_t i = 0; i < sizeof(freq); ++i) {
if (freq[i] > maxCount)
maxCount = freq[i];
printf("%c occurs %d times.\n", i+'a', freq[i]);
}
printf("\n\n"); // padding
// Print all characters with the maximum frequency
for (size_t i = 0; i < sizeof(freq)/sizeof(freq[0]); ++i)
if (freq[i] == maxCount)
printf("%c occurs with maximum frequency.\n", 'a'+i);
}
EDIT: You could also extend your program by making it work with letters of any case by using the tolower() function from libc's ctype.h header file to make all characters lowercase when calculating their frequencies.
The line ++freq[text[i]-'a']; would become ++freq[tolower(text[i])-'a'];.
Here is a simpler version:
#include <stdio.h>
int main() {
char text[200];
int freq[26] = { 0 };
int max_freq = 0;
// read use input or use the empty string
if (!fgets(text, sizeof(text), stdin))
*text = '\0';
// compute frequencies, update maximum frequency
for (int i = 0; text[i] != '\0'; i++) {
if (text[i] >= 'a' && text[i] <= 'z') {
int index = text[i] - 'a'; // assuming ASCII
if (++freq[index] > max_freq)
max_freq = freq[index]; // update maximum frequency
}
}
// print characters with maximum frequency in alphabetical order
for (int i = 0; i < 26; i++) {
if (freq[i] == max_freq)
putchar('a' + i);
}
putchar('\n');
return 0;
}
Generally, when wanting the frequency of any object within a specified range, you want your frequency array to cover the entire range of possible values for that object. For a full explanation of what is frequency array is, and how to use it, a fuller explanation is provided in answer to How to remove duplicate char in string in C
In this case for ASCII characters, you have a range of 128 possible value (or 256 if you include the extended ASCII set), See ASCII Table & Description. By creating your frequency array with 128 (or 256) elements, you eliminate having to check for special cases such as lower/uppercase characters.
For example, you could cover all ASCII characters and find the most frequent a user may enter with the following:
#include <stdio.h>
#include <ctype.h>
#define SIZE 256 /* size works for both frequency array and text as a multiple */
int main (void) {
char text[SIZE * 4]; /* 1024 byte buffer */
int freq[SIZE] = {0}, max = 0; /* frequeny array & max */
fputs ("enter string: ", stdout); /* prompt */
if (!fgets (text, SIZE, stdin)) { /* read/validate EVERY input */
puts ("(user canceled input)");
return 0;
}
for (int i = 0; text[i]; i++) /* loop over each char */
if (++freq[(unsigned char)text[i]] > max) /* increment/check against max */
max = freq[(unsigned char)text[i]];
printf ("\nmost frequent appear %d times: ", max);
for (int i = '!'; i < SIZE; i++) /* loop over freq array */
if (freq[i] == max) /* if count == max */
putchar (i); /* output char */
putchar ('\n'); /* tidy up with newline */
}
(note: since a user may validly cancel input generating a manual EOF by pressing Ctrl + d, or Ctrl + z on windows, it is good to validate every input and handle the EOF case as well as any other possible failure modes)
Since ASCII characters below ' ' (space, 32, 0x20) are non-printable or whitespace such as '\t', '\n', \r, etc.., you can begin your output loop with the '!' character to ignore whitespace. If you need the frequency of every character, you can create a short lookup table with the string representations of each non-printable or whitespace character. That way if the ' ' character were the, or one of the, most frequent characters, you could output, e.g. "(sp)" or something similar, "(tab)" for tab, etc..
Example Use/Output
$ ./bin/badfreq
enter string: 123+HH~helloo+345
most frequent appear 2 times: +3Hlo
Saving Most Frequent Characters To Array
There are very few changes needed to buffer the most frequently occurring characters in an array instead of directly outputting them with putchar(). All you need to do is declare an array of sufficient size to hold the maximum number of possible characters (+1 to allow space for a nul-terminating character if you wish to treat the array as a C-string.
Below we add the buffer (character array) most_freq[] to hold the most frequently used characters, and the fill the most_freq[] array where we were simply outputting it in the first example, e.g.
#include <stdio.h>
#include <ctype.h>
#define SIZE 256 /* size works for both frequency array and text as a multiple */
int main (void) {
char text[SIZE * 4], /* 1024 byte read buffer */
most_freq[SIZE + 1] = ""; /* 257 byte buffer for storage */
int freq[SIZE] = {0}, /* frequeny array */
max = 0, /* times most frequent occurs */
mf_ndx = 0; /* most_frequent index */
fputs ("enter string: ", stdout); /* prompt */
if (!fgets (text, SIZE, stdin)) { /* read/validate EVERY input */
puts ("(user canceled input)");
return 0;
}
for (int i = 0; text[i]; i++) /* loop over each char */
if (++freq[(unsigned char)text[i]] > max) /* increment/check against max */
max = freq[(unsigned char)text[i]];
for (int i = '!'; i < SIZE; i++) /* loop over freq array */
if (freq[i] == max) /* if count == max */
most_freq[mf_ndx++] = i; /* store in most_freq array */
most_freq[mf_ndx] = 0; /* nul-terminate as string */
printf ("\n%d most frequent chars appear %d times: %s\n", /* output results */
mf_ndx, max, most_freq);
}
Following exit of the loop we use to fill the array, we add the nul-termianting character '\0' (same as plain old ASCII 0) after the last character added so we can then treat the most_freq[] array as a string.
Example Use/Output
This does allow a simple way to provide a bit more information in the output, e.g.
$ ./bin/most_freq_array
enter string: 123+HH~helloo+345
5 most frequent chars appear 2 times: +3Hlo
Or in your specific example case of "helloo":
$ ./bin/most_freq_array
enter string: helloo
2 most frequent chars appear 2 times: lo
Look things over and let me know if your have further questions.

Reversing an input string

I am trying to capture a user input string, then display that string in reverse order next to the initial string. My code is as follows:
char str[300], revstring[300];
int i, strlen;
int main(void) {
printf("Enter a string: "); //Prompt user for input string
gets(str);
for (i = 0; str[i] != NULL; i++) { //Get length of string
strlen += 1;
}
for (i = 0; i <= strlen; i++) {
revstring[i] = str[strlen - i];
}
printf("\n\nThe palindrome of your input is %s%s\n\n\n", str, revstring);
return 0;
}
When I run the program however, I see nothing after the initial string. I come from a python background so maybe I am thinking about this in too much of a python mindset, but I feel like this should work.
After this loop
for (i = 0; str[i] != NULL; i++) { //Get length of string
strlen += 1;
}
str[strlen] is equal to the terminating zero '\0'. And the next loop starts from writing this zero in the first element of the array revstring when i is equal to 0.
for (i = 0; i <= strlen; i++) {
revstring[i] = str[strlen - i];
}
As result nothing is displayed.
Also you should not forget to append the result string with the terminating zero.
Take into account that the function gets is unsafe and is not supported any more by the C Standard. It is better to use the standard function fgets. But using it you should remove the appended new line character.
The program can be written the
#include <stdio.h>
#define N 300
int main( void )
{
char str[N], revstring[N];
printf( "Enter a string: " );
fgets( str, N, stdin );
size_t length = 0;
while ( str[length] != '\0' && str[length] != '\n' ) ++length;
if ( str[length] == '\n' ) str[length] = '\0';
size_t i = 0;
for ( ; i != length; i++ ) revstring[i] = str[length - i - 1];
revstring[i] = '\0';
printf("\n\nThe palindrome of your input is %s%s\n\n\n", str, revstring);
return 0;
}
Its output might look like
Enter a string: Hello, Froobyflake
The palindrome of your input is Hello, FroobyflakeekalfyboorF ,olleH
The string is a null-terminated string. You are copying the null character to the beginning of the reversed string. This tells the system that they string is terminated at the first character.
You could use this code instead.
for (i = 0; i < strlen; i++)
{
revstring[i] = str[(strlen - 1) - i];
}
revstring[strlen] = 0;
Here only the characters before the null character are copied and then the null character is added at the end.

I want my code to print the frequency of characters in the order of appearance of string

My code is printing the frequency of characters in random order. What can be done so that it prints the frequency of characters in order in which the word is given. My current code is as follows
#include <stdio.h>
#include <conio.h>
void main() {
char string1[50];
int i = 0, counter[26] = { 0 };
printf("\nEnter a string\n");
//Inputs a string
gets(string1);
while (string1[i] != '\0') {
//checks and includes all the characters
if (string1[i] >= 'a' && string1[i] <= 'z') {
//counts the frequency of characters
counter[string1[i] - 'a']++;
i++;
}
}
//printing frequency of each character
for (i = 0; i < 26; i++) {
if (counter[i] != 0)
printf("%c occurs %d times.\n", i + 'a', counter[i]);
}
getch();
}
sample output:
There are several issues in your code:
you use gets: this function is unsafe, it was removed from the current version of the C Standard.
you increment i only for if string1[i] is a lowercase letter: you will run an infinite loop if you type any other character.
the proper prototype for main is either int main(void) or int main(int arc, char *argv[]).
you only count lower case letters. H is upper case, thus not counted.
Here is an improved version:
#include <stdio.h>
#include <ctype.h>
int main(void) {
char string1[128];
int i = 0, counter[256] = { 0 };
printf("\nEnter a string\n");
//Inputs a string
if (fgets(string1, sizeof string1, stdin) == NULL) {
// empty file: got an empty line
*string1 = '\0';
}
for (i = 0; string1[i] != '\0'; i++) {
if (isalpha((unsigned char)string1[i])) {
//counts the frequency of letters
counter[string1[i]]++;
}
}
//printing frequency of each counted character
//characters are printed in the order of appearance
for (i = 0; string1[i] != '\0'; i++) {
if (counter[string1[i]] != 0) {
printf("%c occurs %d times.\n",
string1[i], counter[string1[i]]);
counter[string1[i]] = 0; // print each letter once.
}
}
getch();
return 0;
}
You can get the characters printed in order of their appearance by using the string a second time to generate the output.
In your section where you are "printing the frequency of each character", use the code to process the input string. This time, if the frequency value is not zero, print it and then reset the frequency value to zero. If the frequency value is zero, you must have already printed it so do nothing.
//printing frequency of each counted character (in input order)
for (i = 0; string1[i] != '\0'; i++) {
char ch = string[i];
if (counter[ch - 'a'] != 0) {
printf("%c occurs %d times.\n", ch, counter[ch - 'a']);
counter[ch - 'a'] = 0;
}
}

Infinite Loop when counting with an array [C]

I've been trying to get back into C lately (for work related purposes) and I've been to a C refresher workshop. I can't seem to get my head around why an infinite loop occurs in this code.
I'm trying to code a program which returns the number of words within an array of characters. Any help would be greatly appreciated. Thanks!
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
int i;
printf("Enter a sentence with at most %d characters:\n", LENGTH);
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
Your use of scanf isn't good.
word_count cause infinite loop because i isn't updated in the while loop.
fixed code:
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i = 0, word = 1;
while(str[i] != '\0') {
if((isspace(str[i])))
{
word++;
}
i++;
}
return word;
}
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Here you are reading a char one by one. so it should have %c, like scanf(" %c", &sentence[i]);
However, this wont be the right way to read the string. Since, it wont put the \0 in the end.
Since the string to be read will contain spaces, best way to do this would be fgets()
Your counting loop also has an error, either you can change it to one of the answers above or simply use a single for loop, like this
for(i = 0; i < LENGTH && str[i] != '\0'; i++)
if((isspace(str[i])))
{
word++;
}
In your code,i isn't actually in the loop.Besides,array contains the sentence with a \0 in the end,so if the length of the sentence is 50,the space must be 51 since at the end of it there is an \0,and scanf is not so good as it judges " "as a stop sign,gets can't stop until enter key which may cause overflow,so I use fgets.
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH+1];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
char* p=str;
int word=0;
while(*p!='\0'){
if((isspace(*p))) word++;
p++;
}
return word;
}
You should read data from stdin, not scanf but fgets or gets!
Maybe fgets( sentence, LENGTH, stdin ) is good.
And in the function word_count you may replace while with if.
This part of the program
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
does not make sense. It tries to enter LENGTH number of words in the loop.
I think you mean format specifier %c instead of %s
scanf("%c", &sentence[i]);
but even in this case this snippet of code is wrong because the user can enter either less than LENGTH characters or even greater than LENGTH characters and the character array sentence will not be zero-terminated..
It is better to use standard function fgets instead of scanf in this situation.
And function word_count is also wrong. For example if str would be zero-terminated nevertheless the outer for loop will try to count words outside the string. And the function in fact counts the number of spaces. It is not the same as the number of words. A string can contain adjasted spaces. This mistake is made by all others in their answers.:)
And inside the while loop variable i is not increased. So it is an infinite loop.
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
The program can look the following way
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
size_t word_count( const char[] );
int main( void )
{
char sentence[LENGTH];
printf( "Enter a sentence with at most %d characters: ", LENGTH );
fgets( sentence, LENGTH, stdin );
printf( "Sentence = \"%s\"\n", sentence );
printf( "Word count = %zu\n", word_count( sentence ) );
return 0;
}
// Count the number of words in str
size_t word_count( const char s[] )
{
size_t words = 0;
while ( *s != '\0' )
{
// skip white spaces
while ( isspace( ( unsigned char )*s ) ) ++s;
if ( *s != '\0' ) ++words;
// skip the word
while ( *s != '\0' && !isspace( ( unsigned char )*s ) ) ++s;
}
return words;
}
Its output might look like
Enter a sentence with at most 50 characters: Hello, Unholy Wish
Sentence = "Hello, Unholy Wish"
Word count = 3
It's not an infinite loop.
Your program is trying to read 50 (or LENGTH) words (and saving them on top of each other).
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Put first word starting at sentence[0];
put second word starting at sentence[1] overwriting characters from the first word;
...

Copy strings with limited characters

Alright this is a homework question whereby I can't use the string.h library. This function is to copy not more than n characters (characters that
follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1.
int main()
{
char sourceString[100];
char targetString[100];
int num;
printf("Enter a string:");
gets(sourceString);
printf("Enter no. of characters: ");
scanf("%d", &num);
printf("stringncpy(): %s", stringncpy(targetString, sourceString, num));
}
char *stringncpy(char * s1, char * s2, int n)
{
int i;
for (i = 0; i < n; i++)
{
if (s2[i] != '\0')
{
s1[i] = s2[i];
}
else
{
break;
}
}
s1[i] = '\0';
return s1;
}
It runs fine except that it is printing some rubbish unrecognizable characters after n characters. Apprantly running the code with http://ideone.com/, I don't get those rubbish characters but on VS it does.
Because gets is used it is better to use
if (s2[i] != '\0' && s2 [i] != '\n')
instead if
if (s2[i] != '\0')
And if n define the max numer of character you should ensure that n < 100. When after for loop i == n writing '\0' to i-th position can cause a problem. Or maybe loop should be
for (i = 0; i < n-1; i++)

Resources