for loop accepts one extra value than the loop condition - c

I have written a program which accepts a value from a user and then iterates over that value in a for loop. in for loop I accept numbers to be stored in the array.
My problem is for loop accepts one extra value than specified by user.
int main()
{
int i = 0;
int a;
int no_of_boxcars = 0;
double array[10];
double boxcart_wt = 0;
//printf("Enter the no of wagons");
scanf_s("%d", &no_of_boxcars); // no of boxcars
for (i = 0; i<=no_of_boxcars;++i)
{
printf("%d \t", i);
scanf_s("%lf ", &boxcart_wt); //weight in boxcar
array[i] = boxcart_wt;
}
}
if the user enters 3 it should accept 3 values if
for (i = 0; i<no_of_boxcars;++i)
{
//but here accepts 4 values
}
if the user enters 3 it should accept 4 values if
for (i = 0; i<=no_of_boxcars;++i)
{
//and here accepts 5 values
}

Indexes in C go from 0..n-1. In your for loop you go from 0..n and that is one too many. Change
for (i = 0; i<=no_of_boxcars;++i)
to
for (i = 0; i<no_of_boxcars;++i)

A space in the scanf format matches any white-space, and any number of consecutive white-space.
The problem with a trailing space is that then scanf must continue reading until it reads something that isn't a white-space, otherwise it doesn't know when the spaces ends.
That leads to the problem that you need to give some extra non white-space input.
For all but two formats ("%c" and "%[") the scanf function automatically reads and discards leading white-space. So it's usually not needed to include spaces in a format string. Except perhaps for those two formats that doesn't skip white-space.
Read e.g. this scanf (and family) reference for more details.

Related

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

How to set the limit of the for loop to work until end of line/until specific string is reached

So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string. It continues scanning until the string = is reached. Each number value is stored to an array of double and each string to an array of char.
Problem is that the input line can be arbitrarily long and I don't know how to make it
The program should work as a basic calculator which reads one double float, then one operator as a string, and performs operation. If another number follows, then perform the operation with this number. If the equal sign = is reached, the program outputs the result.
int main() {
double res;
double in[10];
char *op[10][5];
int arrCheck[10];
for(int i=0; i<=5; i++) {
scanf("%lf %s ", &in[i], op[i]);
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
This is the main section of my program so far. I managed to get it working and storing the data correctly. Although it always works only on predefined limit (i<=5, for instance). Is it legal to write condition like:
for(i = 0; i<'\n'; i++), or i<=?
I would expect it to continue scanning and storing the data until it reaches the equal sign =.
Try this:
for(int i = 0; (i <= 5) && (strcmp(op[i], "=") != 0); i++) {
...
}
And on your question, it is not legal to compare integers with strings. This is why string comparing functions exist.
You can also break from for loop like this:
int main()
{
double res;
double in[10];
char op[10][5];
int arrCheck[10];
for(int i=0;i<=5;i++){
scanf("%lf %s ", &in[i], op[i]);
if (strcmp(op[i], "=") == 0)
break;
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
Which is even better solution than the one posted previously.
Since you are reading with scanf and the "%s" conversion-specifier, you will consume leading whitespace before each operator stored in op[n]. There is no need to call strcmp, you can simply check the first character by dereferencing the pointer, e.g.
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
A short example omitting opCheck(op[i]) not included in your question, you could do something similar to:
#include <stdio.h>
int main (void) {
double in[10];
char op[10][5];
int i = 0, n;
while (i < 10) {
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
i++;
}
n = ++i;
puts ("\nequation: ");
for (i = 0; i < n; i++)
printf (" %g %s", in[i], op[i]);
puts (" res");
}
(note: the use of while (i < 10) rather than a for (i = 0; i < 10; i++). You do not want to increment i in case of a matching or input failure. You only increment i after validating both conversions succeeded)
Example Use/Output
$ ./bin/eqnread
5.1 + 6 - 2 + 25 * 4 =
equation:
5.1 + 6 - 2 + 25 * 4 = res
So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string.
If you care about lines specifically (which are ended by \n -or by \r on some operating systems), you cannot use scanf alone, because scanf deals with all kind of space characters (including the space, the tabulation, the newline, the formfeed characters) in the same way, so ignores the specificity of end of line characters (\n and/or \r).
So the good way is to read the entire line first with fgets (or getline(3) on Linux) and later to parse that line. Be careful about very long lines, they could happen.
How would you parse that read line is a different question: manual lexing and parsing, or sscanf, or strtok or strtod, etc... come to mind.
And you did not define what a string is for you. What about spaces inside it? What about input lines that are longer than what you expect (e.g. a line of a thousand characters)? The %s for scanf would stop at the first space.
Don't forget to read carefully the documentation of every used function. Learn How to debug small programs.
Be also aware that, practically speaking, in 2019 UTF-8 is used everywhere, and that may add complications to your scheme (and to what strings are in practice).
The program should work as a basic calculator
It seems that you then should care about operator precedence. Then, recursive descent parsing comes to mind.

using scanf("%d ") with a space after the %d

In my c class today I was troubling with the scanf() command, we were just learning pointers and we got a question asking us to get an array, and print it reversed without using the [] for anything but declaring the (int) array. Of course it seems like a piece of cake but not when you accidentally write:
scanf("%d ", arr + i);
Did you notice the space after the %d? Sure did take me a while to figure it out but for some reason that makes loops go crazy, and I wanted you guys to help me (and my teachers) to figure out why does that happen. Example:
#include <stdio.h>
#define LEN 10
void arrayInput(int * arr, unsigned int len);
void arrayReverseOutput(int * arr, unsigned int len);
int main(void)
{
int arr[LEN] = { 0 };
arrayInput(arr, LEN);
arrayReverseOutput(arr, LEN);
system("pause");
return 0;
}
void arrayInput(int * arr, unsigned int len)
{
unsigned int i = 0;
printf("Enter 10 numbers: ");
for (i = 0; i < len; i++)
{
//printf("i = %d \n", i); see what happens when you use this line
scanf("%d ", arr + i);
}
}
void arrayReverseOutput(int * arr, unsigned int len)
{
int i = 0;
printf("The numbers in reverse order: ");
for (i = --len; i >= 0; i--)
{
printf("%d ", *(arr + i));
}
}
I'm really curios to see what's going on with that scanf... it's as if it requires 2 inputs at the first time it runs but somehow still manages to put the inputs in their right position in the array...
Thanks for taking your time to read this <3
A space in the format string tells scanf() to match zero or more whitespace characters, until the match fails. Spaces (' '), newlines('\n'), carriage returns ('\r'), and tabs ('\t') are among the whitespace characters. When a space occurs at the end of a format string, scanf() will try to match whitespace characters from the input until no match is found. But, scanf() can only return when a match fails, or end of file is reached. Thus, in the case of a statement like:
scanf("%d ", arr + i);
the call to scanf() will appear to hang, greedily waiting for more input from the user. Whenever the Enter key is pressed, a newline is sent and matched by scanf(), which is still waiting for a failing match. Or end of file. You can escape such a loop by signalling end of file from the keyboard with Ctrl-D on Linux, or Ctrl-C on Windows.
It is almost always a mistake to terminate a scanf() format string with a space. A newline ('\n') is also a whitespace character, and has the same effect when placed at the end of a format string.
Note that spaces can be used effectively in scanf() format strings. For example:
int retval = scanf(" %c %c", &c1, &c2);
Here, if a previous IO operation has left a newline in the input stream (a not uncommon occurrence), the leading whitespace directs scanf() to read and ignore it. The second space in the format string tells scanf() to expect zero or more whitespace characters between the input characters to be converted. This allows the user to input the characters with an intervening space. Without the added whitespace, if a user entered a b\n, c2 would end up holding the value for a space character, and the b would be left behind in the input stream for the next IO operation to pick up. Also note that scanf() returns the number of successful conversions, allowing the program to check whether the input is as expected. If retval in the above line is anything other than 2, something has gone wrong.

Character Arrays using

I want to use scanf_s("%c\n", &arr[index]) to input once character at a time in a single line using for/while loop. I cannot figure out how to output the result. Below is the code.(I only want to use scanf statement. fgets way is easy.
printf("\nEnter the lowercase letters\n");
for (index = 0; index < size; index++)
{
scanf_s("%c\n", &arr[index]);
_getch();
}
printf("\nThanks");
for (index = 0; index < size; ++index)
{
printf("%c/n", arr[index]);
}
It takes the input but exits out after thanks statement. I cannot figure out why. Although I have used a different method that works. It's just a variation I was trying.
Change
scanf_s("%c\n", &arr[index]);
_getch();
To
scanf_s(" %c", &arr[index], 1);
When scanning a character(%c) or string(%s) using scanf_s, you must supply an additional value as a parameter which indicates the amount of characters to be scanned.
The space before %c discards all whitespace characters(newlines, spaces etc) including none before scanning a non-whitespace character.
Also, the printf in the loop has /n instead of \n for a newline.
This code would probably work better:
int nchars;
printf("\nEnter the lowercase letters\n");
for (index = 0; index < size; index++)
{
if (scanf_s("%c", &arr[index], 1) != 1)
break;
}
printf("\nThanks\n");
nchars = index; // Do not report on values that were not entered
for (index = 0; index < nchars; ++index)
{
printf("%c\n", arr[index]);
}
Note that when you use scanf_s() and the %c format (and %s and %[…]formats), it require a length as well as the pointer to the data storage location (two arguments for one conversion specification). This tells the function how much space there is available to store the value. Often, the length will not be 1; you'd use scanf_s("%s", buffer, sizeof(buffer)) to read a string.
It is a good idea to check the return value from scanf_s() every time you use it so that you know whether it worked or not.
You can add extra criteria for breaking the loop, such as if the code reads a newline.
I also noted some problems in the comments — the issues are fixed in the code above.
Why are you using _getch() when you're also scanning with scanf_s()? That's going to confuse the poor user who types abcd and sees only ac. The _getch() is eating the b and d.
Also, newline is \n not /n — the third printf() has that as a typo.
Using \n at the end of an interactive input format string is a bad idea; the user has to type something that's not a white space character after the input to get the scanf_s() to return.

Scanning in strings into a 2D array in C

I need to take an input of 20 words entered by the user put those into a 2D array and print that out
my current code is
char array2[20][20];
int i;
for(i=0;i<20;i++)
{
printf("enter a word\n");
scanf(" %[^\n]",array2[i]);
}
for(i=0;i<colsize2;i++)
{
printf("\n");
for(j=0;j<rowsize2;j++)
{
printf("%c",array2[i][j]);
}
}
(I have no idea what %[^\n] is but it works better than %c or %s)
there are no compiler errors and the program will run but when it prints the array after all the words have been entered all I get is complete garbage
like
aȪ(M▒awn-US▒ e▒(<▒▒t/▒▒▒(5h▒tr:▒(
qh▒tdle__000
HW5.exe▒`wauld▒(▒&Oe,▒*a▒+a▒▒
so much so that it takes a bit of scrolling to get back to the start of my program
I do have more in this program that's not in my question but I'm 99% sure it wouldn't mess with what I have here but if you do want to see the rest just ask
I literally just started programming so I don't know diddly squat about it yet so if you could keep that in mind when you answer also this is for a school assignment so it doesn't need to be perfect it just has to get the job done
thanks to whoever answers this I've been grappling with this for hours
The format string
" %[^\n]"
^ note the leading space
means that scanf will first read and discard any number of leading whitespace characters and then match any sequence of characters which does contain a newline. scanf can potentially overrun the buffer it save the string into if the input string is too large for the buffer invoking undefined behaviour. The %s format specifier means scanf skips the leading whitespace characters and reads the input string till it encounters a whitespace at which point it appends a terminating null byte to the buffer it writes into and then returns.
Therefore, what you need is
char array2[20][20];
int i;
for(i = 0; i < 20; i++)
scanf("%19s", array2[i]);
for(i = 0; i < 20; i++)
printf("%s\n", array2[i]);
Initialize your array to 0:
char array2[20][20] = { 0 } ;
And then print the string not every character:
for(i=0;i<20;i++)
{
printf("%s",array2[i]);
printf("\n");
}

Resources