C - scanf has gone ROGUE - c

I have this c program where I am inputing a number N followed by N more numbers. For example, I'll enter 100 followed by 100 more numbers. For some reason, after so many inputs the scanf function will stop working properly. It's as if it has stopped taking input and will just continue one with whatever value is in size.
The use case I came up with is 100 1 2 3 4 5 6 7 8 9 10... (repeated ten times). then after three or four times of that I'll type in 100 10 9 8 7 6 5 4 3 2 1... (repeated ten times) and then there will be an infinite loop of print statements.
int main(int argc, const char * argv[]) {
int histogram[10000];
int i;
while (1) {
int *rectPtr = histogram;
int size;
scanf("%d", &size);
if (!size) return 0;
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr);
rectPtr++;
}
printf("%d", 1);
printf("\n");
}
return 0;
}

Distrust infinite loops.
In a series of comments, I said:
You're not testing the return value from scanf(), so you don't know whether it is working. The pair of printf() statements is odd; why not write printf("%d\n", 1); or even puts("1");?
Your code does not test or capture the return value from scanf(), so you do not know whether scanf() is reporting a problem. As a general rule, test the return value of input functions to make sure what you thought happened did in fact happen. You could also print out the values read just after you read them:
if (scanf("%d", rectPtr) != 1)
{
fprintf(stderr, "scanf() failed\n");
return 1;
}
printf("--> %d\n", *rectPtr);
rectPtr++;
Similarly when inputting size. Also consider if (size <= 0) return 0;. And using fgets() plus `sscanf() can make reporting errors easier.
j.will commented:
It is great to know if scanf fails, but I want to know why it fails and prevent it from failing. How do I do that?
I responded:
I understand you'd like to know. With scanf(), the best you can do after a failure is usually to read all the characters that follow up to a newline or EOF, and if you want to know what went wrong, then you print those characters too, because scanf() leaves the last character that it read in the input buffer ready for the next input operation.
void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
The first character in the output is what caused the failure.
See also How to use sscanf() in loops?
Hacking your code to match this:
#include <stdio.h>
static void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
int main(void)
{
enum { MAX_VALUES = 10000 };
int histogram[MAX_VALUES];
int size;
while (printf("Number of items: ") > 0 && scanf("%d", &size) == 1 &&
size > 0 && size <= MAX_VALUES)
{
int *rectPtr = histogram;
for (int i = 0; i < size; ++i)
{
if (scanf("%d", rectPtr) != 1)
{
gobble();
return 1;
}
rectPtr++;
}
printf("size %d items read\n", size);
}
return 0;
}

IMO, you need to check the return value of scanf() for proper operation. Please check the below code. I have added some modifications.
To exit from the program, you need to press CTRL+ D which will generate the EOF. Alternatively, upon entering some invalid input [like a char instead of int] wiil also cause the program to beak out of while() llop and terminate.
I have put the sequence to check first scanf(). All others need to be checked, too.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int histogram[10000] = {0};
int i;
int *rectPtr = histogram;
int size = 0;
int retval = 0;
printf("Enter the number of elements \n");
while ( (retval = scanf("%d", &size)) != EOF && (retval == 1)) {
rectPtr = histogram;
if (!size) return 0;
printf("Enter %d elements\n", size);
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr); //check in a simmilar way to above
rectPtr++;
}
printf("%d\n", 1111111);
printf("Enter the number of elements: \n");
}
return 0;
}
The output of a sample run
[sourav#broadsword temp]$ ./a.out
Enter the number of elements: 2
Enter 2 elements
1
2
1111111
Enter the number of elements: 3
Enter 3 elements
1
2
3
1111111
Enter the number of elements: 9
Enter 9 elements
0
9
8
7
6
5
4
3
2
1111111
Enter the number of elements: r
[sourav#broadsword temp]$

histogram is declared to have size 10000. You say you do 100 1 2 3 ... repeated 10 times. If I correctly understand that uses 1000 slots in histogram.
If you repeat the test more than 10 times, you exhaust histogram and begin to write past the end of array causing undefined behaviour.
So you must either :
reset recPtr = histogram at each iteration
control recPtr - histogram + size <= sizeof(histogram) after reading size (IMHO better)
And as other said, you should always control input operations : anything can happen outside of your program ...

Related

Pythagorean triplets program

I have written a program that should be rather simple but on execution, it is not giving the wanted results. Even when debugging the program, I guess I found the error (getting stuck in the first if condition) but I'm not able to solve it (my inexperience perhaps). Anyways, this program, which should have been frugal, took 3 days whereas I expected it to take mere hours. Please help me with guiding me where I'm going wrong and how to solve it.
Here is the code
/*WAP to read pre entered no. of ints. consider only +ve and print the pythagorean triplets in them.*/
#include <stdio.h>
int main(){
int c,p,pp,count=0,a;
printf("How many entries to accept?\n");
scanf("%d",&a);
printf("Enter the nos.\n");
for (int i = 0; i < a; i++)
{
scanf("%d",&c);
if (c<0) //skip -ve nos.
{
continue;
}
if (count==0)
{
pp=c;
count++;
}
else if (count==1)
{
p=c;
count++;
}
else if ((pp*pp)+(p*p)==(c*c)) //Tracking count not necesarry after first three
{
printf("Pythagorean triplet found\n");
printf("%d %d %d",pp,p,c);
pp=p;
p=c;
}
}
return 0;
}
The main objective is to first scan a no. to signify the inputs to be read. Then scan the inputs, separated by a space or enter, in a loop which will only accept the no. of inputs stated before. It should neglect any -ve entries. It should print out the Pythagorean triplet if it encounters one, in a consecutive manner i.e. the triplet should appear one after the other & not randomly. We have to do the task without using arrays.
sample input is (you can consider any)(all given through the terminal)
(no. of entries)
6
1 -1 3 4 -4 5
(Here it will ignore -1 & -4)
expected output will be
Pythagorean triplet found
3 4 5
I am still learning so sorry for the elaborate program.
Thank you in advance.
since I cant see the input file I dont know if the values are sorted, since we need to identify which is the hypotenuse, makes it a bit more fiddly.
Also not clear what 'skip negatives' means. Does it mean
that we might see 3 -6 4 5 and say 'yes 3,4,5' is a triple
that we might see 3 -4 5 and say yes 3 4 5
or that we might see 3 -4 5 and simply ignore the whole set
I have assumed the first one
#include <stdio.h>
int main() {
printf("How many entries to accept?\n");
int a;
if (scanf("%d", &a) != 1) {
printf("bad input\n");
return (-1);
}
printf("Enter the nos.\n");
for (int i = 0; i < a; i++)
{
int sides[3] = { 0 };
int max = 0; // longest side length -> hypot
for (int j = 0; j < 3; j++)
{
int c;
if (scanf("%d", &c) != 1) {
printf("bad input\n");
return (-1);
}
if (c < 0) //skip -ve nos.
j--; // try again
else {
if (c > max) {
max = c;
}
sides[j] = c;
}
}
int hyp = max * max; // hypotenuse squared
int adjTot = 0; // adj sides squared total
for (int j = 0; j < 3; j++)
{
if (sides[j] == max)
continue;
adjTot += sides[j] * sides[j];
}
if (adjTot == hyp)
printf("%d %d %d is py\n", sides[0], sides[1], sides[2]);
else
printf("%d %d %d isnt py\n", sides[0], sides[1], sides[2]);
}
return 0;
}
Since you say you are reading from a file it just exits if there is non numeric data

How to fix infinite printing of random number?

I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.
For example for the input: 1 2 3 4 5
The output would be 55555555555555555555555...
Why does this happen and how can I fix that?
My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...
int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSet == NULL) {
return FAIL;
}
scanf("%d", &c);
pSet[i] = c;
printf("%d ", c);
}
free(pSet);
Why does this happen (?) (print ... an infinite amount of times.)
Look at the loop terminating conditions c != EOF.
int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) { // Not good code
scanf("%d", &c);
}
EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.
how can I fix that?
Only loop when the return value of scanf() is as expected (1).
for(i = 1; scanf("%d", &c) == 1; i++) {
...
}
Putting this together with some other ideas
#include <stdio.h>
#include <stdio.h>
int main(void) {
printf("Please enter a stream of numbers to make a set out of them:\n");
int *pSet = NULL; // Start with no allocation
size_t i = 0;
int c;
for (i = 0; scanf("%d", &c) == 1; i++) {
// +--------------------------- No cast needed.
// v v----------v Use sizeof de-referenced pointer
void *p = realloc(pSet, sizeof *pSet * (i + 1));
if (p == NULL) {
free(pSet);
return EXIT_FAILURE;
}
pSet = p;
pSet[i] = c;
}
for (size_t j = 0; j < i; j++) {
printf("%d ", pSet[j]);
}
free(pSet);
return 0;
}
There are a number of problems.
1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items
successfully matched)
2) Don't allocate memory until it's needed
3) Never do realloc directly into the target pointer - always use a temp variable.
Fixing this your code could be:
#include <stdio.h>
int main(void) {
int *pSet = NULL;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
int i = 0;
int c;
while (1) {
if (scanf("%d", &c) != 1)
{
printf("Terminating input loop\n");
break;
}
int* tmp = realloc(pSet, sizeof(int)*(i+1));
if(tmp == NULL) {
printf("oh dear...\n");
break;
}
pSet = tmp;
pSet[i++] = c;
printf("%d ", c);
}
for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
free(pSet);
return 0;
}
Input:
1 2 3 4 5 6 7 stop
Output:
Please enter a stream of numbers to make a set out of them:
1 2 3 4 5 6 7
Terminating input loop
1
2
3
4
5
6
7
You should stop your loop when scanf fails. According to the manual:
On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]
So you can turn your for loop into a while one.
#include <stdio.h>
#include <stdlib.h>
#define FAIL 0
int main() {
int *pSet = (int*) malloc(sizeof(int));
int c;
int i=0;
printf("Please enter a stream of numbers to make a set out of them: ");
while(scanf("%d", &c) == 1) {
pSet[i] = c;
pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSetNew == NULL) {
free(pSet);
return FAIL;
} else {
pSet = pSetNew;
}
printf("%d ", c);
i++;
}
free(pSet);
}
But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.
Note: HengLi fixed a potential memory leak in the code sample above

How to remove newline in tabular addition

When executing this code, additions are separated by a newline each time I enter a value. So for example:
1
4 7 10
I reckon this is caused by the scanf() inputting a new line. How do you write the following code such that
1 4 7 10
is printed?
#include <stdio.h>
int main() {
int number;
int counter = 1;
printf("A\tA+3\tA+6\tA+9\n");
scanf ("%d", &number);
while (number != -1) {
while (counter <=3) {
number += 3;
printf("\t%d", number);
counter++;
}
printf("\n");
scanf ("%d", &number);
counter = 1;
}
}
I think you've mixed the concept of input & output. Actually in your code, you had only output:
> 4 7 10
try replace this code with your inner while loop, then pipe the standard out to another file, check the results and you will understand.
while (counter <=4){
printf("%d\t", number);
number += 3;
counter++;
}
./your_program > output_file

Stop scanf loop if user enters a specific number (Not working) C

I've looked at multiple solutions but none of them worked for me.
I'm asking the user to enter numbers in a loop, but if the user enters a specific number the loop should break.
This is what I've got so far.
#include <stdio.h>
#include <stdlib.h>
#define MAXNUMBERS 5
int getNumbers(int array[])
{
int i;
int n = 0;
printf("Enter max. %d numbers, enter empty line to end:\n", MAXNUMBERS);
for (i = 0; i < MAXNUMBERS; i++)
{
scanf("%d", &array[i]);
fflush(stdin);
n++;
if (array[i] == '5')
{
break;
}
}
return n;
}
int main()
{
int array[MAXNUMBERS];
int amount_numbers;
amount_numbers = getNumbers(array);
printf("Numbers entered: %d\n", amount_numbers);
printf("First three: %d %d %d", array[0], array[1], array[2]);
return 0;
}
Input:
1
5
4
3
2
Output:
Numbers entered: 5
First three: 1 5 4
If the user enters 5 the loop should break.
I'm using 5 as an example, I later want it to do with an empty line. But it doesn't even work with 5.
It just keeps prompting the user to enter another number after he entered 5.
The actual problem is '5' != 5 the former is the character 5 which is in fact it's ascii value, and the latter is the number 5, since you are reading integers, i.e. using the "%d" specifier in scanf() you should use 5, but it would be better if it was just a int variable, and you could initialize it to any number you like before the loop starts.
Your loop is wrong anyway because if the user enters a non-numeric value then your program will invoke undefined behavior. Besides you already invoke undefined behavior with fflush(stdin), so
Remove fflush(stdin)1
7.21.5.2 The fflush function
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.
So the behavior is undefined for an input stream like stdin, or even if the most recent operation was input.
You must check that the value was read properly, and then check in the loop condition if it equals the value you want to stop the loop with, try this
int readNumber()
{
int value;
printf("input a number > ");
while (scanf("%d", &value) == 1)
{
int chr;
printf("\tinvalid input, try again...\n");
do { /* this, will do what you thought 'fflush' did */
chr = getchar();
} ((chr != EOF) && (chr != '\n'));
printf("input a number > ");
}
return value;
}
int getNumbers(int array[])
{
int i;
int stop = 5;
printf("Enter max. %d numbers, enter empty line to end:\n", MAXNUMBERS);
array[0] = 0;
for (i = 0 ; ((i < MAXNUMBERS) || (array[i] == stop)) ; i++)
array[i] = readNumber();
return i;
}
1This is a quote from the C11 draft 1570.
if (array[i] == '5')
You're checking whether array[i] is equal to the ASCII value of the character '5'.
Remove the '' to make it compare against the integer 5.
You are checking if an integer is equal to the character '5', which is then being cast to an ascii value of '5'.
Try using this:
if (array[i] == 5)
Disregard everything!
I should have written
if (array[i] == 5)
without the quotes!
I'm an idiot!
I sat 2 hours at this error...

C program: Checking digits entered are 1s and 0s only using arrays

So I am trying to make a smaller simple program to solve a problem. For this, I am trying to check to make sure the user inputs a number containing ONLY 1s and 0s and then I will use this number to perform a division. For example the number 11010 or 10111. Now my problem is, if I declare an integer to store this number (as follows) there wouldn't be a way to check all the digits are 1s or 0s right?
int userInput;
Now, I can use an array for this. (I know how to do this BUT this leads to my second problem.). Like so:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int myArray[20];
int i, input, length;
printf("Please enter how long your number is: \n");
scanf("%d", &length);
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%d", &input);
assert ((input == 1) || (input ==0));
}
For example, for the first digit the user enters a '1', the second digit the user enters a '0', then the third digit the user enters '0'. I need to "grab" this number though. How would I grab this number "100" and perform arithmetic operations on it. I hope this makes sense, if not moderators please give me a chance to clear it up.
EDIT: Many have suggested the modulo approach. BUT I still want to know if I can do this with an array. That is creating a integer variable and set that equal to each element the user has entered in the array.
I think this could be more simple:
bool is_zeros_and_ones(int n) {
for (; n != 0; n /= 10) {
int mod = n % 10;
if (0 != mod && 1 != mod) {
return false;
}
return true;
}
So you can input whole number and test it without arrays.
You don't really need to get the number one digit at a time.
It is easy to extract the digits of an int. Notice that a number such as 12345 is actually
5 * 10^0 + 4 * 10^1 + 3 * 10^2 + 2 * 10^3 + 1 * 10^4.
To get the lowest digit you can just take the remainder of the number when divided by 10 (i.e. mod it by 10 using the % operator). So, 12345 % 10 is 5. To get the next digit, you can divide the number by 10 (getting 1234) and then mod by ten again - giving you 4. Keep doing this as long as you have digits left in the number (i.e. the number is > 0).
#include <stdio.h>
int is_valid(int number) {
if (number == 0) return 1; // its a 0.
while (number != 0) {
int digit = number % 10;
if (digit != 1 && digit != 0) return 0;
number = number / 10;
}
return 1; // no other digits were found.
}
int main() {
int n;
scanf("%d", &n);
if (is_valid(n)) printf("valid\n");
else printf("not valid\n");
return 0;
}
Here's another idea:
Just write the number again into a string. Then iterate over the string checking each character. This is somewhat less efficient, but simpler to understand/code.
#include <stdio.h>
int is_valid(int n) {
char buffer[20];
char *c;
sprintf(buffer, "%d", n);
for(c = buffer; *c != '\0'; c++) {
if (*c != '0' && *c != '1') return 0;
}
return 1;
}
int main() {
int n;
scanf("%d", &n);
if (is_valid(n)) printf("valid\n");
else printf("not valid\n");
return 0;
}
EDIT:
Since you mentioned in your edit that you are not interested in alternate approaches and just need a way to "grab" the digits as they are fed in, I'm adding this to my answer.
Keep a variable initially set to 0. Now as each digit comes in, (I am assuming the user enters higher digits before lower ones), we multiply our variable by 10 and add the new digit to it. Thus, if the user enters 1, 0, 0, our variable is initially 0, the its 1 (0 * 10 + 1), then its 10 (1*10 + 0) and finally 100 (10 * 10 + 0), which is what we needed.
Maybe something like this would be enough
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int myArray[21];
printf("Please enter your number (max 20 digits)\n");
scanf("%s", myArray);
for (i = 0; i < strlen(myArray); i++){
assert ((myArray[i] == 1) || (myArray[i] == 0));
}
You don't need an array to store all the digits.
Keep dividing by 10 & taking modulo to get each digit & keep a single flag to mark if all digits are 1 or 0.
Of course works only for max word size of the integer...
Something like:
char isBinary = 1;
int copyInput = +input;
while(copyInput && (isBinary=copyInput%10<=1)) copyInput/=10;
You could cheat your way by making sure the program always deals with ints. Your array basically holds the binary representation of a base 10 number. Why not use it convert to an int. Then you can apply all operations to that number just as you would operate on ints.
Here is what i mean
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int i, input, length;
int num = 0; /* holds the actual number */
printf("Please enter how long your number is <= %d: \n", 8 * sizeof(num) - 1);
scanf("%d", &length);
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%d", &input);
assert ((input == 1) || (input ==0));
/* humans enter numbers L TO R */
/* set that bit if it is one */
num |= (input << (length - i - 1)) ;
}
printf("Your number in base 10 is %d\n",num);
/* Now you do normal multiplications, additions, divisions */
/* The only thing remaining now is to convert from base 10 to base 2. */
}
Sample run
Please enter how long your number is <= 31:
5
Please enter digit 1 of your array
1
Please enter digit 2 of your array
1
Please enter digit 3 of your array
1
Please enter digit 4 of your array
1
Please enter digit 5 of your array
0
Your number in base 10 is 30
This solution is only for the second part of the problem. You can take the input as characters and use atoi to convert them to integer.
char arrayOfNumbers[MAX_LENGTH];
char tmpChar;
int number;
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%c", &tmpChar);
assert ((tmpChar == '1') || (tmpChar == '0'));
arrayOfNumbers[i] = tmpChar;
}
/*make sure it is NULL terminated*/
arrayOfNumbers[length] = '\0';
number = atoi(arrayOfNumbers);

Resources