For loop doesn't increment indexes properly - c

I'd like to store input from keypad in array, but my for loop doesn't seem to work properly. Instead of reading an input from keypad, adding it to the array, and then incrementing the index, the program keep printing weird indexes.
Code
void loop(){
char arr[3];
for (int i = 0; i<3; i++){
char input = customKeypad.getKey();
if (input != NO_KEY){
do{
arr[i] = input;
Serial.println("Index");
Serial.println(i);
Serial.println("Value");
Serial.println(arr[i]);
} while(input == NO_KEY);
}
}
}
Console output
Index
2
Value
1
Index
1
Value
2
Index
1
Value
3
Index
1
Value
4
Index
2
Value
5
Index
2
Value
6

This is the dataflow of your program. This probably could be a comment but I needed the visualization to make it more understandable. It is not really clear what you want to do:
For instance, if you enter, in this order:
input==NO_KEY
input!=NO_KEY
input!=NO_KEY
You update the indexes #1 and #2, then the iteration (arduino loop) restarts and you can overwrite the values of the array. Is this what you want?
Also notice that the while loop never gets repeated, this is very clear from the dataflow.
I have rewritten you program to be tested outside of Arduino:
#include "stdio.h"
#define NO_KEY 'a'
int main(){
while(1){
char arr[3];
for (int i = 0; i<3; i++){
char input;
printf("%d -> ", i);
scanf(" %c",&input);
if (input != NO_KEY){
do{
arr[i] = input;
} while(input == NO_KEY );
}
}
for (int i = 0; i <3; i++){ printf("Value %d\n",arr[i]); }
printf("\n Reset\n");
}
}
And this is the output, as expected from your code
0 -> a
1 -> b
2 -> c
Value 127
Value 98
Value 99
Reset
0 -> b
1 -> a
2 -> a
Value 98
Value 98
Value 99

Related

Last element is missing from the 2D array

Code:
#include <stdio.h>
int main(){
int num;
scanf("%d", &num);
printf("Enter: ");
char nums[5][num], ch;
for(int i = 0; i < num; i++){
for(int j = 0; j < 5; j++){
if((ch = getchar()) != '\n'){
nums[j][i] = ch;
}
}
}
for(int i = 0; i < num; i++){
for(int j = 0; j < 5; j++){
printf("%c ", nums[j][i]);
}
printf("\n");
}
return 0;
}
Output:
1
Enter: 12345
1 2 3 4
Process returned 0 (0x0) execution time : 6.282 s
Press ENTER to continue.
Why the last element is missing and the additional space at the beginning of the output of array?
If I change the range for j in both for loops to
j <= 5
then, the output looks like this:
1
Enter: 12345
1 2 3 4 5
Process returned 0 (0x0) execution time : 2.107 s
Press ENTER to continue.
If the initial value for j is 1 in the printf loop, then the output looks like this:
1
Enter: 12345
1 2 3 4 5
Process returned 0 (0x0) execution time : 3.675 s
Press ENTER to continue.
No extra gap at the beginning of the array output.
Can anyone explain this and how to resolve this problem?
The problem is that the function getchar reads all characters from the input stream including the new line character that stored in the buffer after the first call of scanf.
So in the loops the first character that is read is the new line character '\n'.
You should remove it for example the following way.
scanf( "%*[^\n]" );
scanf( "%*c" );
You have a logic issue in the first loop. You test for \n but then if you do find a \n, you leave the array entry uninitialized and go on to the next entry anyway. This leads to the bogus output.
Instead you could delay the j++ until getting a valid character, e.g. :
for(int i = 0; i < num; i++){
for(int j = 0; j < 5; ){
if((ch = getchar()) != '\n'){
nums[j][i] = ch;
++j;
}
}
}
Then the array will be filled with the non-newline characters that get entered, and you don't need to do any other flushling.
It would improve the code to also check ch != EOF (and ch should be declared as int), but then you will need some error handling (it would be a mistake to just break the loop and go on to try and output the whole array).

Weird Array Outputs

Okay what am I doing wrong here?
This program is supposed to read 20 integers and then output an array of the integers that are not duplicates (Output each integer only once).
//Program to read 20 integers and return each integer only once (no duplicates).
#include <stdio.h>
int main()
{
int a, b, count=0, temp, array1[20];
printf("Enter 20 array elements between 1 and 10 inclusive\n");
for (a=0; a<20; a++) //Loop to enter 20 elements
{
scanf("%d", &temp);
for (b=0; b<=20; b++) //Loop to test each new element against all previous entered elements
{
if (array1[b] == temp) //If duplicate increment count
{
count++;
}
else if (count == 0 && b == 20) //If there have been no duplicates and 20 numbers have been tested... add entered number to the array
{
array1[a] = temp;
}
}
}
for (a=0; a<20; a++)
{
printf("%d\t", array1[a]);
}
return 0;
}
There are the following things wrong here.
In the inner loop, during the first check, you are comparing against 20 elements. On receiving the first element you do not have any elements to compare against. I have added a variable size to indicate the size of the array. size is initialized to 0.
The if (count == 0 && b == 20) should be moved outside the for loop and can be simplified to if (count == 0)
When an element is added to the array it is added at array1[size] and size is incremented.
You need to reinitialize count at every outer for loop as shown below.
The printing will print size elements that are non duplicate.
Code is below.
//Program to read 20 integers and return each integer only once (no duplicates).
#include <stdio.h>
int main()
{
int a, b, count=0, temp, array1[20];
int size = 0;
printf("Enter 20 array elements between 1 and 10 inclusive\n");
for (a=0; a<20; a++) //Loop to enter 20 elements
{
scanf("%d", &temp);
count = 0;
for (b=0; b<size; b++) //Loop to test each new element against all previous entered elements
{
if (array1[b] == temp) //If duplicate increment count
{
count++;
}
}
if (count == 0) //If there have been no duplicates and 20 numbers have been tested... add entered number to the array
{
array1[size] = temp;
size++;
}
}
for (a=0; a<size; a++)
{
printf("%d ", array1[a]);
}
return 0;
}
This code will accept 20 elements and store and display as many as were non duplicate (which can be 1-20). If you want to store 20 non duplicate elements (entering possibly many more than 20) it can be easily modified.
You have multiple reads of uninitialized variables which is undefined behavior. You also access the array out of range.
for (b=0; b<=20; b++)
^^
This will result in b in the range [0..20]
{
if (array1[b] == temp) //If duplicate increment count
^^^^^^^^^
array1[b] is uninitialized
and when b is 20 you access out of range
Further you only write to the array when count is 0 and b is 20
else if (count == 0 && b == 20)
{
array1[a] = temp;
}
Notice that you never reset count so after the first match you'll never write the array again
BTW - you print:
Enter 20 array elements between 1 and 10 inclusive
but you never perform any check of the input value to be in that range.

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

fgets causing an infinite for loop in C

It seems my implementation of fgets() is incorrect here, would very much appreciate some extra eyes to look over what I've done!
Here's the code
int main(int argc, const char* argv[]){
int numIntegers;
char buffer[20];
int intArray[10];
//if no argument is passed in, terminate
if (argc == 1){
printf("no argument given, terminating..\n");
return EXIT_FAILURE;
}
else{
numIntegers = atoi(argv[1]);
//we only want numbers greater than 0
if (numIntegers <= 0){
printf("# must be greater than 0\n");
return EXIT_FAILURE;
}
else{
printf("Enter %d integer values to place in array: \n", numIntegers);
for (int i = 0; i < numIntegers; i++){
fgets(buffer, numIntegers, stdin);
intArray[i] = atoi(buffer);
printf("Index is = %d \n", i);
}
}
}
//for (int i =0; i < numIntegers; i++){
// printf("Index[%d] = %d \n", i, intArray[i]);
//}
}
Here's the output, the line with no other text besides an integer is user input. Notice how the value of i resets. The issue only occurs when I give an initial argument of anything more than 10. It turns the for loop into an endless loop, for whatever reason.
$ ./a.out 11
Enter 11 integer values to place in array:
5
Index is = 0
2
Index is = 1
1
Index is = 2
2
Index is = 3
3
Index is = 4
4
Index is = 5
123
Index is = 6
123
Index is = 7
123
Index is = 8
1
Index is = 9
2
Index is = 2
2
Index is = 3
3
Index is = 4
5
Index is = 5
1
Index is = 6
12
Index is = 7
You are using
fgets(buffer, numIntegers, stdin);
The second parameter should be the size of the buffer - in your case, 20. That is at least one obvious problem...
The next problem: you are allowing numIntegers to be greater than 10 - so you will be writing values beyond the end of your intArray. Need to fix that too...
if(numIntegers > 10) {
printf("cannot have number greater than 10!\n");
// abort, retry, ignore...
}
In fact - here is your code, with the bugs ironed out: note the use of defined sizes for BUFSIZE and MAXNUM just so you don't have to change it in multiple places if you change your mind...
#include <stdio.h>
#define BUFSIZE 20
#define MAXNUM 10
#define EXIT_FAILURE 0
int main(int argc, const char* argv[]){
int i, numIntegers;
char buffer[BUFSIZE];
int intArray[MAXNUM];
//if no argument is passed in, terminate
if (argc == 1){
printf("no argument given, terminating..\n");
return EXIT_FAILURE;
}
else{
numIntegers = atoi(argv[1]);
//we only want numbers greater than 0
if (numIntegers <= 0 || numIntegers > MAXNUM){
printf("# must be greater than 0 and less than %d!\n", MAXNUM);
return EXIT_FAILURE;
}
else{
printf("Enter %d integer values to place in array: \n", numIntegers);
for (i = 0; i < numIntegers; i++){
fgets(buffer, BUFSIZE, stdin);
intArray[i] = atoi(buffer);
printf("Index is = %d \n", i);
}
}
}
}
Finally - you may wonder why your integer counter seems to "reset"? Well - your intArray is a block of 10 integers on the stack; and when you declare loop variable i, it occupies the next place in memory (as int intArray[10]; was the last time a variable was declared before you got to the for loop) - which you happen to get to when you "index" to intArray[10] (a memory location you are not allowed to access, but you did anyway). You happened to enter the value 2 - and thus, i was reset to 2...
If you had declared i at the start of the program (as I did, since my compiler doesn't "do" C99 by default - I'm that old!), the problem would have shown up differently - or not at all.

How to find the largest and smallest number in an array in c

I have to find a way to display the Maximum and Minium number in an array, the size of the array is 100 and will not exceed that and there is not need for input validation. The program will keep asking for input until 0 is encountered and it too will get added to the array.
I have everything figured out except how to keep track which is the largest and smallest value. I'd appreciate it if someone can fix my code or show me.Another problem I'm having is getting the loop to terminate and do max/min calculation within the while loop when the input is equal to 0.
/*
============================================================================
Name : test.c
Author :
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#define n 100
int main(void){
int numbers[n];
int i = 1;
int j;
int input;
int maxvalue;
int minvalue;
printf("Enter the next array element>");
input = scanf("%d", &numbers[100]);
while (input != 0){
numbers[i] = input;
i++;
printf("Enter the next array element, while loop>");
input = scanf("%d", &numbers[n]);
if (input == 0){
printf("Enter the next array element, if loop");
numbers[i] = 0;
for (j =2;j <= i; j++){
minvalue = numbers[1];
j++;
if (numbers[j] > minvalue){
maxvalue = numbers[j] ;
}
else{
minvalue = numbers[j] ;
}
}
}
}
printf("%f\t", maxvalue);
printf("%f\n", minvalue);
}
EDIT: I took all off your suggestions and edited my code. This is my code below. However, it's output isnt what I'm expecting.
#include <stdio.h>
#include <stdlib.h>
#define N 100
int main(void){
int numbers[N];
int i = 0;
int j;
int input;
int maxvalue;
int minvalue;
printf("Enter the next array element>");
scanf("%d", &input);
while (input != 0){
numbers[i] = input;
i++;
if (input == 0){
i++;
numbers[i] = 0;
minvalue = numbers[0];
maxvalue = numbers[0];
for (j=0;j<=i-1;j++){
if (minvalue >= numbers[j]){
minvalue = numbers[j];
}else if (maxvalue <= numbers[j]){
maxvalue = numbers[j];
}
}
/* min = value of first array element
max = value of first array element
begin loop for each array element, index = 0 to (n-1)
--- if array element value is less than min, set min to this value
--- if array element value is more than max, set max to this value
increment index and repeat loop til last index is completed
average = sum / number of elements (n).
max and min will hold their correct values.*/
}
printf("Enter the next array element, while loop>");
scanf("%d", &input);
}
printf("%d\t", maxvalue);
printf("%d", minvalue);
}
This is the output, I'm getting! Can someone solve this for me.
Enter the next array element>1
Enter the next array element, while loop>2
Enter the next array element, while loop>3
Enter the next array element, while loop>0
12190144 l6Press [Enter] to close the terminal
FINAL EDIT: I SOLVED THIS ON MY OWN. I put the min/max checking outside the master WHILE loop, this allowed the input of 0 to be entered in the array.
#include <stdio.h>
#include <stdlib.h>
#define N 100
int main(void){
int numbers[N];
int i = 0;
int j;
int input;
int maxvalue =1;
int minvalue = 1;
printf("Enter the next array element>");
scanf("%d", &input);
minvalue = input;
maxvalue = input;
while (input != 0){
numbers[i] = input;
++i;
printf("Enter the next array element>");
scanf("%d", &input);
if (input == 0){
numbers[i] = 0;
++i;
}
}
for (j =0;j<i;j++){
if (numbers[j] >= maxvalue){
maxvalue = numbers[j];
}
if(numbers[j] < minvalue){
minvalue = numbers[j];
}
}
printf("%d\t", maxvalue);
printf("%d\n", minvalue);
}
First of all, you're assigning input to the return value of scanf(). This is the number of items assigned by the call, and since you say the input will always be correct, this value will always be 1.
Secondly, you're writing past the end of the numbers[] array with the line:
input = scanf("%d", &numbers[100]);
(you should do scanf("%d, &input) instead, and assign numbers[i] to input in your loop.
Finally, you don't need to recalculate maxvalue and minvalue by iterating through numbers[] every iteration of your loop. Instead, just compare them to input and assign them accordingly.
Hopefully this puts you on the right track.
It looks like your central problem is that you compare each number only against minvalue. That's fine for deciding whether to replace the current minvalue, but obviously it doesn't tell you anything about the relationship of each element to maxvalue.
Another problem: it makes sense to initialize minvalue from the first element, but not if you do it in the loop. That just invalidates all your prior work.
You need to do the same initialization with maxvalue as well. You should initialize that number to the first value.
You should also make a decision about calculating the min and max as you accumulate the data or in a pass through the data when done. What you don't want to do, however, is loop through past elements with every new one. That gives your program quadratic time complexity for no benefit.
Finally, don't tolerate crummy formatting. Debugging always involves studying the code and you will want it to always be perfectly formatted both to be professional about things and also to facilitate reading your own work.
You are asking two questions, about the strategy for the min / max computation and for the loop. Don't do that (to yourself) but solve one problem at a time. So first put something like
signed int input[] = { 8, -5 , /* some more values */ };
size_t const n = sizeof input/ sizeof input[0];
at the start and forget about your scanf problems.
Then wrap your min/max detection in the appropriate loop instruction.
Then compile your code with warnings on: e.g -Wall for gcc, but this might vary for your compiler.
Mine the tells me something:
test-numbers.c:21: warning: 'maxvalue'
may be used uninitialized in this
function test-numbers.c:22: warning:
'minvalue' may be used uninitialized
in this function
This tells you that you are doing something very wrong in not considering the starting point of your algorithm well.
I've reindented your code and replaced lots of it with `/* ...PLACEHOLDER... */
#include <stdio.h>
#include <stdlib.h>
#define N 100
int main(void) {
int numbers[N];
int i = 0;
int input;
int maxvalue;
int minvalue;
printf("Enter the next array element>");
scanf("%d", &input);
while (input != 0) {
numbers[i] = input;
i++;
if (input == 0) {
/* ...PLACEHOLDER... */
}
printf("Enter the next array element, while loop>");
scanf("%d", &input);
}
printf("%d\t", maxvalue);
printf("%d", minvalue);
}
Hopefully you can see what happens when you enter 1, or 2, or 3 and when you enetr 0.
Hint: maxvalue and minvalue values are never changed.
Another hint: how many times does the while() line execute?
Edit with example run
For this example run, code is on the left side, what happens is on the left side
printf("Enter the next array element>"); |
scanf("%d", &input); | Enter 42
|
while (input != 0) { | input is 42, so you do the loop
numbers[i] = input; | numbers[0] = 42
i++; | i = 1
|
if (input == 0) { | input != 0; skip placeholder
/* ...PLACEHOLDER... */ |
} |
printf("Enter the next ...>"); |
scanf("%d", &input); | enter 3
} |
while (input != 0) { | input is 3
numbers[i] = input; | numbers[1] = 3
i++; | i = 2
|
if (input == 0) { | input != 0; skip placeholder
/* ...PLACEHOLDER... */ |
} |
printf("Enter the next ...>"); |
scanf("%d", &input); | enter 0
} |
while (input != 0) { | input is 0, skip while body
/* ...PLACEHOLDER... */ |
} |
printf("%d\t", maxvalue); | maxvalue hasn't been initialized
printf("%d", minvalue); | minvalue hasn't been changed
int cmp(const void *a,const void *b)
{
return *(const int*)a-*(const int*)b;
}
...
qsort( numbers, 100, sizeof(numbers[0]), cmp );
printf("\nmin: %d\nmax: %d",numbers[0],numbers[99]);

Resources