C: first number in array becomes 0 for unknown reason - c

The Program:
This was supposed to be a simple reverse polish notation addition program, please ignore the EOF break thing, it's a placeholder.
Input is c, always one numeral number, it gets transfered to x where every next numeral c will be added to the number x, so for example when we input c as 1,2 and 3 x will be 123.
When we input 'e' it will mark the start of a new number, and x will be transfered to the stack[0] after the entire stack gets pushed back, and x will become 0. When inputing '+' addition happens, the last two numbers will be summed, x and the first number in the stack, or the first and second number in the stack, or the first number in the stack will duplicate itself.
The Problem:
The first number in the stack array will randomly become 0 and I cannot see where I made the error. The first number (stack[0]) only gets the value zero at the start, never again. At times when inputting '+' it will just get a value.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int stack[16];
int x;
int i;
char c;
//int c;
x=0;
for (i = 0; i < 16; i++)
{
stack[i]=0;
}
while(1)
{
//input character
scanf("%s", &c);
if (c == EOF) break;
//put x to stack
else if (c == 'e')
{for (i = 15; i >0; i--)
{
stack[i]=stack[i-1];
}
stack[0] = x;
x = 0;
}
//reverse polish addition
else if (c == '+')
//if x is 0 go immediately to the stack
{if (x == 0)
//if both x and the second number in array are 0 just duplicate the first number
if (stack[1] == 0)
stack[0] = stack[0] + stack[0];
//if only x is 0 add the first number on the second
else
{
stack[0]=stack[0]+stack[1];
//push back the array to fill the gap on the second number
for (i = 1; i <15; i++)
{
stack[i]=stack[i+1];
}
}
else
{
stack[0] = stack[0] + x;
x = 0;
}
}
else
{
x = x * 10 + ((int)c-0x30);
// putchar(c);
}
printf("X=%d\n",x);
//print stack
for (i = 0; i < 16; i++)
{
printf("%d \t",stack[i]);
}
printf("\n");
}
return 0;
}

Problem 1
scanf("%s", &c); causes undefined behavior. Use scanf(" %c", &c);.
Problem 2
c is never going to be equal to EOF by using scanf. Hence, the following line is useless.
if (c == EOF) break;
The following will take care of both problems.
// Use " %c" instead of "%c" to skip leading whitespace characters.
while ( scanf(" %c", &c) == 1 )
{
}

Related

Parse char from int input in C

I am trying to display a matrix by taking input from a user. Here, the input is a lower triangular matrix and the user may enter the 'x' character which has to be replaced with INT_MAX.
The below program is not working correctly as the output is not matching the expected one.
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_int() {
char input[30] = {0};
int number;
for (int i = 0; i < sizeof(input) - 1; i++){
char c = (char)getc(stdin);
if (c == 'x' || c == 'X')
return INT_MAX;
if (c < '0' || '9' < c){
if (i == 0) continue;
input[i] = 0;
return atoi(input);
}
input[i] = c;
}
input[29] = 0;
return atoi(input);
}
int main() {
int N = read_int();
int matrix[N][N];
memset(matrix, 0, N * N * sizeof(int));
for(int i = 0; i < N; ++i){
for(int j = 0; j <= i; ++j){
int distance = read_int();
matrix[i][j] = distance;
matrix[j][i] = distance;
}
}
printf("\n");
for(int i = 0; i < N; ++i){
for(int j = 0; j < N; ++j){
printf("%d\t", matrix[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}
For input:
3
x 2
x x 2
The Above program prints:
3 2147483647 2147483647
2147483647 32 2147483647
2147483647 2147483647 32
which is not expected
It should be
3 2147483647 2147483647
2147483647 2 2147483647
2147483647 2147483647 2
Update: The answers below, doesn't work for all case [except accepted one]
One such case is -
5
10
50 20
30 5 30
100 20 50 40
10 x x 10 50
it just keeps on taking input
Your logic for skipping whitespace is broken because when you eventually assign a character after skipping position 0, you will always be writing a "wanted" character at position i. That means anything already in position 0 remains.
In your case, it's undefined behavior because input[0] was originally filled with 3 on the first input where no whitespace was skipped, but in subsequent calls to your function it is uninitialized. You then go on to write a 2 into input[1] and thus by pure chance (your array from previous calls has not been overwritten on the stack and the stack is the same), you end up with the string "32" sitting in input.
What you need to do is have some way to count the actual required characters so that you write them into the array at the correct position. One naive approach would be:
int pos = 0;
for(...) {
// other logic...
// Actually write a character we want
input[pos++] = c;
}
Another way that is more like how integer input works is:
int c;
int pos = 0;
while(pos < sizeof(input) - 1 && (c = getc(stdin)) != EOF)
{
if (c == 'x' || c == 'X')
return INT_MAX;
else if (pos == 0 && isspace(c))
continue;
else if (!isdigit(c) && !(pos == 0 && (c == '-' || c == '+')))
break;
input[pos++] = c;
}
input[pos] = '\0';
return atoi(input);
I think the problem is this part of the loop:
if (c < '0' || '9' < c){
if (i == 0) continue;
input[i] = 0;
return atoi(input);
}
If you have entered 3enterx 2 as your input, then the 3 gets read successfully, and the the x gets returned as INT_MAX as intended, but in the next call to read_int, the next character in the input sequence is a space (i.e. c == ' '), and therefore it branches here. Since i == 0 at this point, the loop continues, which means i is incremented to 1, but this also means that input[0] is never changed. Most likely, input[0] contains the same value from the previous call to read_int (3), but in any case, it's undefined behaviour.
As a quick alternative, you can simply change this condition to:
if (c != ' ' && (c < '0' || '9' < c)){
This will mean input[0] will be set to a space character, which atoi will ignore.
An alternative solution could be to read in an entire line at once and tokenise the line.

How to add the numbers inside the scanf in loop?

Is there some way to add all the numbers in a scanf loop? The loop would stop if the input number is negative. The problem is that the negative must also be included in the sum.
Here, I managed to get the sum of all the positive scanf values repeated in the loop, but the negative number is still not included in the sum of all the numbers.
#include <stdio.h>
main()
{
int z, x;
printf("Enter a number:\n");
z = 0;
scanf("%d", &x);
do
{
z += x;
scanf(" %d", &x);
} while (x >= 0);
printf("Sum = %d ", z);
return 0;
}
A simple rearrangement of the order of statements in your do ... while loop (and removal of the preceding scanf call) will do the trick:
#include<stdio.h>
int main() // You are returning "0" so declare "int" as return type
{
int x = 0, z = 0; // Easier to initialize at the same time as declaration.
printf("Enter a number:\n");
// scanf ("%d", &x); // Don't read here - do that inside the loop.
do {
int test = scanf(" %d", &x); // Read as the FIRST statement in the loop ...
if (test != 1) { // If the "scanf" call failed, we need to clear the input stream ...
int c;
while ((c = getchar()) != '\n' && c != EOF)
; // Clear any offending input
if (c == EOF) break; // Probably can't recover from an EOF, so exit the while loop
}
else z += x; // ... then we can add X even if it's negative
} while (x >= 0); // But end the loop when it IS negative anyway
printf("Sum = %d ", z);
return 0;
}
Note that I have added a test variable to makes sure that the scanf operation succeeded. If the usser enters foo (as mentioned in the comment by William Pursell), then the input buffer is cleared, the addition is skipped, and the read will be attempted again.
I'm not sure if you want to handle an input stream that does not contain a negative value as an error, but you could simply do:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
int sum = 0, x, rv;
while( 1 == (rv = scanf ("%d", &x)) ){
sum += x;
if( x < 0 ){
break;
}
}
if( rv == 0 ){
fprintf(stderr, "Invalid input\n");
} else {
printf("Sum = %d\n", sum);
}
return rv == 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
I think the following behavior is reasonable:
$ echo 4 5 8 5| ./a.out
Sum = 22
$ echo 4 5 -1 5| ./a.out
Sum = 8
$ echo 4 5 not-an-integer 5| ./a.out
Invalid input
Inverting the lines inside the loop should do it:
int z, x;
int ch;
printf("Enter a number:\n");
z = 0;
do
{
if (scanf("%d", &x) == 1) // checking if parsing was successful
{
z += x; // if so, perform the sum
}
else
{
puts("Bad input"); // if user inputs a bad value
while((ch = getchar()) != '\n' && ch != EOF){} // you clear the input buffer
}
} while (x >= 0);
printf("Sum = %d ", z);
Note that I also removed the first scanf ouside the loop, which becomes unneeded.

Sequential input in C

Let's say I am creating a 3*4 matrix (or a 2D array of 12 elements). So I want user to enter values of elements one by one as a sequence, divided by either spaces/tabs or enter-key. Also, if a value in a sequence is bad (in my case, any non-integer values are bad), I want to ignore it and read next values until I have all 12 of them.
int fill(Matrix * mtx)
{
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0;
for (int i = 1; i <= mtx -> rows; i++)
{
for (int j = 1; j <= mtx -> cols; j++)
{
scanf(" %d", &temp);
setElement(mtx, i, j, temp);
}
}
return 0;
}
This is my most basic vision of the algorithm; I was wondering about the implementation of this "skip input if bad" condition.
Just started learning C btw, so any kind of advice is hugely appreciated!
You have to check the return value of scanf to be sure whether it scanned the integer input correctly or not. In case it fails due to some bad input - scanf can't take that as input and then you have to make sure that you clear the stdin so that the next calls of scanf don't fail. What you can do is, when scanf returns 0 - consume all characters (using getchar or similar) and do this until you get \n (Considering that user inputs the number each in a line). Illustration would be:
int n; //total number inputs to take.
n = 10;
int num, num_inputs = 0;
while( 1 )
{
while(scanf("%d", &num) != 1)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
if(c == EOF){ fprintf(stderr,"Error in input\n"); exit(1)}
}
num_inputs++; // one more int correctly input.
...
if( num_inputs == n )
break;
}
An alternative and better way would be to use strto* functions and then considering the return value of it to understand whether there is any error or not. Illustration would be: (Here we have shown just the case where there is single int input in each line - this can be extended to process multiple int inputs in a line).
char buf[MAXLEN];
int num_inputs = 0;
while(fgets(buf,MAXLEN,stdin)){
char *en;
errno = 0;
long n = strtol(line, &en, 10);
if (errno == 0 && *en== '\0' && n >= INT_MIN && n < INT_MAX)
{
// n is an correctly inputted int
num_inputs++;
}
}
Check the man page for strtol - there is a detailed listing of the erros one might get. Check it.
Check what scanf returns. If not 1 means entered value is not a digit in this case. So discard the data from the stream first before entering next data.
int fill(Matrix * mtx) {
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0, v;
for (int i = 1; i <= mtx->rows; i++) {
for (int j = 1; j <= mtx->cols; j++) {
v = scanf(" %d", &temp);
if (v != 1) { //if invalid input.
while ( (v = getchar()) != EOF && v != '\n' ); // discard invalid input.
j--; //don't forget to `j--` or else you will skip one position.
}
else { // if correct input.
setElement(mtx, i, j, temp);
}
}
}
return 0;
}

How to use arrays in C

I started my computer science course in college, and we're studying arrays. We have to write a program that reads a sequence of data, and prints it in reverse order. The char '%' declares the end of the sequence.
This is the program that I wrote:
#include <stdio.h>
int index;
int x;
int sequence[10];
int main () {
index = 0;
printf("Insert x: ");
scanf("%d", &x);
while (x != '%') {
sequence[index] = x;
printf("Insert x: ");
scanf("%d", &x);
index = index + 1;
}
while (index > 0) {
index = index - 1;
printf("%d", sequence[index]);
}
}
It reads the sequence via printf, saves each number in an array and when it receives a '%', it starts printing the sequence in reverse order, with the second while iteration.
The main problem is: when I try to run it, I get an error after that I enter '%', it starts printing back "Insert x: " lots of time, and then it crashes.
The second problem is: do I need to declare the size of the array?
Thank you.
This will scan an int. If it is successful the int will be added to the array until 10 ints have been added. If it fails to read an int, getchar will read a char and if the char is % the main loop will exit. If the char is not % it will try to read another int.
The size of the array needs to be declared.
#include<stdio.h>
#include<stdlib.h>
int main() {
int x = 0;
int index = 0;
int sequence[10] = {0};
int ch = 0;
printf ( "Input 10 integers (% to exit)\n");
while ( ch != '%') { // loop until ch is a %
if ( scanf ( "%d", &x) == 1) { // scanf read an int
sequence[index] = x;
index++;
if ( index >= 10) {
break; // too many inputs for array
}
}
else {
ch = getchar(); //scanf failed to read int. read a char and retry
}
}
while (index > 0) {
index = index - 1;
printf("%d\n", sequence[index]);
}
return 0;
}
As per your program. You are checking a character with integer value in while loop. Either you change your code like below or change condition in while loop as X!=? where ? is a ascii value of '%'. you can increase the array size but array value must be declared
#include <stdio.h>
int index;
char x;
char sequence[10]; //you can increase the array size here
int main () {
index = 0;
printf("Insert x: ");
scanf("%c", &x);
while (x != '%' && index <= 10) {
sequence[index] = x;
printf("Insert x: ");
scanf("%c", &x);
index = index + 1;
}
while (index > 0) {
index = index - 1;
printf("%c", sequence[index]);
}
return 0;
}
It crashes because inside the loop there are no condition to stop when you reach array max size.
At certain time : index = 10 -> sequence[10] doesn't exist because in c index must go from 0 to (array size - 1).
modify this
while (x != '%') {
to this
while ((x != '%') && (index <= 10)) {
For your question about array size declaration, the answer is YES, the size of an array must be always declared.
The reason is that scanf(3) returns the number of items read with that format string "%d", and as you don't check that number, it's getting one until you introduce the % (which is not a valid number), scanf(3) returns 0 (because it cannot convert that thing to an integer) and doesn't advance the file pointer from this point on, reading the % again and again. Each time, the last read value is getting assigned to one more cell of the array, overflowing it past of its limit (the last element is 9 but you allow to go up to element 10, one more), beggining to write other memory and probably crashing the program.
change the while loop to read so:
while ((scanf("%d", &x) == 1) && (index < 10)) { ...
Also, use < as the array is an array of 10 elements, numbered from 0 to 9.

Detecting combination of characters from input

My task is:
Write a program that reads input up to # and reports the number of times that the sequence ei occurs.
I wrote something that in most of the times works, but there are inputs when it dosent...
Like this input:(suppose to return 1)
sdlksldksdlskd
sdlsklsdks
sldklsdkeisldksdlk
#
number of combination is: 0
This is the code:
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
char userInput;
char wordChar[index];
printf("please enter your input:\n");
while ((userInput = getchar()) != '#')
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
}
}
printf("number of combination is: %d", combinationTimes);
return 0;
}
Can you please tell me what am I not getting 1 using this input?
in the book he said to test it with "Receive your eieio award" and it worked...but after i played with it a little i see that not always.
It really doesn't seem necessary to read the file into an array. You just need to keep track of how many times ei is found before you read a # or reach EOF:
#include <stdio.h>
int main(void)
{
int c;
int ei_count = 0;
while ((c = getchar()) != EOF && c != '#')
{
if (c == 'e')
{
int c1 = getchar();
if (c1 == 'i')
ei_count++;
else if (c1 != EOF)
ungetc(c1, stdin);
}
}
printf("ei appeared %d times\n", ei_count);
return(0);
}
Testing (the program is called ei and is built from ei.c):
$ ei < ei.c
ei appeared 0 times
$ sed 1d ei.c | ei
ei appeared 1 times
$ sed 's/#/#/' ei.c | ei
ei appeared 4 times
$
The first one stops at the #include line, the second stops at the # in the comparison, and the third reads the entire file. It also gives the correct output for the sample data.
Analysing the code
Your primary problem is that you do not allocate any space for the array. Change the dimension of the array from index to, say, 4096. That'll be big enough for your testing purposes (but really the program should pay attention to the array and not overflowing it β€” but then I don't think the array is necessary at all; see the code above).
The next primary problem is that despite its name, getchar() returns an int, not a char. It can return any valid character plus a distinct value, EOF. So it must return a value that's bigger than a char. (One of two things happens if you use char. If char is a signed type, some valid character β€” often ΓΏ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS β€” is also treated as EOF even though it is just a character. If char is an unsigned type, then no input matches EOF. Neither is correct behaviour.)
Fixing that is easy, but your code does not detect EOF. Always handle EOF; the data may be malformatted. That's a simple fix in the code.
A tertiary problem is that the printf() statement does not end with a newline; it should.
Your test condition here is odd:
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
It's odd to use one pre-increment and one post-increment, but that's just a consistency issue.
Worse, though, is what happens when the character i appears in the input and is not preceded by e. Consider the line #include <stdio.h>: you start with index as 1; that is an i, so you decrement index, but wordChar[0] is not an e, so you don't increment it again, but the end of the loop does, so the loop checks index 1 again, and keeps on going around the loop testing that the i is i and # is not e for a long time.
There's no reason to decrement and then increment index; just use:
if (wordChar[index-1] == 'e')
combinationTimes++;
With those fixed, your code behaves. You trouble was largely that you were using an array that was not big enough (being size 0), and you were overwriting quasi-random memory with the data you were reading.
#include <stdio.h>
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
int userInput;
char wordChar[4096];
printf("please enter your input:\n");
while ((userInput = getchar()) != '#' && userInput != EOF)
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
printf("total: %d\n", total);
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[index-1] == 'e')
combinationTimes++;
}
}
printf("number of combination is: %d\n", combinationTimes);
return 0;
}
Note that you could reasonably write the nested if as:
if (wordChar[index] == 'i' && wordChar[index-1] == 'e')
combinationTimes++;
change your wordChar array value.
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
char userInput;
//char wordChar[index]; // index = 0
char wordChar[255]; // should change the value of array.
printf("please enter your input:\n");
while ((userInput = getchar()) != '#')
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
}
}
printf("number of combination is: %d", combinationTimes);
return 0;
}
or maybe you can use pointer and then use malloc and realloc.

Resources