Reputation:
(a newer version of my program is right in the end)
I need to create a program with a function that compares two arrays of integers and returns the subscript of the first place they differ.
I have to use a sentinel value to indicate the end of valid input, rather than EOF, as a file cannot have two end-of-files.
Example of my desired input and output for my program:
Input 1:
3 4 5
3 4 6
Output 1:
2
Explanation: the third values of two arrays are different, so it prints the third subscript (counting as 0,1,2).
I looked over similar issues on stackoverflow. Many errors were fixed and now it lets me to compile a program, without giving me any errors or warnings. But it blinds me because I don't understand what exactly doesn't work.
My problem that I encounter:
I assume my tableDiff function is wrong, however I copied it from teacher's notes. Unless I made a typo, there shouldn't be any difference.
Here is my submitted version:
/*
* A simple program to sort numbers in the correct order
*/
#include <stdio.h>
#include <stdlib.h>
#define MAX 10 //max elements in array
#define SENTINEL -999 //indicate the end of valid input
int main () {
int tableFill(int a[], int max);
int tableDiff (const int a[], const int b[], int n, int m);
void tablePrint (const int a[], const int b[], int n, int m);
int a[MAX];
int b[MAX];
int m,n,index;
m = tableFill(a, MAX);
n = tableFill(b, MAX);
tablePrint(a,b,n,m);
index = tableDiff(a,b,m,n);
if(index==-1)
printf("Index is the same");
else
printf("Index is the different");
return 0;
}
// read values from stdin into array up to 'max' values
int tableFill(int a[], int max) {
int r; // input from scanf
int next; // next input value
int cnt = 0; // count of values read
int *ptr; //pointer
printf("Enter the numbers! \n");
while ((r=scanf("%i", &next)) == 1 && next != SENTINEL)
{
if (r == 0) //invalid input data
{
printf("Nonnumeric data entered. Please enter a number. \n");
while (getchar()!= '\n'); // flush invalid data
}
else
*ptr++=cnt;
}
if(r==1) //another value was read but the array is full
printf("Error - too many values. Array size %i.\n", max);
return ptr-a; //(ptrb - b) should return the same value
}
int tableDiff (const int a[], const int b[], int n, int m)
{
const int *ptra = a; //start for 1st array
const int *ptrb = b; //start for 2nd array
const int *endptra = a+m; //end for 1st array
const int *endptrb = b+n; //end for 2nd array
while(ptra<endptra && ptrb<endptrb && *ptra==*ptrb)
{
ptra++;
ptrb++;
}
if( ptra==endptra && ptrb==endptrb)
{
return -1;
}
else
return ptra -a; //(ptrb - b) should return the same value
}
//print all elements in array.
void tablePrint (const int a[], const int b[], int n, int m)
{
int i; //varriable to print
for (i = 0; i < n; i++)
printf ("%d ", a[i]);
printf ("\n");
}
Here is my newer version:
The program now continues to work until reaches second sentinel (works correctly).
/*
* A simple program to sort numbers in the correct order
*/
#include <stdio.h>
#define MAX 10 //max elements in array
#define SENTINEL -999 //indicate the end of valid input
int main () {
// read values from stdin into array up to 'max' values
int tableFill(int a[], int max);
//compare two arrays and returns the first subscript they differ
int tableDiff (const int a[], const int b[], int n, int m);
//print all elements in array
void tablePrint (const int a[], int n);
int a[MAX];
int b[MAX];
int m,n,index;
m = tableFill(a, MAX);
n = tableFill(b, MAX);
tablePrint(a,m);
tablePrint(b,n);
index = tableDiff(a,b,m,n);
if(index==-1)
printf("-1. Arrays are the same.");
else
printf ("\n The arrays differ at index '%d'.\n", index);
return 0;
}
// read values from stdin into array up to 'max' values
int tableFill(int a[], int max) {
int r; // input from scanf
int next; // next input value
int cnt = 0; // count of values read
int *ptr = a; //pointer
printf("Enter the numbers! \n");
while ((r=scanf("%i", &next))==0 || (next != SENTINEL))
{
if (r == 0) //invalid input data
{
printf("Nonnumeric data entered. Please enter a number. \n");
while (getchar()!= '\n'); // flush invalid data
}
else if (cnt == max) //another value was read but the array is full
printf("Error - too many values. Array size %i.\n", max);
else {
*ptr++ = next;
++cnt;
}
}
return ptr-a; //(ptrb - b) should return the same value
}
//compare two arrays and returns the first subscript they differ
int tableDiff (const int a[], const int b[], int n, int m)
{
const int *ptra = a; //start for 1st array
const int *ptrb = b; //start for 2nd array
const int *endptra = a+m; //end for 1st array
const int *endptrb = b+n; //end for 2nd array
while(ptra<endptra && ptrb<endptrb && *ptra==*ptrb)
{
ptra++;
ptrb++;
}
if( ptra==endptra && ptrb==endptrb)
{
return -1;
}
else
return ptra -a; //(ptrb - b) should return the same value
}
//print all elements in array
void tablePrint (const int a[], int n)
{
int i; //loop counter
for (i = 0; i < n; i++)
printf ("%d ", a[i]);
printf ("\n");
}
Upvotes: 1
Views: 184
Reputation: 84579
You have a number of issues in your logic. The first of which in
while ((r=scanf("%i", &next)) == 1 && next != SENTINEL)
prevents the remainder of the code within the loop from ever executing in the event a non-numeric value is entered. If r != 1
, you exit the loop, not process further within it.
While not an error, function prototypes within main
only works when the functions exclusively do not rely on each other. They know nothing about one another during execution. Better to move the prototypes above main
.
The remainder of your logic was somewhat difficult to follow and overly complicated. When you are looking for a difference within two arrays, you only need iterate over common elements. If they have differing number of elements, you know they differ by definition starting at the first unique element. So you can whittle down your comparison code quite a bit. Something like the following is fine:
/* check if array 'a' and 'b' are the same, else return index
* of first difference, otherwise return -1 for equal arrays.
*/
int tablediff (const int *a, const int *b, int sza, int szb)
{
int i, lim = sza < szb ? sza : szb; /* limit search to common elements */
for (i = 0; i < lim; i++) /* for each common element check */
if (a[i] != b[i])
return i;
if (sza != szb) /* if size differs, arrays differ */
return lim;
return -1; /* otherwise equal */
}
You can avoid the use of a SENTINEL
just by proper bounds checking. Further, while you are free to create a arrayprint
function that prints 2 arrays, it is far better to create a function that prints a single array and call it twice.
Putting those pieces together, and noting you do not use anything from stdlib.h
, you could do something similar to the following:
#include <stdio.h>
#define MAX 10 //max elements in array
int tablefill(int *a, int max);
int tablediff (const int *a, const int *b, int sza, int szb);
void tableprn (const int *a, int sza);
int main (void) {
int a[MAX];
int b[MAX];
int idx, sza, szb;
sza = tablefill (a, MAX);
szb = tablefill (b, MAX);
tableprn (a, sza);
tableprn (b, szb);
if ((idx = tablediff (a, b, sza, szb)) == -1)
printf ("\n the arrays are the same.\n\n");
else
printf ("\n the arrays differ at index '%d'\n\n", idx);
return 0;
}
/* read values from stdin into array up to 'max' values */
int tablefill (int *a, int max)
{
int idx = 0, tmp;
while (idx < max && scanf (" %d", &tmp) == 1)
a[idx++] = tmp;
return idx;
}
/* check if array 'a' and 'b' are the same, else return index
* of first difference, otherwise return -1 for equal arrays.
*/
int tablediff (const int *a, const int *b, int sza, int szb)
{
int i, lim = sza < szb ? sza : szb;
for (i = 0; i < lim; i++)
if (a[i] != b[i])
return i;
if (sza != szb)
return lim;
return -1;
}
/* print all elements in array. */
void tableprn (const int *a, int sz)
{
int i; //varriable to print
for (i = 0; i < sz; i++)
printf (" %d", a[i]);
printf ("\n");
}
Example Equal
$ /bin/arraycmp <../dat/20intsame.txt
8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495
8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495
the arrays are the same.
Example Differ
$ ./bin/arraycmp <../dat/20intdif.txt
8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495
8572 -2213 6434 16330 3034 12346 4855 16985 11250 1494
the arrays differ at index '9'
Providing Prompts for Input
When taking user input, it is a good idea to proving meaningful prompts as well so the user isn't left looking at a blinking cursor wondering if the program has hung, or what is going on. So in addition to the logic above, you would want to add simple prompting that explains what the program needs and how to provide the input. Something simple will do:
printf ("\nenter a max of 10 integers below 'ctrl+d` to end.\n");
sza = tablefill (a, MAX);
printf ("enter a max of 10 integers below 'ctrl+d` to end.\n");
szb = tablefill (b, MAX);
printf ("\nthe arrays entered are:\n\n");
tableprn (a, sza);
tableprn (b, szb);
(note: to generate a manual EOF
on windoze, the key combination is ctrl+z)
So for entering less than 10 integers for each array you could do something like:
$ ./bin/arraycmp
enter a max of 10 integers below 'ctrl+d` to end.
10 12 14 16 17
enter a max of 10 integers below 'ctrl+d` to end.
10 12 14 15 17
the arrays entered are:
10 12 14 16 17
10 12 14 15 17
the arrays differ at index '3'
Look over the example and let me know if you have any additional questions.
Upvotes: 1