My code for finding the frequency of digits in a character array in C is not giving the desired output.
int main() {
int n;
scanf("%d",&n);
char str[n];
int f[10],i,j,ns;
gets(str);
for(i=0;i<10;i++)
{
f[i]=0;
for(j=0;j<strlen(str);j++)
{
ns=str[j]-'0';
if(i==ns)
f[i]+=1;
}
}
for(i=0;i<10;i++)
printf("%d ",f[i]);
return 0;
}
If I enter the string
1wjhue73b38409598
I am getting the output of frequency of (0-9):
1 0 0 2 1 1 0 1 2 2
Instead of frequency 1 for '1'.
Where am I going wrong?
This is what happens when you mix scanf with gets / fgets.
The call to scanf is expecting a number. When you enter "1wjhue73b38409598" as the input it reads the 1 at the start of the string and stops reading when it sees the "w". So n gets set to 1.
Then gets immediately reads the remaining characters (i.e. "wjhue73b38409598") without prompting. Since the 1 is not part of this string, it doesn't get counted.
There's another problem however. Because n is set to 1, str can only hold 1 character. So the gets call writes past the end of the buffer. This invokes undefined behavior. In this particular case, things appeared to otherwise work, however a minor change to the code could change how undefined behavior manifests.
Even if you were to enter a proper value for n such as 50, the scanf call leaves a newline in the buffer. The subsequent call to gets then immediately reads the newline and stops, so all of the counters are 0.
Use a fixed size buffer instead and use fgets, which can be given a maximum size to read, to read the string:
char str[50];
fgets(str, sizeof(str), stdin);
Related
The runs stored by N batsmen of a cricket team is passed as the input to the program. The program must print the name of the batsman who scored the highest runs.
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
int run[n],maxIndex=0;
char name[n][100];
for(int i=0;i<n;i++)
scanf("%[^,],%d",name[i],&run[i]);
for(int i=0;i<n;i++){
if(run[i]>run[maxIndex])
maxIndex=i;
}
printf("%s",name[maxIndex]);
return 0;
}
Input:
5
BatsmanA,45
BatsmanB,42
BatsmanC,12
BatsmanD,9
BatsmanE,78
Output:
BatsmanE
The issue is I'm getting a newline at first before the print statement. Like,
Output:
BatsmanE
The issue is I'm getting a newline at first before the print statement.
That is becasue %[^,] reads the prior line's left-over '\n' first.
scanf("%d",&n); reads the "5" and stores 5 into n. '\n' remains in stdin.
scanf("%[^,],%d",name[i],&run[i]); reads the "\nBatsmanA,45" and stores "\nBatsmanA" into name[0], then reads the ",", then reads "45" and stores 45 into run[0].
To read a line of user input, research fgets().
First of all, if you want to use scanf for string reading, you should make sure you can't get more characters than the string can handle. For that you can use width sub-specifier:
scanf("%99[^,],%d", name[i], &run[i]);
About the '\n' you got on the beginning of that string, that's because "%[^,]"
keeps it from the previous scanf, just add * that will read and discard that thing:
scanf("%*[\n]%99[^,],%d", name[i], &run[i]);
but as you can see, the format string becomes a lot less readable now...
Best thing would be if you just used "%99s" and rely on spaces instead of ',':
scanf("%99s%d", name[i], &run[i]);
now you just separate the values with space in the input and get the same result:
Input:
5
BatsmanA 45
BatsmanB 42
BatsmanC 12
BatsmanD 9
BatsmanE 78
but at that point I'd personally prefer just separating the format into 2 "scanfs":
scanf("%99s", name[i]);
scanf("%d", &run[i]);
And again, you will get the same result
This is sample of my program:
#include <stdio.h>
void sum();
int main()
{
char choice[4];
do
{
sum();
printf("\nDo You want to restart the program: yes or no:\n");
fgets(choice, 4, stdin); //error point
} while (choice[0] == 'y' || choice[0] == 'Y');
printf("\nThanking You");
return 0;
}
void sum()
{
int a = 3, b = 4;
printf("sum of two number is %d", a + b);
}
In this program, only in the 1st iteration of while does it ask for input in choice and, on the next iteration the program auto terminates by taking any value in choice.
Following is the result after execution of code:
sum of two number is 7
Do You want to restart the program: yes or no:
yes
sum of two number is 7
Do You want to restart the program: yes or no:
Thanking You
[Program finished]
I am unable to understand that it takes input in choice while I haven't used scanf() (which leaves the new line character in the buffer). It may be it takes input from buffer that may be whitespace or other characters, but I don't know from where it came?
Your program is leaving a newline in the input buffer after the first prompt because there's not enough room for it in the buffer.
On the first call to fgets you give the string "yes" followed by a newline. The buffer has size 4 and you pass that size to fgets so it reads at most that many characters-1 to account for the terminating null byte. So there is still a newline left in the buffer.
That newline gets read immediately the next time fgets is called.
You should enlarge your buffer to handle more characters.
Your choice array is not large enough to hold all the input from the first loop. The second argument to the fgets function (4) tells it to read at most 3 characters (and it then appends a nul-terminator to the input). So, it leaves the newline character in the input stream, and that is read in the second loop (by itself).
Just increase your choice array size and the input limit to 5 (or more):
#include <stdio.h>
void sum();
int main()
{
char choice[5]; // Increase space for newline and nul
do {
sum();
printf("\nDo You want to restart the program: yes or no:\n");
fgets(choice, 5, stdin); // Inputs 'y', 'e', 's' and newline (4 chars) and appends a nul.
} while (choice[0] == 'y' || choice[0] == 'Y');
printf("\nThanking You");
return 0;
}
void sum()
{
int a = 3, b = 4;
printf("sum of two number is %d", a + b);
}
From fgets - cppreference (bolding mine):
Reads at most count - 1 characters from the given file stream and
stores them in the character array pointed to by str. Parsing stops if
a newline character is found, in which case str will contain that
newline character, or if end-of-file occurs. If bytes are read and no
errors occur, writes a null character at the position immediately
after the last character written to str.
I am trying to create a C code that takes an input string of maximum length 10 from the user and assigns each letter into different elements of an array of size 10. However, I cannot understand my results. My code:
char word1[9];
int i;
printf("Enter your first word: \n");
scanf("%s", &word1);
printf("your word is %s \n",word1);
for(i = 0; i < 10; i++)
printf("%d ", word1[i]);
system("pause");
When I input the word "hello", the for loop shows me that each of the first 6 elements of the array word1 has been assigned the ASCII number equivalents of the letters h,e,l,l,o. Ideally, the last 4 elements should be 0 however they are not. output is [104 101 108 108 111 0 0 0 1 0]. Where is that 1 coming from? Similarly if I input "hi" the output is [104 105 0 24 -3 127 0 0 1 0]. What are these random numbers after 104 and 105 and why are they not 0?
For context, I am trying to build a simple code that would check if two input words are anagrams. My thought process is that 2 ASCII equivalent arrays would be produced which I can then sort in ascending order so I can compare each corresponding element.
Additional question: Why when I increase the 10 from i<10 in the for loop does output show more than 10 values? Since the array has 10 elements shouldn't it always show only 10 outputs?
Sorry if this is trivial, I am very new to C.
You're getting the ASCII numbers because of this line:
printf("%d ", word1[i]);
You need to replace %d with %c – so the problem fixes. Still, there's a problem. When asking for input from the user, scanf() must be used to accept the limited number of characters:
char word[11]; // to get 10 chars + '\0' (null-terminator)
scanf("%10s", word);
You don't need to introduce an ampersand in the scanf() and use the (max length - 1) explicitly between % and s.
Lastly, iterating till the whole length of the array is a very bad idea. Considering iterating till the detection of a null-terminator. In short, replace:
for(i = 0; i < 10; i++)
with
while (word[i] != '\0')
Your biggest problems are:
incorrect use of scanf() adding & before word1 invoking undefined behavior. word1 is already a pointer due to array/pointer conversion. See: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
You fail to use the field-width modifier to protect your array bounds allowing the user to exploit your code by entering more characters than your array can hold. Using scanf() with the "%s" conversion specifier without a field-width modifier to limit the input to the number of characters your array can hold is no safer than using gets(). See: Why gets() is so dangerous it should never be used!
You loop beyond the end of your array with your for loop if your array contains less than 9 character (which should be 11 to hold a 10 character string.) word1 (if properly read), is a nul-terminated string. You simply loop until you find the end-of-string (e.g. the '\0' character whose ASCII value is just plain-old 0). You don't loop over the max number of chars your array can hold -- they may hold values that are not set.
To correct the issues above, and more, you could do:
#include <stdio.h>
#define MAXCHR 10 /* if you need a constant, #define one (or more) */
int main (void) {
char word1[MAXCHR + 1]; /* to treat chars as a string, you need +1 for \0 */
int i;
fputs ("Enter your first word: ", stdout); /* no conversion, printf not needed */
if (scanf ("%10s", word1) != 1) { /* validate EVERY input, protect */
puts ("EOF encountered on read of word1"); /* array bounds with field-width */
return 0;
}
printf ("your word is: %s\n", word1); /* output word1 */
for (i = 0; word1[i]; i++) /* word1 is a string, loop to end */
printf ("%c ", word1[i]);
putchar ('\n'); /* tidy up with newline */
#if defined (_WIN32) || defined (_WIN64)
system("pause"); /* non-portable, only for windows */
#endif
}
(note: printf() is only needed for output if your output string contains a conversion, otherwise, puts(), or fputs() if end-of-line control is needed, are fine)
Example Use/Output
Basic input within the number of characters:
$ ./bin/word1
Enter your first word: bananas
your word is: bananas
b a n a n a s
Input of exactly the number of characters allowed:
$ ./bin/word1
Enter your first word: 1234567890
your word is: 1234567890
1 2 3 4 5 6 7 8 9 0
Input of twice as many characters as the array can hold as a string:
$ ./bin/word1
Enter your first word: 12345678901234567890
your word is: 1234567890
1 2 3 4 5 6 7 8 9 0
(note: no matter how many characters you attempt to input, only 10 plus the nul-terminating character will be stored. Be aware that any characters not read, remain in stdin unread -- just waiting to bite you on your next input. That is why input should be taken with fgets() or POSIX getline() so that the entire line of input is consumed. Regardless of which input function you use, you cannot use it correctly unless you check the return to determine if the input succeeded or failed.)
Look things over and let me know if you have further questions.
The reason is, arrays are not initiated by a default value (like 0) in C, so when you input a string which does not cover whole the array, rest of elements don't have any default value and they have some garbage value from the memory.
You can initiate the word array like this:
for(i = 0; i < 10; i++)
word1[i] = 0;
PS: char word1[9]; creates 9 cells not 10. Also be aware that you should consider another cell for the \0 char which will indicate the string has ended. So in total you need 11 cells.
I'm using this code to catch user's standart input and then print it back with number of characters saved.
#include <stdio.h>
int main()
{
char input[100];
int inputSize;
while (scanf("%99s%n", input, &inputSize) != EOF)
{
printf("INPUT: %s, SIZE %d\n", input, inputSize);
}
return 0;
}
And these are results:
> hello
INPUT: hello, SIZE: 5
> hello
INPUT: hello, SIZE: 6
Why is the size not the same?
How can I get exact size every time?
And finally:
The char variable is array, right?
Then why this does NOT happen?
> AAAAAAAAAA
INPUT: AAAAAAAAAA, SIZE: 10
> BBBBB
INPUT: BBBBBAAAAA, SIZE: 6
What happened to saved 10x A? They are deleted on new input? Why?
Thanks in advance
Why is the size not the same?
User input is "hello\nhello\n".
The first scanf("%99s%n", input, &inputSize) scans "hello\n". Sees '\n' as trailing white-space, puts it back into stdin. So 5 char are scanned, saving 5 char in input. Then it appends a '\0' to input.
The next scanf("%99s%n", input, &inputSize) scans "\nhello\n". "%s" scans but does not save leading white-space. Sees 2nd '\n' as trailing white-space, puts it back into stdin. So 6 char are scanned, saving 5 char in input. Then it appends a '\0' to input.
How can I get exact size every time?
Enter the same thing - type Enter before the first "Hello". "%s" ends its scanning before the end-of-line. The real solution it to not use scanf(). If user input is line orientated, use fgets() or getline() and then parse as needed.
... The char variable is array, right? Then why this does NOT happen?
It is happening. input is an array 10 of char. This is certainly a new run of the program and so n of 10 matches the char save in input as there was no preceding '\n' to discard.
> AAAAAAAAAA
INPUT: AAAAAAAAAA, SIZE: 10
What happened to saved 10x A? They are deleted on new input? Why?
The A saved in input are overwritten with the Bs.
It remains a mystery why the last output is "BBBBBAAAAA" and not "BBBBB". Given "SIZE: 6", suspect OP transcription error.
scanf("%99s%n", input, &inputSize)
Will write the x char read on the x first bytes of "input".
You can try
scanf("%99s%n", &input[TotalAmountOfBytesRead], &inputSize)
Then, it will give to scanf the adress of the first byte not already written.
Beware of buffer overflow though (Hint: malloc()/realloc()).
I am trying to populate 2 arrays using fgets. For some reason, the last fget of the last loop iteration never executes.
For example, if num_inputs = 5, only 9 lines are read (instead of 10).
int num_imputs;
//read the number of inputs
scanf("%d", &num_imputs);
char secret_arr[num_imputs][8];//stores all the secrets
char encoded_message_arr[num_imputs][256];//stores all the encoded messages
for(int i = 0; i < num_imputs ; i++){
fgets (secret_arr[i],8, stdin);
fgets (encoded_message_arr[i],256, stdin);
}
This code works perfectly find if I hardcode num_inputs instead of reading it using scanf(). Can someone explain why this is happening?
You are missing a newline in scanf (assuming your input has an ENTER for the num_inputs data entry). Results in the first fgets actually storing an empty string as it stops when it sees the newline that was part of the num_inputs data entry.
Should be:
scanf("%d\n", &num_imputs);