My program should first read an entered string word and then count the amount of repeated letters.
For example, if I enter apple it should print 1, but instead it prints 4.
I suppose word[i] = word[i + 1] isn't the right way to count?
#include<stdio.h>
int main() {
int i, j, wordLength = 0, alphabeticalSort, counter = 0, swap;
char word[51];
scanf("%s", word);
while (word[wordLength] != '\0'){
wordLength++;
}
...
for (i = 0; i < wordLength; i++){
if (word[i] = word[i + 1])
counter++;
}
printf("\nNumber of repeated letters: %d", counter);
...
return 0;
}
It's best to split what you're doing into two functions, one of which will count the number of occurrences of each letter.
#define LETTERS 26
/* counts number of occurrences of each lowercase letter in str. Result is placed in outCounts,
assuming it has room */
void countletters(char *str, int outCounts[])
{
memset(outCounts, 0, LETTERS * sizeof (int));
for (; *str; ++str) {
if (isupper(*str))
*str = tolower(str);
if (islower(*str))
++outCounts[*str - 'a'];
}
}
Then you write another function will examines the outCounts array, which is modified. If a letter is repeated, the corresponding member of this array will be greater than one. I leave this as an exercise to the reader.
You have:
for (i = 0; i < wordLength; i++){
if (word[i] = word[i + 1])
counter++;
}
Look at the 'comparison' inside the loop; you're giving the value of word[i+1] to word[i+1]. This condition will always be true unless the word[i+1]'s value is a 0 or a null char which is also a 0 in the ASCII table.
Remember: the equality operator in C is always ==, so replace the = with ==.
int main()
{
char string[80];
int c = 0, count[26] = {0}, x;
printf("Enter a string\n");
//gets(string);
scanf("%s", string);
while (string[c] != '\0') {
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
c++;
}
for (c = 0; c < 26; c++)
printf("%c occurs %d times in the string.\n", c + 'a', count[c]);
return 0;
}
Related
I'm quite new to C and I'm wondering why in the code below, the char I'm comparing to each letter of the string word is showing that it's equal everytime.
For example
If I've inputted the word
apple
and I'm looking for any repeating char in "apple" my function. I pass in to the function each char of apple such as a, p, p etc. It should return 1 when I pass in p since it's repeated, but instead, for every char of apple, my function says a == word[0], a == word[1] even though word[1] for "apple" is 'p'.
I know char is ASCII, so each char has a number value, but I'm not sure why this is not working. Perhaps, I'm using the pointer *word in the functions arguments incorrectly?
My code is below for my function, rpt_letter:
int rpt_letter(char *word, char c)
{
int i;
int count = 0;
i = 0;
printf("This is the WORD %s\n", word);
while(count < 2)
{
if(word[i] == c)
{
count++;
printf("the count is %d\n the char is %c and the string is %c\n", count, c, word[i]);
}
i++;
}
if (count<2)
{
// printf("letter %c was not found in the array. \n", c);
return 0;
}
else
{
//printf("letter %c was found at index %d in the array.\n", c, mid);
repeats[rpt_counter] = c;
rpt_counter++;
return 1;
}
return 0;
}
I'll include the main method just in case -- but I believe the main method is working well
int main(void)
{
//! showArray(list, cursors=[ia, ib, mid])
//int n = 51;
char word[51];
scanf("%s", word);
//length of string
for (n=0; word[n] != '\0'; n++); //calculate length of String
printf("Length of the string: %i\n", n);
int count = 0;
//sort words
int i;
char swap = ' ';
for(int k = 0; k < n; k++)
{
for (i=0; i<n-1; i++)
{
//if prev char bigger then next char
if (word[i] > word[i+1])
{
//make swap = prev char
swap = word[i];
//switch prev char with next char
word[i] = word[i+1];
//make next letter char
word[i+1] = swap;
}
}
}
printf("%s\n", word);
for (i=0; i<n-1; i++)
{
int rpt = rpt_letter(word, word[i]);
if(rpt == 1)
{
count++;
}
}
printf("%d", count);
return 0;
}
I've tried a number of things such as using the operator !=, also <, > but it gives me the same result that each word[ia] == c.
You are getting this issue because in your code rpt_letter() the while loop has a terminating condition count >= 2. Now consider input apple and character a. As a appears in apple only once, the count after traversing the whole word remains 1. But the loop doesn't terminate. So, the index i becomes greater than the length of string and tries to check the character appearing after that.
The loop terminates eventually when it gets another a this way. You need to add a check for the terminating null character in your loop so that it doesn't cross the length of the string .
Change the while loop condition to something like -
while((count < 2) && (word[i] != '\0'))
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;
}
}
My program is designed to allow the user to input a string and my program will output the number of occurrences of each letters and words. My program also sorts the words alphabetically.
My issue is: I output the words seen (first unsorted) and their occurrences as a table, and in my table I don't want duplicates. SOLVED
For example, if the word "to" was seen twice I just want the word "to" to appear only once in my table outputting the number of occurrences.
How can I fix this? Also, why is it that i can't simply set string[i] == delim to apply to every delimiter rather than having to assign it manually for each delimiter?
Edit: Fixed my output error. But how can I set a condition for string[i] to equal any of the delimiters in my code rather than just work for the space bar? For example on my output, if i enter "you, you" it will out put "you, you" rather than just "you". How can I write it so it removes the comma and compares "you, you" to be as one word.
Any help is appreciated. My code is below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 1000
void occurrences(char s[], int count[]);
void lower(char s[]);
int main()
{
char string[SIZE], words[SIZE][SIZE], temp[SIZE];
int i = 0, j = 0, k = 0, n = 0, count;
int c = 0, cnt[26] = { 0 };
printf("Enter your input string:");
fgets(string, 256, stdin);
string[strlen(string) - 1] = '\0';
lower(string);
occurrences(string, cnt);
printf("Number of occurrences of each letter in the text: \n");
for (c = 0; c < 26; c++){
if (cnt[c] != 0){
printf("%c \t %d\n", c + 'a', cnt[c]);
}
}
/*extracting each and every string and copying to a different place */
while (string[i] != '\0')
{
if (string[i] == ' ')
{
words[j][k] = '\0';
k = 0;
j++;
}
else
{
words[j][k++] = string[i];
}
i++;
}
words[j][k] = '\0';
n = j;
printf("Unsorted Frequency:\n");
for (i = 0; i < n; i++)
{
strcpy(temp, words[i]);
for (j = i + 1; j <= n; j++)
{
if (strcmp(words[i], words[j]) == 0)
{
for (a = j; a <= n; a++)
strcpy(words[a], words[a + 1]);
n--;
}
} //inner for
}
i = 0;
/* find the frequency of each word */
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
}
}
}
/* count - indicates the frequecy of word[i] */
printf("%s\t%d\n", words[i], count);
/* skipping to the next word to process */
i = i + count;
}
printf("ALphabetical Order:\n");
for (i = 0; i < n; i++)
{
strcpy(temp, words[i]);
for (j = i + 1; j <= n; j++)
{
if (strcmp(words[i], words[j]) > 0)
{
strcpy(temp, words[j]);
strcpy(words[j], words[i]);
strcpy(words[i], temp);
}
}
}
i = 0;
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
}
}
}
printf("%s\n", words[i]);
i = i + count;
}
return 0;
}
void occurrences(char s[], int count[]){
int i = 0;
while (s[i] != '\0'){
if (s[i] >= 'a' && s[i] <= 'z')
count[s[i] - 'a']++;
i++;
}
}
void lower(char s[]){
int i = 0;
while (s[i] != '\0'){
if (s[i] >= 'A' && s[i] <= 'Z'){
s[i] = (s[i] - 'A') + 'a';
}
i++;
}
}
I have the solution to your problem and its name is called Wall. No, not the type to bang your head against when you encounter a problem that you can't seem to solve but for the Warnings that you want your compiler to emit: ALL OF THEM.
If you compile C code with out using -Wall then you can commit all the errors that people tell you is why C is so dangerous. But once you enable Warnings the compiler will tell you about them.
I have 4 for your program:
for (c; c< 26; c++) { That first c doesn't do anything, this could be written for (; c < 26; c++) { or perhaps beter as for (c = 0; c <26; c++) {
words[i] == NULL "Statement with no effect". Well that probably isn't what you wanted to do. The compiler tells you that that line doesn't do anything.
"Unused variable 'text'." That is pretty clear too: you have defined text as a variable but then never used it. Perhaps you meant to or perhaps it was a variable you thought you needed. Either way it can go now.
"Control reaches end of non-void function". In C main is usually defined as int main, i.e. main returns an int. Standard practice is to return 0 if the program successfully completed and some other value on error. Adding return 0; at the end of main will work.
You can simplify your delimiters. Anything that is not a-z (after lower casing it), is a delimiter. You don't [need to] care which one it is. It's the end of a word. Rather than specify delimiters, specify chars that are word chars (e.g. if words were C symbols, the word chars would be: A-Z, a-z, 0-9, and _). But, it looks like you only want a-z.
Here are some [untested] examples:
void
scanline(char *buf)
{
int chr;
char *lhs;
char *rhs;
char tmp[5000];
lhs = tmp;
for (rhs = buf; *rhs != 0; ++rhs) {
chr = *rhs;
if ((chr >= 'A') && (chr <= 'Z'))
chr = (chr - 'A') + 'a';
if ((chr >= 'a') && (chr <= 'z')) {
*lhs++ = chr;
char_histogram[chr] += 1;
continue;
}
*lhs = 0;
if (lhs > tmp)
count_string(tmp);
lhs = tmp;
}
if (lhs > tmp) {
*lhs = 0;
count_string(tmp);
}
}
void
count_string(char *str)
{
int idx;
int match;
match = -1;
for (idx = 0; idx < word_count; ++idx) {
if (strcmp(words[idx],str) == 0) {
match = idx;
break;
}
}
if (match < 0) {
match = word_count++;
strcpy(words[match],str);
}
word_histogram[match] += 1;
}
Using separate arrays is ugly. Using a struct might be better:
#define STRMAX 100 // max string length
#define WORDMAX 1000 // max number of strings
struct word {
int word_hist; // histogram value
char word_string[STRMAX]; // string value
};
int word_count; // number of elements in wordlist
struct word wordlist[WORDMAX]; // list of known words
My assignment is to allow the user to enter any input and print the occurrences of letters and words, we also have to print out how many one letter, two, three, etc.. letter words are in the string. I have gotten the letter part of my code to work and have revised my word function several times, but still can't get the word finding function to even begin to work. The compiler says the char pointer word is undeclared when it clearly is. Do I have to allocate memory to it and the array of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void findLetters(char *ptr);
void findWords(char *point);
int main()
{
char textStream[100]; //up to 98 characters and '\n\ and '\0'
printf("enter some text\n");
if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
{
findLetters(textStream);
findWords(textStream);
}
else
{
printf("fgets failed\n");
}
return 0;
}
void findLetters(char *ptr) //find occurences of all letters
{
int upLetters[26];
int loLetters[26];
int i;
int index;
for (i = 0; i < 26; i++) // set array to all zero
{
upLetters[i] = 0;
loLetters[i] = 0;
}
i = 0;
while (ptr[i] != '\0') // loop until prt[i] is '\0'
{
if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
{
index = ptr[i] - 'A';// subtract 'A' to get index 0-25
upLetters[index]++;//add one
}
if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
{
index = ptr[i] - 'a';//subtract 'a' to get index 0-25
loLetters[index]++;//add one
}
i++;//next character in ptr
}
printf("Number of Occurrences of Uppercase letters\n\n");
for (i = 0; i < 26; i++)//loop through 0 to 25
{
if (upLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
// add 'A' to go from an index back to a character
}
}
printf("\n");
printf("Number of Occurrences of Lowercase letters\n\n");
for (i = 0; i < 26; i++)
{
if (loLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
// add 'a' to go back from an index to a character
}
}
printf("\n");
}
void findWords(char *point)
{
int i = 0;
int k = 0;
int count = 0;
int j = 0;
int space = 0;
int c = 0;
char *word[50];
char word1[50][100];
char* delim = "{ } . , ( ) ";
for (i = 0; i< sizeof(point); i++) //counts # of spaces between words
{
if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
{
space++;
}
}
char *words = strtok(point, delim);
for(;k <= space; k++)
{
word[k] = malloc((words+1) * sizeof(*words));
}
while (words != NULL)
{
printf("%s\n",words);
strcpy(words, word[j++]);
words = strtok(NULL, delim);
}
free(words);
}
This is because you are trying to multiply the pointer position+1 by the size of pointer. Change line 100 to:
word[k] = malloc(strlen(words)+1);
This will solve your compilation problem, but you still have other problems.
You've got a couple of problems in function findWords:
Here,
for (i = 0; i< sizeof(point); i++)
sizeof(point) is the same as sizeof(char*) as point in a char* in the function fincdWords. This is not what you want. Use
for (i = 0; i < strlen(point); i++)
instead. But this might be slow as strlen will be called in every iteration. So I suggest
int len = strlen(point);
for (i = 0; i < len; i++)
The same problem lies here too:
word[k] = malloc((words+1) * sizeof(*words));
It doesn't makes sense what you are trying with (words+1). I think you want
word[k] = malloc( strlen(words) + 1 ); //+1 for the NUL-terminator
You got the arguments all mixed up:
strcpy(words, word[j++]);
You actually wanted
strcpy(word[j++], words);
which copies the contents of words to word[j++].
Here:
free(words);
words was never allocated memory. Since you free a pointer that has not been returned by malloc/calloc/realloc, the code exhibits Undefined Behavior. So, remove that.
You allocated memory for each element of word. So free it using
for(k = 0; k <= space; k++)
{
free(word[k]);
}
Your calculation of the pointer position+1 is wrong. If you want the compilation problem will go away change line 100 to:
word[k] = malloc( 1 + strlen(words));
I got some help earlier fixing up one of the functions I am using in this program, but now I'm at a loss of logic.
I have three purposes and two functions in this program. The first purpose is to print a sentence that the user inputs backwards. The second purpose is to check if any of the words are anagrams with another in the sentence. The third purpose is to check if any one word is a palindrome.
I successfully completed the first purpose. I can print sentences backwards. But now I am unsure of how I should implement my functions to check whether or not any words are anagrams or palindromes.
Here's the code;
/*
* Ch8pp14.c
*
* Created on: Oct 12, 2013
* Author: RivalDog
* Purpose: Reverse a sentence, check for anagrams and palindromes
*/
#include <stdio.h>
#include <ctype.h> //Included ctype for tolower / toupper functions
#define bool int
#define true 1
#define false 0
//Write boolean function that will check if a word is an anagram
bool check_anagram(char a[], char b[])
{
int first[26] = {0}, second[26] = {0}, c = 0;
// Convert arrays into all lower case letters
while(a[c])
{
a[c] = (tolower(a[c]));
c++;
}
c = 0;
while(b[c])
{
b[c] = (tolower(b[c]));
c++;
}
c = 0;
while (a[c] != 0)
{
first[a[c]-'a']++;
c++;
}
c = 0;
while (b[c] != 0)
{
second[b[c]-'a']++;
c++;
}
for (c = 0; c < 26; c++)
{
if (first[c] != second[c])
return false;
}
return true;
}
//Write boolean function that will check if a word is a palindrome
bool palindrome(char a[])
{
int c=0, j, k;
//Convert array into all lower case letters
while (a[c])
{
a[c] = (tolower(a[c]));
c++;
}
c = 0;
j = 0;
k = strlen(a) - 1;
while (j < k)
{
if(a[j++] != a[k--])
return false;
}
return true;
}
int main(void)
{
int i = 0, j = 0, k = 0;
char a[80], terminator;
//Prompt user to enter sentence, store it into an array
printf("Enter a sentence: ");
j = getchar();
while (i < 80)
{
a[i] = j;
++i;
j = getchar();
if (j == '!' || j == '.' || j == '?')
{
terminator = j;
break;
}
else if(j == '\n')
{
break;
}
}
while(a[k])
{
a[k] = (tolower(a[k]));
k++;
}
k = 0;
while(k < i)
{
printf("%c", a[k]);
k++;
}
printf("%c\n", terminator);
//Search backwards through the loop for the start of the last word
//print the word, and then repeat that process for the rest of the words
for(j = i; j >= 0; j--)
{
while(j > -1)
{
if (j == 0)
{
for(k=j;k<i;k++)
{
printf("%c", a[k]);
}
printf("%c", terminator);
break;
}
else if (a[j] != ' ')
--j;
else if (a[j] == ' ')
{
for(k=j+1;k<i;k++)
{
printf("%c", a[k]);
}
printf(" ");
break;
}
}
i = j;
}
//Check if the words are anagrams using previously written function
for( i = 0; i < 80; i++)
{
if (a[i] == ' ')
{
}
}
//Check if the words are palindromes using previously written function
return 0;
}
I was thinking that perhaps I could again search through the array for the words by checking if the element is a space, and if it is, store from where the search started to the space's index-1 in a new array, repeat that process for the entire sentence, and then call my functions on all of the arrays. The issue I am seeing is that I can't really predict how many words a user will input in a sentence... So how can I set up my code to where I can check for anagrams/palindromes?
Thank you everyone!
~RivalDog
Would be better,if you first optimize your code and make it readable by adding comments.Then you can divide the problem in smaller parts like
1.How to count words in a string?
2.How to check whether two words are anagrams?
3.How to check whether a word is palindrome or not?
And these smaller programs you could easily get by Googling. Then your job will be just to integrate these answers. Hope this helps.
To check anagram, no need to calculate number of words and comparing them one by one or whatever you are thinking.
Look at this code. In this code function read_word() is reading word/phrase input using an int array of 26 elements to keep track of how many times each letter has been seen instead of storing the letters itself. Another function equal_array() is to check whether both array a and b (in main) are equal (anagram) or not and return a Boolean value as a result.
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
void read_word(int counts[26]);
bool equal_array(int counts1[26],int counts2[26]);
int main()
{
int a[26] = {0}, b[26] = {0};
printf("Enter first word/phrase: ");
read_word(a);
printf("Enter second word/phrase: ");
read_word(b);
bool flag = equal_array(a,b);
printf("The words/phrase are ");
if(flag)
printf("anagrams");
else
printf("not anagrams");
return 0;
}
void read_word(int counts[26])
{
int ch;
while((ch = getchar()) != '\n')
if(ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z')
counts[toupper(ch) - 'A']++;
}
bool equal_array(int counts1[26],int counts2[26])
{
int i = 0;
while(i < 26)
{
if(counts1[i] == counts2[i])
i++;
else
break;
}
return i == 26 ? true : false;
}