How can I read a varying amount of integer input in C? - c

I will be getting three lines of input. The first line will give me 2 integers and the third line will give me 1 integer. But the second line can give me any number of integers ranging between 1 to 100. For example, the input could be:
2 1
5 6 1 9 2
10
or could be:
10 4
5 6
9
I can read the second line of integer input into an integer array for a fixed number of integers, but cannot do so for a varying number of integers. I suppose, in this case, I should use a while loop which will break when scanf() finds a newline. How do I code that?

Read the line into a buffer (#John Coleman) using using fgets() or getline().
Parse the string looking for whitespace that may contain a '\n', exit loop if found. Then call strtol() or sscanf() to read the 1 number. Check that function's return value for errors too.
Repeat above steps.

I am actually a newbie in programming and am unaware of most of the functions. The only string functions I know of are strlen() and strcmp(). And my i\o function knowledge is limited to printf() and scanf().
Anyhow, I solved my problem in this way:
int a[101];
int i, num;
char ch;
for (i = 0; i < 101; i++)
a[i] = 0;
while (1)
{
scanf("%d%c", &num, &ch);
i = num;
a[i] = num;
if (ch == '\n')
break;
}
This works!
The value of num had to be equal to the value i because my program needed it.

Related

Assigning the letters of a string into an array

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.

Why is the first value of my char array 10?

I'm new to programming but I wanted to make a program that gets as input a number, (length) and then stores a series of a's and b's of said length. Finally it should output the numbers as the ascii numbers. (so 97 and 98)
I thought I should malloc a char array of the size length and then do a for-loop over it and print everything as an integer.
The problem is however that I get a value 10 as the value of the first letter.
Thanks a lot for any help!
int main()
{
int length;
scanf("%d", &length);
char *matrix = malloc((length + 1 ) * sizeof(char));
for (int i = 0; i < length; i++)
{
scanf("%c", &matrix[i]);
}
for (int i = 0; i < length; i++)
{
printf("\n%d", matrix[i]);
}
return 0;
}
When inputting 3 on the first line and aba on the next line, I get 10 97 98.
However I expected it to be 97 98 97. Why do I get a value of 10 in the first place of the array?
Use
scanf(" %c", &matrix[i]);
^^^^
instead of
scanf("%c", &matrix[i]);
^^
When the format starts with a blank all white spaces are skipped.
From the C Standard (7.21.6.2 The fscanf function)
5 A directive composed of white-space character(s) is executed by
reading input up to the first non-white-space character (which remains
unread), or until no more characters can be read.
10 is the ASCII code of the (white space) new line character '\n' that was present in the input buffer after you entered the length of the array.
The first scanf() with the format string %d leaves a newline in the input buffer.
What happens here, is that your terminal collects input one full line at a time, passing it to the program, and then the scanf() only reads the digits from the buffer, leaving the newline character there for the next scanf() to see. The same would happen if you entered 10 abc: the space, abc and the newline would be left there.
This mismatch is not something people usually expect, and it's one of the things that makes scanf() annoying. I would suggest using fgets() instead to first read a full line, matching what the terminal gives, and then parse the number from it with sscanf() or strtol() (or atoi()).
This cleans up the issue at the point where the first line is read, instead of passing it on to the next input function to handle. Otherwise all your input functions are tied together, if the next input would be for a whole line with possible white space, you'd need to know if you expect to clear a pre-existing newline or not. (You could also replace the later scanf("%c") with getchar(), not that that matters with buffering though.)
That said, the scanf("%c")/getchar() loop may still see newlines if you enter lines that don't have as many characters as the loop expects, so if you don't want to see them at all, filter them out.
So, something like this:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int length;
char linebuf[100];
fgets(linebuf, 100, stdin);
length = strtol(linebuf, NULL, 10);
char *matrix = malloc(length + 1);
for (int i = 0; i < length; i++)
{
matrix[i] = getchar();
}
for (int i = 0; i < length; i++)
{
printf("\n%d", matrix[i]);
}
printf("\n");
return 0;
}
(The obvious downside of fgets() is that you have to decide on a maximum length for the input line, allocate a buffer and call another function in addition to it.)

to find frequency of digits(0-9) in a string

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);

Use scanf() to input to multiple variables?

I am wondering if it is possible to use scanf() to read one line (actually just 1 digit from 0 to 9) and input the data as both a char variable and an integer variable so the user only has to enter the number once. Any help would be greatly appreciated. I am writing in C, using nano as my text editor, gcc as my compiler, and Ubuntu 12.04 as my OS. I also have access to Windoze, if necessary. Thanks in advance!
You can read the integer in with scanf and then convert it to a character by adding '0'. Since digits are always represented sequentially, this will convert any single digit integer to its corresponding character value.
int i;
do {
printf("Enter an integer: ");
scanf("%d", &i);
if (i < 0 || i > 9)
printf("Please try again (number must be between 0 and 9)\n");
} while (i < 0 || i > 9);
char c = i + '0';
// now i has the number and c has the character
printf("%d %c\n", i, c); // outputs, e.g., 4 4
You don't want to take the variable in twice, you want to use a cast or type conversion.
Read the variable as a character, check if it is between '0' and '9' (character zero and character nine), and if it is, cast it to an int like so: int x = (int)(my_character-'0');.
If you want to be very safe or need more-than-one-character strings, see the atoi function.

What are the mechanics of scanf() in C

So I started learning C today, and as an exercise I was told to write a program that asks the user for numbers until they type a 0, then adds the even ones and the odd ones together. Here it is:
#include <stdio.h>;
int main() {
int esum = 0, osum = 0;
int n, mod;
puts("Please enter some numbers, 0 to terminate:");
scanf("%d", &n);
while (n != 0) {
mod = n % 2;
switch(mod) {
case 0:
esum += n;
break;
case 1:
osum += n;
}
scanf("%d", &n);
}
printf("The sum of evens:%d,\t The sum of odds:%d", esum, osum);
return 0;
}
My question concerns the mechanics of the scanf() function. It seems that when you enter several numbers at once separated by spaces (eg. 1 22 34 2 8), the scanf() function somehow remembers each distinct numbers in the line, and steps through the while loop for each one respectively. Why/how does this happen?
Example interaction within command prompt:
-> Please enter some numbers, 0 to terminate:
42 8 77 23 11 (enter)
0 (enter)
-> The sum of evens:50, The sum of odds:111
I'm running the program through the command prompt; it's compiled for win32 platforms with Visual Studio.
Notice that you're calling scanf() each time you go through the loop; each time you call scanf() with the arguments "%d" and &n, it reads a single integer into the variable n and advances to the position immediately after that integer in the input stream.
You can sort of think of the input stream as a "string" of sorts. Suppose I typed "25 16 0"; after scanf() reads the first integer, the input stream becomes "16 0"; if you call scanf() again, you'll read the integer 16 and the input string becomes "0".
It happens because scanf function gets its input from the standard input stream. It is called stream for a reason: everything you enter is put into that stream, and scanf reads that stream. Whatever you put into the input stream will stay there until something like scanf gets it out of there.
In other words, scanf doesn't really "remember" anything. It is the input stream that does all the "remembering".

Resources