I have a text file with n lines of m length (it doesn't matter in the long term ). In every line, there is a sequence like this:
1 + 2 + 5 - 3 =
I'm using fscanf function to catch all numbers and operators and calculate it and when '=' operator found it prints into a different file. I'm using a loop . My question is how does C recognizes a number and operator? I know the operator is a type of %c and the number is of type %d, but how my program does work properly and why it doesn't take them for example 5 as a character :
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *InFile;
FILE *OutFile;
int number=0;
int result=0;
char operator;
int foundEqualsOp=0;
InFile = fopen("dane.txt","r");
OutFile = fopen("wynik.txt","w");
while(fscanf(InFile,"%d",&result)!=EOF)
{
number = 0;
foundEqualsOp = 0;
while(!foundEqualsOP){
fscanf(InFile,"%c",&operator);
if(operator == '='){
foundEqualsOp = 1;
fprintf(OutFile,"%d\n",result);
}
else if(operator == '-'){
fscanf(InFile,"%d",&number);
result = result-number;
}
else if (operator == '+'){
fscanf(InFile,"%d",&number);
result = result + number;
}
}
}
fclose(InFile);
fclose(OutFile);
return 0;
}
Let's assume your input file contains the following as in your example:
1 + 2 + 5 - 3 =
The outer scanf reads with %d. This picks up 1 as the integer value 1 and puts it in result.
Now the inner scanf runs with %c. It reads the space after 1 so none of the if blocks are entered and the inner loop runs again. The inner scanf again reads with %c and reads the + character. This causes the if (operator == '+') block to be entered where a call to scanf uses %d. This format specifier skips over the space after the + and reads 2 as the integer value 2 and adds it to result.
The above happens again reading the space after 2, the + that follows, and the space and 5 that follows. And again for the following space, -, space, and 3.
After that, the scanf in the inner loop reads the space after 3 and does nothing, then on the next iteration it reads the = after which it prints the result and sets the flag to exit the inner loop.,
Related
I'm working on one of my C assignments. I have a little problem with taking unknown numbers of input. This is my code:
while ((a = getchar()) != EOF){
ungetc(a,stdin);
scanf(" %c %d %d %d",&a,&b,&c,&d);
arr1[3*i] = b;
arr1[3*i+1] = c;
arr1[3*i+2] = d;
i++;
(I have done all the declaretions befor this)
What i'm trying to do this here is I take inputs and stroe them in three arrays. My input is:
X 10 18 3
r -3 2 1
Y 0 -2 -1
After i write these in terminal, i have to push the buttons ctrl+d twice. And then when i try to check arr1, its like {10, 18, 3, -3 ,2 ,1 ,0 ,-2 ,-1 ,0 ,-2 ,-1} The last input is duplicated and i don't know the reason..
!!! The main thing is that I don't that how many inputs i will take. !!!
Thank you for your help.
After each scanf, the file pointer is left on the trailing newline of input. After the last line of input is scanned and values are assigned to b, c, and d, the getchar in the while loop reads the final newline. Then scanf reads no values so b, c, and d are unchanged. The values that were left from the previous loop are assigned to the array, i is incremented, and then getchar returns EOF and the loop breaks. Always check the value returned by scanf. In other words, this problem evaporates if you use the usual idiom
while(scanf(" %c%d%d%d",&a,&b,&c,&d) == 4) { ...
Also, in this case, the error would have been noticed more readily if you weren't copying the data unnecessarily to the temporary variables b, c, and d, but just did:
while( scanf(" %c%d%d%d", &a, arr + 3*i, arr + 3*i +1, arr + 3*i + 2) == 4
which would be written a lot more cleanly as:
int *base = arr;
while( scanf(" %c%d%d%d", &a, base, base + 1, base + 2) == 4 ) {
base += 3; ...
Note that in all of these, a must really be declared as a char, but to assign a from getchar requires that a be an int, and that should be a clue that trying to use getchar/ungetc is a mistake.
To summarize, on all but the first line of input, getchar is reading '\n', ungetc pushes that newline back to the buffer, and then scanf skips over it because of the leading whitespace in the format string.
regarding:
while ((a = getchar()) != EOF){
ungetc(a,stdin);
scanf(" %c %d %d %d",&a,&b,&c,&d);
arr1[3*i] = b;
arr1[3*i+1] = c;
arr1[3*i+2] = d;
i++;
Suggest using the returned value from scanf(), similar to:
int i = 0;
while ( scanf(" %c %d %d %d",&a,&b,&c,&d) == 4 )
{
arr1[3*i] = b;
arr1[3*i+1] = c;
arr1[3*i+2] = d;
i++;
}
I created function that takes in a char pointer. I first get the string value from fgets, the input i'm entering is "rwx". When I enter that value, the strlen of it says it's length is 2 and when I look at the first index of the char array, it returns rw instead of r. May I ask where abouts am I going wrong for iterating through the string?
What I've tried:
int main()
{
char access[3];
while (ValidateAccess(access))
{
printf("Please enter your access\n");
fgets (access, 3, stdin);
}
return 0;
}
int ValidateAccess(char * access)
{
int length = strlen(access);
int r = 0,w = 0,x = 0,i;
printf("this is the length %d\n", length);
if (length == 0)
return 1;
for(i = 0; i < length; i++)
{
printf("this is the character: %s", &access[i]);
if (strcmp(&access[i], "r") == 0)
r++;
else if (strcmp(&access[i], "w") == 0)
w++;
else if (strcmp(&access[i], "x") == 0)
x++;
}
if (r <=1 && w <= 1 && x <= 1 )
return 0;
else
return 1;
}
when the program is ran this is the output
"this is the length 0"
Please enter your access
rwx
this is the length 2
this is the character: rw
man fgets is a very useful reading. Let me quote: "fgets() reads in at most one less than size characters from stream..."
The strings in C are expected to be terminated with \0 (zero byte). When you define access as an array of 3 elements, it has a room for a string of length 2 -- two characters plus terminating zero byte. When you call fgets saying that you have the space for 3 bytes, it reads two characters, puts them in the first two bytes, and puts terminating zero in the third byte.
Define access a having 4 bytes, and pass 4 to fgets.
Additionally, you are printing string not a char, so it prints everything to the terminating zero byte (that's where rw you see comes from). If you want to print a single character, use %c in format string, not %s (and you should pass a character, not a pointer then).
Try the following program and make sure you understand the output.
#include <stdio.h>
int main() {
char *foo = "barbaz";
printf("%c\n", foo[2]);
printf("%s\n", foo + 2);
}
I am doing homework to school. Task is to make program in C that can do some simple things with matrixes like *, -, +.
My program is reading matrixes and save them to int array. When the matrix input ended, I scanf to char to know what operation iam going to do with the matrixes. Operation are stores in char array. (on input can be up to 100 matrixes so 99 operations in between). If user writes * everything is okay, BUT when user writes '-' or '+' it stores '/n'. I was googling and debuging but still dont know why this happens. Any suggustions are welcome.
User input looks like this: First line is size of matrix.
2 3
76 98 -31
30 30 32
-
2 3
89 25 38
1 -32 -38
int* readMatrix(int width, int height, char arrayOperation[], int numberOfMatrix, int*err)
{
int sizeOfMatrix = ((height*width) + 3), i = 0;
char operation = 'n';
int *arrayMatrix = malloc(sizeOfMatrix* sizeof(int));
arrayMatrix[0] = width;
arrayMatrix[1] = height;
for (i = 2; i <= sizeOfMatrix; i++)
{
if (i == sizeOfMatrix)
{
if (scanf_s("%c", &operation) != EOF)
{
if (operation == '*' || operation == '-' || operation == '+')
{
arrayOperation[numberOfMatrix] = operation;
}
else
{
*err = 100;
}
}
else
{
arrayOperation[numberOfMatrix] = 'n';
break;
}
}
else if (scanf_s("%d", &(arrayMatrix[i])) == 1)
{
*err = 0;
}
}
return arrayMatrix;
}
In case of * the var operation==*,but in -,+ operation==/n. I call this function in loop, output array is stored in array of int**.
scanf("%c" reads the very next character without skipping any whitespace, so it will store whatever is after the last thing read -- usually a newline. If you want to skip whitespace, add a space to the format:
scanf(" %c", &operation)
this will skip any whitespace and store the next non-whitespace character.
You don't need this with %d as all of the conversion patterns except %c and %[ skip whitespace.
I was discusing this particular problem with my lecturer.
I understand this: when scanf reading the number it jumps over whitespace and /n.
So reading "32/n - " results in reading everything. When reading "32/n * " it stops at "*" because its not sign of any number. So its behave little stupid.
This can solve using fgets() function and read it by char.
I am a newbie to C and I was looking over some questions where I pondered upon a question where we need to scan in values using the users input. Example
1 2 3 45 6 7. So Automatically we scan these values into a 2D array.
One thing that troubles me is what If the user inputs
1 2 3 2 3 Josh, how can we ignore Josh and only scan in the values into the array.
I looked at using getchar and use a flag variable but I am unable to figure out the conundrum of differentiating between the integer and character.
/* This is something that I tried */
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
int b;
int A[10];
while (((a = getchar()) != '\n') && (b = 0)) {
if (!(a >= "A" && a <= "Z")) {
scanf("%d", A[b]);
}
b++;
}
}
}
I think one good method for achieving what you want is using scanf with the format "%s", which will read everything as a string, effectively splitting the input according to white spaces. From the manual:
s
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long
enough to hold the input sequence and the terminating null
byte ('\0'), which is added automatically. The input string
stops at white space or at the maximum field width, whichever
occurs first.
To convert the string to integer, you can use atoi. From the manual:
The atoi() function converts the initial portion of the string
pointed to by nptr to int.
So, if it converts the initial portion of the string into an integer, we can use that to identify what is a number and what's not.
You can build a simple "word detector" for atoi.
Using the function isalpha from ctype.h you can do:
int isword(char *buffer)
{
return isalpha(*buffer);
}
And rewriting your reading program you have:
#include <stdio.h>
#include <ctype.h>
int isword(char *buffer)
{
return isalpha(*buffer);
}
int main(void)
{
char input[200];
int num;
while (1) {
scanf("%s", input);
if (!strcmp(input, "exit")) break;
if (isword(input)) continue;
num = atoi(input);
printf("Got number: %d\n", num);
}
return 0;
}
You should keep in mind that the name isword is fallacious. This function will not detect if buffer is, in fact, a word. It only tests the first character and if that is a character it returns true. The reason for this is the way our base function itoa works. It will return zero if the first character of the buffer is not a number - and that's not what you want. So, if you have other needs, you can use this function as a base.
That's also the reason I wrote a separate function and not:
if (!isalpha(input[0]))
num = itoa(input);
else
continue;
The output (with your input):
$ ./draft
1 2 3 2 3 Josh
Got number: 1
Got number: 2
Got number: 3
Got number: 2
Got number: 3
exit
$
About assigments and &&
while (((a = getchar()) != '\n') && (b = 0))
As I said in a comment, this loop will never work because you're making a logical conjunction(AND) with an assignment that will always return zero. That means the loop condition will always evaluate to false.
In C, assignments return the value assigned. So, if you do
int a = (b = 10);
a will have now hold the value 10. In the same way, when you do
something && (b = 0)
You're effectively doing
something && 0
Which will always evaluate to false (if you remember the AND truth table):
p q p && q
---------------
0 0 0
0 1 0
1 0 0
1 1 1
Your code is completely wrong. I suggest to delete it.
You could use scanf with %d to read in numbers. If it returns 0, there is some invalid input. So, scan and discard a %s and repeat this process:
int num = -1;
while(num != 0)
{
printf("Enter a number, enter 0 to exit:");
if(scanf("%d", &num) == 0) /* If scanf failed */
{
printf("Invalid input found!");
scanf("%*s"); /* Get rid of the invalid input (a word) */
}
}
This one has me scratching my head. One of these works, the other doesn’t always work, and I can’t tell why. The first batch of code works thus far, but the second batch will occasionally give a different, and incorrect, result from the first. For anyone wondering, this is part of a larger program to solve linear equations I want to make.
The only differences I can note between the two are that the firstEquation array sizes are different, and one of these arrays is declared globally, whereas the other is declared in the main function. I can't see why this would matter though.
// First File (THIS ONE WORKS)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int co1 = 0;
int i = 0;
char firstEquation[50];
main ()
{
printf("Enter the first equation.. e.g '3x + 2' \n");
fscanf(stdin, " %99[^\n]", firstEquation);
printf("the equation you just entered is: %s \n", firstEquation);
for (i = 0; i < sizeof(firstEquation)/sizeof(firstEquation[0]); i++)
{
if (firstEquation[i] == 'x' || firstEquation[i] == ' '
|| firstEquation[i] == '+'|| firstEquation[i] == '-')
{
printf("%d \n", i);
co1 = i;
}
}
printf("the yintercept of your equation starts at the %d th element in the array", co1+1);
}
Here is the second.
// Second File (THIS ONE STUFFS UP SOMETIMES)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int co1 = 0;
int i = 0;
main ()
{
char firstEquation[100];
printf("Enter the first equation.. e.g '3x + 2' \n");
fscanf(stdin, " %99[^\n]", firstEquation);
printf("the equation you just entered is: %s \n", firstEquation);
for (i = 0; i < sizeof(firstEquation)/sizeof(firstEquation[0]); i++)
{
if (firstEquation[i] == 'x' || firstEquation[i] == ' '
|| firstEquation[i] == '+'|| firstEquation[i] == '-')
{
printf("%d \n", i);
co1 = i;
}
}
printf("the yintercept of your equation starts at the %d th element in the array", co1+1);
}
This is what I input into both files as a way to test it: 65x + 554
//OUTPUT OF FIRST BATCH OF CODE (GIVES CORRECT RESULT)
Enter the first equation.. e.g '3x + 2'
65x + 554
the equation you just entered is: 65x + 554
2
3
4
5
the yintercept of your equation starts at the 6 th element in the array
And the second.
//OUTPUT OF SECOND BATCH OF CODE (GIVES INCORRECT RESULT)
Enter the first equation.. e.g '3x + 2'
65x + 554
the equation you just entered is: 65x + 554
2
3
4
5
10
the yintercept of your equation starts at the 11 th element in the array
Your second program invoke Undefined Behaviour as you try to access uninitialized locations.
In the first program,since firstEquation is global,it will be initialized to 0 while in the second program,it will remain uninitialized thus invoking UB when you access these locations.
You can fix this by initializing firstEquation in the second program to 0 by using
char firstEquation[100]={0};
or you can use memset to do it:
memset(firstEquation,0,sizeof(firstEquation));
sizeof(firstEquation)/sizeof(firstEquation[0])
in the for loop will probably return 50 for the first program and 100 for the second. Thus,the loop executes 50 times in the first program and 100 times in the second program.But you only need to loop the number of characters entered times.So,use
for (i = 0; i < strlen(firstEquation); i++)
Also,
fscanf(stdin, " %99[^\n]", firstEquation);
in the first program should be
fscanf(stdin, " %49[^\n]", firstEquation);
as firstEquation is 50 elements long and not 100. Use int main() instead of main() and add a return 0; just before closing main.