How to fix infinite printing of random number? - c

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

Related

How to resolve this problem relevant File and Null in C?

So I need output size of array in this file text and to do this I must break the loop in the last position by using NULL to break but the problem here that when arr[i] come to value 0, it equal to NULL and break at that position so my size of array is not complete. How to resolve it? Thanks for support!
The file .txt input:
3
4
0
5
6
The code:
#include <stdio.h>
int main() {
char a[20];
char e[40];
int arr[30];
int num, key, k = 0, len = 0;
printf("Enter a filename: ");
scanf("%s", &a);
scanf("%c", &e);
FILE* rfile;
rfile = fopen(a, "r");
if (rfile == NULL) {
printf("Not found the file !!!");
}
else {
printf("Successfully accessed the file: %s\n", a);
int i;
for (i = 0; i < 30; i++) {
fscanf(rfile, "%d", &arr[i]);
fscanf(rfile, "%c", &e);
if (arr[i] == NULL) { // PROBLEM HERE
break;
}
len++;
}
}
printf("The size of array: %d", len);
return 0;
}
You can find some more details regarding what NULL is here, but you should save NULL for pointer comparisons, not comparing against ints as you are doing. In fact, your usage generates a warning:
warning: comparison between pointer and integer
Despite that, 0 == NULL will evaluate to true. Since 0 is in your list of values, you prematurely break revealing your problem. Instead, you simply need to read the entire file, either until you run out of room in your array (already covered by your for loop) or reach the end of the file (designated by EOF). To determine that, you need to check the return value of fscanf. Below is an example of a possible implementation:
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[30];
int len = 0;
FILE* rfile;
rfile = fopen("file.txt", "r");
if (rfile == NULL) {
printf("Not found the file !!!");
exit(-1);
}
else {
int i;
for (i = 0; i < 30; i++) {
// fscanf returns the number of correctly matched items, or
// EOF when the end of the file is reached (or EOF on error)
int ret = fscanf(rfile, "%d", &arr[i]);
// did we get a correct match?
if (ret == 1)
{
// we matched one number as expected, increment len
len++;
}
// did we reach the end of file?
else if (ret == EOF)
{
// EOF can also indicate an error, check errno here to determine if
// an error occurred instead of end of file, if you want
break;
}
}
}
// prints 5 with your input file example
printf("The size of array: %d\n", len);
return 0;
}
I have no idea what you were trying to accomplish with e, so I removed that as well as other unused variables, and hardcoded user input.
arr is the array of ints arr[i] has type int. NULL is a pointer.
If 0 indicated the end of the data (sentinel value) then:
if (arr[i] == 0) break;
or in a short form
if (!arr[i]) break;

Need to use malloc for homework assignment but output always reads 10.00

`
void avgOfArray()
{
float avg = 0, *ptr = 0;
ptr = (float*)malloc(5*sizeof(float));
printf("Enter 5 numbers: \n");
for(int x = 0; x < 5; x++) {
ptr[x] = getchar();
while ((ptr[x] = getchar()) != EOF && ptr[x] != '\n');
}
for (int y = 0; y < 5; y++) {
avg = avg + ptr[y];
}
avg = avg / 5;
printf("Average = %0.2f \n", avg);
system("pause");
}
`
I'm learning about pointers in class and the question asked to get the average of 5 numbers. Every output is 10 regardless of the input. If someone could explain the issue that would be very appreciated.
getchar returns the code of the character, not the float itself.
Since your loop scans the chars until it meets \n (ASCII code = 10), you always get 10 (as float).
Don't rewrite float scan, use fgets to get a line (issue with end of file or \n automatically handled), then scan 5 floats from the line buffer, or use scanf 5 times with a space
int i;
for (i=0;i<5;i++)
{
scanf(" %f",p+i); // no error check!
}
Don't cast malloc, and also check the return value of malloc, if it
returns NULL, you cannot access the memory otherwise it's undefined behaviour.
float *ptr = malloc(5 * sizeof *ptr);
if(ptr == NULL)
{
fprintf(stderr, "Not enough memory\n");
return; // or exit or whatever
}
Also note that dynamically allocating space is usually needed when the size is
not known at compile time, because the user inputs the size or it has to be
calculated. In your example you already know the size, malloc is not needed.
float arr[5]; would be enough.
getchar(); returns a single character. The value of the character is
determined by the ASCII table. The value for '1' is not the same as the
value 1, because '1' is 49. You have to read all the characters forming a
number and then convert them to float using functions like scanf or strtof.
Alternative 1: using scanf.
// assuming you are using ptr = malloc(...)
for(size_t i = 0; i < 5; ++i)
{
while(scanf("%f", ptr + i) != 1)
{
// clear buffer
int c;
while((c = getchar()) != '\n' && c!= EOF));
if(c == EOF)
{
// cannot continue doing scanf
free(ptr);
return; // or exit
}
printf("Please re-enter the number:\n");
}
}
Alternative 2: using fgets
char line[50];
for(size_t i = 0; i < 5; ++i)
{
while(1) // continue reading if value is not a float
{
if(fgets(line, sizeof line, stdin) == NULL)
{
// cannot continue reading
free(ptr);
return; // or exit
}
char *end;
float val = strtof(line, &end);
if(*end == '\n' || *end == '\0')
{
ptr[i] = val;
break; // exit while(1) loop, continue reading next value
} else
printf("Please re-enter the number:\n");
}
}
Also at the end do not forget to free the memory with free(ptr);.

C - scanf has gone ROGUE

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

How to read 2 lines of integer input in C?

I'm doing a project for my algorithms class and I'm having a lot of trouble with inputs. I'm trying to read an input like this:
6 0 2 3 1 3
5 9 2 1 3
The integers will need to go to
int num1; // num1 = 6
int num2; // num2 = 5
int array1[100]; // array1 = {0, 2, 3, 1, 3, 0, 0, ...}
int array2[100]; // array2 = {9, 2, 1, 3, 0, 0, ...}
The input will come from standard input, in the form of a file. So in terminal running the program would look like this:
cat input.txt | ./a.out
Where input.txt contains the two lines of integers.
Here is my flawed attempt so far:
while(scanf("%d%c", &temp, &ch) > 1){
if (ch != '\n'){
one[count] = temp;
}
else if (ch == '\n'){
count = 0;
two[count] = temp;
}
one[count] = temp;
count++;
if (ch != ' ')
{
printf("Invalid input. Please do int + space.\n");
return -1;
}
if ((temp >= 100) || (temp <= -100))
{
printf("Input is too big, must be between -100, 100.\n");
return -1;
}
if (one[0] < 1){
printf("Input for n cannot be smaller than one!");
return -1;
}
}
I think the main issue is that I'm just not sure how to deal with multiple lines of input. One line of input is fine by me but multiple lines is what trips me over.
You could fetch an entire line of input using the getline function and then iterate over that line, scanning one number at a time using the strtol function.
From the example in your question I assume that you want all remaining entries in the two arrays to be zero so don't forget to zero them out (either manually or using the memset function.).
And also don't forget to free() the buffer getline gave you.
Actually I ended up using scanf, here is the working code below. It really helped to read some of these comments and also refer to K&R
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE 100
void shiftArrayBackByOne(int a[]){
for(int i = 1; i <= ARRAY_SIZE; i++){
a[i - 1] = a[i];
}
}
void printArray(int a[], int n){
for(int i = 0; i < n; i++){
printf("%d ", a[i]);
}
putchar('\n');
}
int main(){
int isLineTwo = 0;
int countOne = 0;
int countTwo = 0;
int inputNum;
int num1;
int num2;
int array1[ARRAY_SIZE];
int array2[ARRAY_SIZE];
char ch;
while(scanf("%d%c", &inputNum, &ch) > 0){
//Puts the input into different arrays depeding
//on value of isLineTwo
if (isLineTwo){
array2[countOne] = inputNum;
countOne++;
} else {
array1[countTwo] = inputNum;
countTwo++;
}
//Increment isLineTwo if ch is a 'newline'
if (ch == '\n')
{
isLineTwo++;
}
//Check if user inputs more than 2 lines
if (isLineTwo > 1){
printf("Hey, no more than 2 input lines!\n");
}
}
printArray(array1, countOne);
printArray(array2, countTwo);
num1 = array1[0];
num2 = array2[0];
shiftArrayBackByOne(array1);
shiftArrayBackByOne(array2);
printf("num1 = %d\n", num1);
printf("num2 = %d\n", num2);
printArray(array1, countOne);
printArray(array2, countTwo);
}
Look at my code below. Maybe it helps you.
Generally, if you know how many numbers will be inputted, you can read numbers one by one using scanf("%d", ...) and use fflush() when the expected amount is met to clear any other numbers in the buffer. This example assumes that the first two numbers are the respective lengths of each line. The input could look like:
// example input:
// 4
// 3
// 1 2 3 4
// 5 6 7
int main()
{
int it;
int it1 = 0;
int it2 = 0;
int line1[100];
int line2[100];
scanf("%d", &it1); // amount of line 1 numbers
scanf("%d", &it2); // amount of line 2 numbers
it = 0;
do
{
scanf("%d", &line1[it]);
} while (++it < it1);
fflush(stdin); // clear input buffer
it = 0;
do
{
scanf("%d", &line2[it]);
} while (++it < it2);
return 0;
}

Input several numbers from array and each one number check for integer or not

everyone!
I hope someone can help me figure out something in C language.
This is my first seriously homework in IT, I have no experience and I'm learning in e-studies, so teacher help isn't very available.
I need to develop console application in C language. User need to input 10 integer numbers, if insert number isn't integer, need to output error and again re-enter new number until all 10 integer numbers will be inserted.
Everything works in case if I say that these 10 numbers can't be 0 (I make this to be sure that my if-else statement working), but won't work when I want that every input number will be check if it is integer or not.
How can I do it right.
Please help
so far my code look like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
float f;
int numbers[10];
for (i = 0; i < 10; i++)
{
scanf ("%d", &numbers[i]);
if (numbers[i] != 0)
{
scanf ("*%d", &numbers[i]);
}
else
{
printf ("\nError!Entered number is't integer \n");
printf ("\nPlease insert number again \n");
scanf("%*d", &numbers[i]);
}
}
}
#include <stdio.h>
int main(void) {
int i = 0;
int val;
char ch;
int numbers[10];
while(i < 10) {
val = scanf("%d", numbers + i); // read the integer into a[i]
if(val != 1) {
while((ch = getchar()) != '\n') // discard the invalid input
; // the null statement
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
val = scanf("%d", numbers + i);
continue;
}
++i;
}
// process the numbers array
return 0;
}
I write this line again
val = scanf("%d", numbers + i);
Now it works how I need. Great - thanks a lot
There are several techniques you might use:
Read the number as a string and reject if it contains characters not suitable for an integer. The use sscanf() to convert the string to integer.
Read the number as a float and reject if it is out of integer range or it has a non-integer value.
Read the input character by character and build up an integer value. If invalid characters appear, reject the value.
scanf returns the number of input items successfully matched and assigned. You can check this value for 1 for each call of scanf. If the value is 0, then you should discard the input to clear the stdin buffer and read input again.
#include <stdio.h>
#include <ctype.h>
int main(void) {
int i = 0;
int val;
char ch;
int numbers[10];
while(i < 10) {
// read an integer and the first non-numeric character
val = scanf("%d%c", numbers + i, &ch);
// if the number of items assigned by scanf is not 2 or if
// the first non-numeric character is not a whitespace, then
// discard the input and call read input again.
// for example input of type 32ws are completely discarded
if(val != 2 || !isspace(ch)) {
while((ch = getchar()) != '\n') // discard the invalid input
; // the null statement
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
continue;
}
++i;
}
// process the numbers array
return 0;
}
Although I am not entirely clear on the details of your question, here is an outline of code similar to what you want:
int main(void)
{
int i;
int numbers[10];
int sum = 0;
for(i=0; i<10; ++i)
{
printf("Enter #%d:\n", i+1);
scanf("%d", numbers+i);
if (numbers[i] % 2 == 0) // Then Number is even
{
sum += numbers[i];
}
}
printf("The sum of only the even numbers is %d\n", sum);
getch();
return 0;
}
To read an int, suggest fgets() then sscanf() or strtol()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
int numbers[10];
for (i = 0; i < 10; ) {
char buffer[50];
if (fgets(buffer, sizeof buffer, stdin) == NULL) break;
int n; // number of `char` parsed
if (sscanf(buffer, "%d %n", &numbers[i], &n) != 1 || buffer[n] != '\0') {
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
continue;
}
i++;
}
return 0;
}
The strtol() approach. This detects overflow issues:
if (fgets(buffer, sizeof buffer, stdin) == NULL) break;
char *endptr;
errno = 0;
long num = strtol(buffer, &endptr, 10);
if (errno || num < INT_MIN || num > INT_MAX) Handle_RangeError();
if (buffer == endptr || *endptr != '\n') Handle_SyntaxError();
numbers[i] = (int) num;
Recommend making a int GetInt(const char *prompt) function that can be used repeatedly.
User input is evil. Do not trust it until well vetted.

Resources