Your program should read a word from the input and then sort the letters of the word alphabetically (by their ASCII codes). Next, your program should iterate through the letters of the word and compare each letter with the one following it. If these equal each other, you increase a counter by 1, making sure to then skip ahead far enough so that letters that occur more than twice are not counted again. You may assume that the word you read from the input has no more than 50 letters, and that the word is all lowercase.
I wrote a program and get these results:
apple gives me 1
erroneousnesses gives 5,
but taylor should give me 0 however it gives 1.
How can I make yup, taylor and other words with non-repeating alphabets give me 0?
Here is my code:
#include <stdio.h>
int main(void) {
char string[51];
int c = 0, count[26] = { 0 }, x = 0;
scanf("%s", string);
while (string[c] != '\0') {
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
c++;
}
printf("%d", count[x]);
return 0;
}
There are multiple problems in your code:
scanf("%s", string); may cause a buffer overflow if the input is longer than 50 bytes.
Furthermore, you do not test the return value to check for invalid or missing input.
counting the number of occurrences of each letter is an alternative approach to the stated problem, and OK if you are only graded based on the program output. However be aware that the program does not implement what the assignment explicitly mandates and the value you output is incorrect anyway.
the output value should be the number of counts that are >= 2. Printing the value of count[x] is meaningless.
Here is a modified version:
#include <stdio.h>
int main() {
char str[51];
int dup = 0;
int count['z' - 'a' + 1] = { 0 };
if (scanf(" %50[a-z]", str) == 1) {
for (int i = 0; str[i] != '\0'; i++) {
if (++count[str[i] - 'a'] == 2)
dup++;
}
printf("%d\n", dup);
}
return 0;
}
to answer your specifc question
printf("%d", count[x]);
prints the count of number of appearances of the last letter.
taylor => 1 (r occurs 1 time)
apple => 1 (e once)
erroneousnesses => 5 (s count)
you need to loop over count array adding all counts > 1
Related
I'm trying to find the frequency of digit into given string,which contain digit and letters. When i run the same program i get different result, look like random output. where is the problem ?
int main() {
char num[1001];
int digit[10];
int j,i;
int count;
scanf("%s",num);
for(i=48;i<=57;i++)
{
count = 0;
for(j=0; num[j] != EOF;j++)
{
if(num[j] == i)
{
count++;
}
}
printf("%d ",count);
}
return 0;
}
You have missed an & in the line with scanf before num. Correct code should be:
scanf("%s", &num);
When you are scanning for the value, you need to provide the address of the variable. That is you let your program know where to put the value. &num points to the address of the variable num. But if you just write scanf("%s",num) you are providing value of the num variable, which you don't care at all. You'll be overwriting that value anyway.
At the end of the string, computer puts a null character \0 whose ASCII value is 0, to denote that this is the end of the string. Kind of like a '.' but for a computer. So you check until you find the null character in the for loop like: num[j] != '\0' [Not EOF]
I don't see any issue here, it seems output is not readable properly
so try printing correctly like
printf("%c=>%d ",i, count);
so that you can read what number how many times. if you find wrong frequency,
post the input for which you are getting wrong output.
It seems like you're trying to compare a char element with an integer type.
for example:
char num[7] = {"ABC123");
if (num[3] == 1)
{
printf("True\n");
}
else
{
printf("False\n");
}
return 0;
// This will return False, even though the element at index 3 is "1".
I've ran your code, and it seems like the output is the same given the same input.
Edit:
We wanted to compare a two digit number to a char data type - which is essentially a character - a one digit number/case.
When we take a number N and modulo by 10, we get the last digit, example:
48 % 10 = 8
To get the first digit we simply divide by 10, and take the quotient, example:
48 / 10 = 4 (remainder 8).
With this knowledge, we can compare the n-th char with first digit, and the n+1-th char with the last one (given that we only compare two digits, we'll stop at n+1-th).
Tip: a number char can be turned into a int using char = char - '0'
char num[1001];
int digit[10];
int j,i;
int count;
scanf("%s",num);
for(i=48;i<=57;i++)
{
count = 0;
for(j=0; num[j] != EOF;j++)
{
if(num[j] - '0' == i / 10 && num[j+1] - '0' == i % 10)
{
printf("%c", num[j] - '0');
count++;
}
}
printf("%d: %d \n",i, count);
}
printf("\n");
return 0;
// This code will print the digits and the frequency in a new line:
48: n times
49: n times
.
.
.
57: n times
I got this exercise that I haven't been able to solve, the point is to create a program where you type in a text, then the program analyzes each word of the text and counts the vowels of each word, then the program returns in screen the number of words that have 3 or more different vowels, and by different I mean, it doesn't matter if the word has 3 "a", it only count as one (the word has the vowels "a", it doesn't matter how many times), so for example, the word "above" has 3 vowels, the word "been" has 1 vowels, the word "example" has 2 vowels. The vowels can be upper case or lower case, it doesn't matter, and here is the tricky part: It cannot contain any pointers or functions made by us.
what i did was asking the user to enter word by word so the program analyze each word, and then at the end returns the number of words that contain 3 or more vowels, but I feel like there must be an easier way where the user can type a complete paragraph or text, then the program analyzes each word and return the number of words that have 3 or more different vowels.
Anyway, my code is as follows, any suggestions would be appreciated:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
main() {
int vowels, text, words, c, total=0,a=0,e=0,i=0,o=0,u=0;
printf ("How many words does your text has? ");
scanf("%d",&words);
for(c=1;c<=words;c++){
printf("Type your word %d, after that press enter, then press 'control' and 'z' at the same time, and then press enter again: \n", c);
while (EOF != (text=getchar())){
if (text == 'a' || text == 'A'){
a++;
if (a >=2){
a = 1;
}
}
if (text == 'e' || text == 'E'){
e++;
if (e >=2){
e = 1;
}
}
if (text == 'i' || text == 'I'){
i++;
if (i >=2){
i = 1;
}
}
if (text == 'o' || text == 'O'){
o++;
if (o >=2){
o = 1;
}
}
if (text == 'u' || text == 'U'){
u++;
if (u >=2){
u = 1;
}
}
}
vowels = a+e+i+o+u;
if(vowels >=3){
total = total +1;
}
a=0,e=0,i=0,o=0,u=0;
vowels = 0;
}
printf("\n\nThe total of words with 3 or more vowels is: %d", total);
printf("\n");
total=0;
return 0;
}
In order to read and analyze a single word, or a paragraph words to determine the number of words that contain at least three different vowels (of any case), this is one of the rare times when reading input with scanf (using the '%s' format specifier) actually is a reasonable choice.
Recall the '%s' format specifier will read characters up to the first whitespace. That gives you a simple way to read a word at a time from stdin. To end input, the user simply need to generate an EOF by entering ctrl+d (or ctrl+z on windows). This satisfies your paragraph requirement.
For parsing, you can take advantage of converting each character to lower case to simplify checking for vowels. Using a frequency array of 5 elements provides a simple way to track the number of different vowels found in each word. Then a final test to see if the number of vowels found equals the required number is all you need before incrementing your total word count for words with three different vowels.
A simple implementation would be something similar to:
#include <stdio.h>
enum { NREQD = 3, NVOWEL = 5, MAXC = 128 }; /* declare constants */
int main (void) {
char word[MAXC] = ""; /* word buffer */
size_t wordcnt = 0; /* words with 3 different vowels */
printf ("enter a word(s) below, [ctrl+d on blank line to end]\n");
for (;;) {
int vowels[NVOWEL] = {0}, /* frequency array */
vowelcnt = 0, /* vowels per-word */
rtn; /* scanf return */
if ((rtn = scanf ("%127s", word)) == EOF) /* chk EOF */
break;
for (int i = 0; word[i]; i++) { /* loop over each char */
if ('A' <= word[i] && word[i] <= 'Z') /* check upper */
word[i] ^= 'a' - 'A'; /* convert to lower */
switch (word[i]) { /* check if vowel */
case 'a': vowels[0] = 1; break;
case 'e': vowels[1] = 1; break;
case 'i': vowels[2] = 1; break;
case 'o': vowels[3] = 1; break;
case 'u': vowels[4] = 1; break;
}
}
for (int i = 0; i < NVOWEL; i++) /* loop over array */
if (vowels[i]) /* check index */
vowelcnt++; /* increment vowelcnt */
if (vowelcnt >= NREQD) /* do we have at least 3 vowels? */
wordcnt++; /* increment wordcnt */
}
printf ("\nThere are %zu words with %d different vowels.\n",
wordcnt, NREQD);
}
Example Use/Output
$ ./bin/vowelcnt
enter a word(s) below, [ctrl+d on blank line to end]
Everyone Understands That The Dictionary Doesn't Track
Words That Contain Vowels Like It Does Etimology.
There are 4 words with 3 different vowels.
Look things over and let me know if you have further questions.
You can use fgets to read a whole line. I don't know how you define a
paragraph though, do you mean just a long text or a collection of lines? You can
copy & paste multiple lines in the console and if you loop using fgets, then
you get all the lines. But allowing the user to enter multiple lines at once,
it's more tricky, because you should know how many lines the user will input.
That's why I'd say focus on reading the text line by line.
Your solution reads characters by characters and you are ignoring non-vowels.
That's OK, but you are not detecting words like you should do. The for loop
makes no sense, because in the first iteration you enter in a while loop that
is only going to leave when there are no more characters to read from stdin.
So the next iteration of the for loop will not enter the while loop and you
won't be reading anything any more.
You are also repeating too much code, I know you assignment says not to use your
own functions, but this can be improved with a simple look up table by creating
an array of chars using the characters as an index for the array. I'll explain
that in the code.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
int main(void)
{
char line[1024];
// initializing look ups with 0
int lookup_vowels[1 << CHAR_BIT] = { 0 };
// using 'a', 'e' as index for the lookup table
// if you want to know if a character is a vowel,
// lookup_vowels[character] will be 1 if character is
// a vowel, 0 otherwise
lookup_vowels['a'] = lookup_vowels['e'] = lookup_vowels['i'] =
lookup_vowels['o'] = lookup_vowels['u'] = 1;
// for parsing word with strtok
const char *delim = " \t\r\n";
int num_of_words = 0;
printf("Enter some text, to end input press ENTER and then CTRL+D\n");
while(1)
{
if(fgets(line, sizeof line, stdin) == NULL)
break;
// parsing words
char *word = strtok(line, delim);
if(word == NULL)
continue; // the line has only delimiters, ignore it
do {
// will be access with the same principle as the lookup
// table, the character is the index
int present[1 << CHAR_BIT] = { 0 };
size_t len = strlen(word);
for(size_t i = 0; i < len; ++i)
{
// I'll explain later the meaning
int c = tolower(word[i]);
if(lookup_vowels[c])
present[c] = 1; // set the present for a vowel to 1
}
int count = present['a'] + present['e'] + present['i'] + present['o']
+ present['u'];
if(count > 2)
{
printf("'%s' has more than three distinct vowels\n", word);
num_of_words++;
}
} while((word = strtok(NULL, delim)));
}
printf("The number of word with three or more distinct vowels: %d\n", num_of_words);
return 0;
}
So let me quickly explain some of the technique I use here:
The lookup table is an array of size 256 because a char is 8-bit1
value and can have 256 different values (range [0,255]). The idea is that this
array is initialized with 0 overall (int lookup_vowels[1<<CHAR_BIT] = { 0 };) and then
I set to 1 only in 5 places: at the position of the vowels using their
ASCII value as index.
So instead of doing the repeating task if checking
// where c is a char
if(c == 'a' || c == 'A')
a=1;
}
for all vowels, I just can do
int idx = tolower(c);
if(lookup_vowels[idx])
{
// c is a vowel
}
The present variable function similar to the lookup table, here I use the
ASCII code of a vowel as index and set it to 1 if a vowel is present in word.
After scanning all characters in word, I sum all values stored in present.
If the value is greater than 2, then the word has at least 3 or more distinct
vowels and the counter variable is increased.
The function strtok is used to split the line using a defined set of
delimiters, in this case the empty character, tab, carriage return and line
feed. To start parsing the line, strtok must be called with the source string
as the first argument and the delimiters as the second argument. All other
subsequent calls must pass NULL as the first argument. The function returns a
pointer to the next word and returns NULL when no more words have been found.
When a word is found, it calculates the number of distinct vowels and checks if
this number is greater than 2.
fotenotes
1CHAR_BIT defined in limits.h returns the number of bits of byte.
Usually a byte is 8-bit wide, so I could have written 256 instead. But there are
"exotic" architectures where a byte is not 8-bit long, so by doing 1<<CHAR_BIT
I'm getting the correct dimension.
The goal for this program is for it to count the number of instances that two consecutive letters are identical and print this number for every test case. The input can be up to 1,000,000 characters long (thus the size of the char array to hold the input). The website which has the coding challenge on it, however, states that the program times out at a 2s run-time. My question is, how can this program be optimized to process the data faster? Does the issue stem from the large char array?
Also: I get a compiler warning "assignment makes integer from pointer without a cast" for the line str[1000000] = "" What does this mean and how should it be handled instead?
Input:
number of test cases
strings of capital A's and B's
Output:
Number of duplicate letters next to each other for each test case, each on a new line.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, c, a, results[10] = {};
char str[1000000];
scanf("%d", &n);
for (c = 0; c < n; c++) {
str[1000000] = "";
scanf("%s", str);
for (a = 0; a < (strlen(str)-1); a++) {
if (str[a] == str[a+1]) { results[c] += 1; }
}
}
for (c = 0; c < n; c++) {
printf("%d\n", results[c]);
}
return 0;
}
You don't need the line
str[1000000] = "";
scanf() adds a null terminator when it parses the input and writes it to str. This line is also writing beyond the end of the array, since the last element of the array is str[999999].
The reason you're getting the warning is because the type of str[10000000] is char, but the type of a string literal is char*.
To speed up the program, take the call to strlen() out of the loop.
size_t len = strlen(str)-1;
for (a = 0; a < len; a++) {
...
}
str[1000000] = "";
This does not do what you think it does and you're overflowing the buffer which results in undefined behaviour. An indexer's range is from 0 - sizeof(str) EXCLUSIVE. So you either add one to the
1000000 when initializing or use 999999 to access it instead. To get rid of the compiler warning and produce cleaner code use:
str[1000000] = '\0';
Or
str[999999] = '\0';
Depending on what you did to fix it.
As to optimizing, you should look at the assembly and go from there.
count the number of instances that two consecutive letters are identical and print this number for every test case
For efficiency, code needs a new approach as suggeted by #john bollinger & #molbdnilo
void ReportPairs(const char *str, size_t n) {
int previous = EOF;
unsigned long repeat = 0;
for (size_t i=0; i<n; i++) {
int ch = (unsigned char) str[i];
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
}
char *testcase1 = "test1122a33";
ReportPairs(testcase1, strlen(testcase1));
or directly from input and "each test case, each on a new line."
int ReportPairs2(FILE *inf) {
int previous = EOF;
unsigned long repeat = 0;
int ch;
for ((ch = fgetc(inf)) != '\n') {
if (ch == EOF) return ch;
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
return ch;
}
while (ReportPairs2(stdin) != EOF);
Unclear how OP wants to count "AAAA" as 2 or 3. This code counts it as 3.
One way to dramatically improve the run-time for your code is to limit the number of times you read from stdin. (basically process input in bigger chunks). You can do this a number of way, but probably one of the most efficient would be with fread. Even reading in 8-byte chunks can provide a big improvement over reading a character at a time. One example of such an implementation considering capital letters [A-Z] only would be:
#include <stdio.h>
#define RSIZE 8
int main (void) {
char qword[RSIZE] = {0};
char last = 0;
size_t i = 0;
size_t nchr = 0;
size_t dcount = 0;
/* read up to 8-bytes at a time */
while ((nchr = fread (qword, sizeof *qword, RSIZE, stdin)))
{ /* compare each byte to byte before */
for (i = 1; i < nchr && qword[i] && qword[i] != '\n'; i++)
{ /* if not [A-Z] continue, else compare */
if (qword[i-1] < 'A' || qword[i-1] > 'Z') continue;
if (i == 1 && last == qword[i-1]) dcount++;
if (qword[i-1] == qword[i]) dcount++;
}
last = qword[i-1]; /* save last for comparison w/next */
}
printf ("\n sequential duplicated characters [A-Z] : %zu\n\n",
dcount);
return 0;
}
Output/Time with 868789 chars
$ time ./bin/find_dup_digits <dat/d434839c-d-input-d4340a6.txt
sequential duplicated characters [A-Z] : 434893
real 0m0.024s
user 0m0.017s
sys 0m0.005s
Note: the string was actually a string of '0's and '1's run with a modified test of if (qword[i-1] < '0' || qword[i-1] > '9') continue; rather than the test for [A-Z]...continue, but your results with 'A's and 'B's should be virtually identical. 1000000 would still be significantly under .1 seconds. You can play with the RSIZE value to see if there is any benefit to reading a larger (suggested 'power of 2') size of characters. (note: this counts AAAA as 3) Hope this helps.
Suppose if I pass a string like "I am Programmer".
If a letter has occurred one time it should print "I has occurred 1 time", or else if a letter appears twice in the string it should print "a has occurred 2 times", "m has occurred 3 times" and so on for every letter in the string. I searched it and found in some website. Is there any way we could rewrite the code because I didn't understand the code.
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
printf("Enter a string\n");
gets(string);
while (string[c] != '\0')
{
/** Considering characters from 'a' to 'z' only
and ignoring others */
if (string[c] >= 'a' && string[c] <= 'z')
count[string[c]-'a']++;
c++;
}
for (c = 0; c < 26; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (count[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'a',count[c]);
}
return 0;
}
Ok here is the rewrite, the original code is better but this one might be easier to understand:
#include <stdio.h>
#include <string.h>
int main()
{
char cur_char;
char string[100];
int index = 0, count[255] = {0};
printf("Enter a string\n");
gets(string);
while (string[index] != '\0')
{
char cur_char = string[index];
// cur_char is a char but it acts as the index of the array like
// if it was an unsigned short
count[cur_char] = count[cur_char] + 1;
index++;
}
for (index = 0; index < 255; index++)
{
if (count[index] != 0)
printf("%c occurs %d times in the entered string.\n", index, count[index]);
}
return 0;
}
A variable type char can be considered as an integer (it's how they are stored in the memory anyway) so you can write:
int test = 'a';
printf("%i", test);
And it will print you 97. Also letters from a to z are represented by continuous intergers, that means 'b' = 98. So taht also means 'b' - 'a' = 1
In your solution, they create an array of 26 integers to count the occurence of each letters betwin 'a' and 'z' (note that they ignore all others including A-Z by doing this)
They decided that in the array count, index 0 is here to count occurences of a, 1 for b .... 25 for z, that explains this:
count[string[c]-'a']++;
If string[c] is a b then string[c]-'a' = 1 so we have our index for count array and increase the amount of occurence of b.
So all you need to understand this code is that you can manipulate a char like an int basically, you should make a quick search about what is ASCII code as well.
If you still need a rewrite of this code to understand, tell me.
My job is to make a password validator with:
No spaces allowed
1 Symbol
2 Digits
Minimum 6 characters
Maximum 10 characters
Just the above restrictions, so far I have done alone the 1, 2, 4, 5 and I can't solve the third requirement about 2 digits. I can only do so with 1 digit so how do I to do it with 2? I think regex doesn't work like C++ and C# in C. Here is my code:
#include <stdio.h>
#include <string.h>
int main(){
char pass[11];
int stop;
printf("Give password:\n");
scanf(" %[^\n]s",pass);
do{
if(strlen(pass)<6){
stop=0;
printf("Too short password.");
}
else if(strlen(pass)>10){
stop=0;
printf("Too long password.");
}
else if(strchr(pass, ' ')){
stop=0;
printf("No spaces.");
}
else if((strchr(pass, '$')==NULL && strchr(pass, '#')==NULL && strchr(pass, '#')==NULL && strchr(pass, '!')==NULL && strchr(pass, '%')==NULL && strchr(pass, '*')==NULL)){
stop=0;
printf("Must give at least one of $, #, #, !, %% or *.");
}
else{
stop=1;
printf("Your password is %s\n", pass);
}
}while(stop=0);
return 0;}
That's not really a regex. What you have there is basically a small program that checks its input for different conditions. So, in the same manner, to make sure you have 2 digits, let's create a function that counts the number of digits. Keep in mind that in ASCII the digits 0 to 9 are in a continuous block (this is very important, as you will see).
int countDigits(char *input) {
int digitCount = 0;
for (int i = 0; i < strlen(input); i++) // for every character
if (input[i] >= '0' && input[i] <= '9') // if it is a digit
digitCount++;
return digitCount;
}
I've written this function this way to introduce show some character manipulation techniques. It would have been better if the condition would be:
if (isdigit(input[i]))
for portability reasons. Note that the function isdigit is defined in the ctype.h header. There is still some room for improvement:
int countDigits(char *input) {
int digitCount = 0;
int noOfCharacters = strlen(input); // avoid strlen() being called
// for every iteration
for (int i = 0; i < strlen(input); i++) // for every character
digitCount += isdigit(input[i]);
return digitCount;
}
Now you need just to take this function and check if it returns 2 for the input you've got.
No reason for small-ish buffer. Test #5 cannot have been done properly with pass[11]
// char pass[11];
char pass[100];
Dangerous to use unlimited length input. Change to
scanf(" %99[^\n]",pass);
Count the digits
int cnt = 0;
for (i=0; pass[i]; i++) {
if (pass[i] >= '0' && pass[i] <= '9') cnt++;
}
if (cnt != 2) BadPsss();
RegEx search [^0-9] the input string and replace globally with nothing.
Verify the remaining string to be two characters long.