Strange behaviour when finding largest number in Array [duplicate] - arrays

This question already has answers here:
Why does the indexing start with zero in 'C'?
(16 answers)
Closed 2 years ago.
Found some very bizarre behaviour when trying to brainstorm a problem:
Purpose of code:
Simple code to find the largest number in an array. I simply store the first index to a variable and compare it to every other index in the list. If another number is larger, that number replaces the number stored in my variable and the process repeats until the end of the list.
#include <stdio.h>
const int SIZE = 8;
int main(void)
{
int arr[] = {7, 3, 9, 14, 1, 27, 14, 2};
int largest;
largest = arr[0];
for (int i = 1; i <= SIZE; i++)
{
if (largest < arr[i])
{
largest = arr[i];
}
}
printf("The largest number in the array is %i\n", largest);
}
Weird behaviour:
This works, sometimes. Other times I get large numbers that give me the impression I've hit an area of memory I shouldn't have. I could understand if this happened every time but because it only happens every 2nd or 3rd time I compile the code I'm bewildered. The code doesn't change and yet the output does
Console Log:
~/pset3/plurality/ $ ./test
The largest number in the array is 1366797536
~/pset3/plurality/ $ ./test
The largest number in the array is 27
~/pset3/plurality/ $ ./test
The largest number in the array is 27
~/pset3/plurality/ $ ./test
The largest number in the array is 1773422672
~/pset3/plurality/ $
My ideas:
The loop somehow hits goes past the end of the array and sees that as the largest number. Again the bizarreness of this is that this only happens 50% of the time
Any ideas would be greatly appreciated.

Your loop is executing one time too many. The loop termination condition i <= SIZE will result in the loop body accessing arr[SIZE], which is outside of the arr array -- remember that C array indices start at 0.
Since the array is stored in the stack frame, your code will be fetching some garbage value from the stack located at the first address beyond the array. This garbage value could be anything, and so could be a large positive value, resulting in what you are seeing.

In C the arrays indices start from 0 to N - 1, with N begin the number of elements of that array, when you do:
for (int i = 1; i <= SIZE; i++)
you are accessing a position out of the allocate memory for that array, therefore you will be reading a random value from memory. Which is considered to be undefined behavior. Hence the reason why:
Again the bizarreness of this is that this only happens 50% of the
time
Sometimes the value that you will be reading from the position outside the array boundaries (i.e., will arr[i] with i = SIZE); will be bigger than the values that you have on the array, other times it will not. Hence, the name undefined behavior.

TLDR: You count i to 8 instead of 7 so you access a value out of bounds of the array. Remove the = sign in the declaration of the for loop.
You are counting from 1...8 in your for loop.
const int SIZE = 8;
…
for (int i = 1; i <= SIZE; i++)
Your Array has 8 values stored so you can access them with arr[0] … arr[7]
If you Access arr[8], which happens in the last Iteration of the for loop since you Count i up to 8 instead of 7 you Access a value out of Bounds, which gives you a kinda random value

Related

How to solve a runtime error happening when I use a big size of static array

my development environment : visual studio
Now, I have to create a input file and print random numbers from 1 to 500000 without duplicating in the file. First, I considered that if I use a big size of local array, problems related to heap may happen. So, I tried to declare as a static array. Then, in main function, I put random numbers without overlapping in the array and wrote the numbers in input file accessing array elements. However, runtime errors(the continuous blinking of the cursor in the console window) continue to occur.
The source code is as follows.
#define SIZE 500000
int sort[500000];
int main()
{
FILE* input = NULL;
input = fopen("input.txt", "w");
if (sort != NULL)
{
srand((unsigned)time(NULL));
for (int i = 0; i < SIZE; i++)
{
sort[i] = (rand() % SIZE) + 1;
for (int j = 0; j < i; j++)
{
if (sort[i] == sort[j])
{
i--;
break;
}
}
}
for (int i = 0; i < SIZE; i++)
{
fprintf(input, "%d ", sort[i]);
}
fclose(input);
}
return 0;
}
When I tried to reduce the array size from 1 to 5000, it has been implemented. So, Carefully, I think it's a memory out phenomenon. Finally, I'd appreciate it if you could comment on how to solve this problem.
“First, I considered that if I use a big size of local array, problems related to heap may happen.”
That does not make any sense. Automatic local objects generally come from the stack, not the heap. (Also, “heap” is the wrong word; a heap is a particular kind of data structure, but the malloc family of routines may use other data structures for managing memory. This can be referred to simply as dynamically allocated memory or allocated memory.)
However, runtime errors(the continuous blinking of the cursor in the console window)…
Continuous blinking of the cursor is normal operation, not a run-time error. Perhaps you are trying to say your program continues executing without ever stopping.
#define SIZE 500000<br>
...
sort[i] = (rand() % SIZE) + 1;
The C standard only requires rand to generate numbers from 0 to 32767. Some implementations may provide more. However, if your implementation does not generate numbers up to 499,999, then it will never generate the numbers required to fill the array using this method.
Also, using % to reduce the rand result skews the distribution. For example, if we were reducing modulo 30,000, and rand generated numbers from 0 to 44,999, then rand() % 30000 would generate the numbers from 0 to 14,999 each two times out of every 45,000 and the numbers from 15,000 to 29,999 each one time out of every 45,000.
for (int j = 0; j < i; j++)
So this algorithm attempts to find new numbers by rejecting those that duplicate previous numbers. When working on the last of n numbers, the average number of tries is n, if the selection of random numbers is uniform. When working on the second-to-last number, the average is n/2. When working on the third-to-last, the average is n/3. So the average number of tries for all the numbers is n + n/2 + n/3 + n/4 + n/5 + … 1.
For 5000 elements, this sum is around 45,472.5. For 500,000 elements, it is around 6,849,790. So your program will average around 150 times the number of tries with 500,000 elements than with 5,000. However, each try also takes longer: For the first try, you check against zero prior elements for duplicates. For the second, you check against one prior element. For try n, you check against n−1 elements. So, for the last of 500,000 elements, you check against 499,999 elements, and, on average, you have to repeat this 500,000 times. So the last try takes around 500,000•499,999 = 249,999,500,000 units of work.
Refining this estimate, for each selection i, a successful attempt that gets completely through the loop of checking requires checking against all i−1 prior numbers. An unsuccessful attempt will average going halfway through the prior numbers. So, for selection i, there is one successful check of i−1 numbers and, on average, n/(n+1−i) unsuccessful checks of an average of (i−1)/2 numbers.
For 5,000 numbers, the average number of checks will be around 107,455,347. For 500,000 numbers, the average will be around 1,649,951,055,183. Thus, your program with 500,000 numbers takes more than 15,000 times as long than with 5,000 numbers.
When I tried to reduce the array size from 1 to 5000, it has been implemented.
I think you mean that with an array size of 5,000, the program completes execution in a short amount of time?
So, Carefully, I think it's a memory out phenomenon.
No, there is no memory issue here. Modern general-purpose computer systems easily handle static arrays of 500,000 int.
Finally, I'd appreciate it if you could comment on how to solve this problem.
Use a Fischer-Yates shuffle: Fill the array A with integers from 1 to SIZE. Set a counter, say d to the number of selections completed so far, initially zero. Then pick a random number r from 1 to SIZE-d. Move the number in that position of the array to the front by swapping A[r] with A[d]. Then increment d. Repeat until d reaches SIZE-1.
This will swap a random element of the initial array into A[0], then a random element from those remaining into A[1], then a random element from those remaining into A[2], and so on. (We stop when d reaches SIZE-1 rather than when it reaches SIZE because, once d reaches SIZE-1, there is only one more selection to make, but there is also only one number left, and it is already in the last position in the array.)

Iterate a long integer and then append number to an array in C

So I'm prompting the user for a number, stored as a long int, then I want to do a for loop and iterate that long int, getting all the odd position numbers in a odd array and all the even position numbers in a even array. I'm trying to resolve the credit problem set from CS50
#include <stdio.h>
#include <cs50.h>
int main(void)
{
long even[] = {}, odd[] = {};
long cc = get_long("Number: ");
}
Basically I'm trying to get this:
If long cc = 12345678912345, then even should be even[7] = {1, 3, 5, 7, 9, 2, 4} and odd should be odd[7] = {2, 4, 6, 8, 1, 3, 5}
I don't really know how I would be able to iterate over long cc to then add the specific number I need into the array
The main problem you have is that arrays in C have a fixed size, set when they are created, and that size cannot be changed. So there's no way to "append" to an array.
The usual way to deal with that is to create an array with a maximum size (or capacity) and track the "in use" part of the array with a separate variable (often called 'size'). At any given time, the array elements from 0 to size-1 are "in use" and valid, while those from size to capacity-1 are "free" and might contain garbage values that will be ignored.
Since the array and the size variable are so intimately connected, it is common to combine them into a struct to make things easier to manage:
#define MAX_ARRAY_SIZE 100
struct long_array {
size_t size;
long data[MAX_ARRAY_SIZE];
};
Now you can initialize an empty array with struct long_array odd = { 0 }; and you could then append to this array with
if (odd.size == MAX_ARRAY_SIZE) {
/* always check for errors or unexpected situations! */
fprintf(stderr, "array overflow\n");
exit(1); }
odd.data[odd.size++] = new_value;
of course, this will end up allocating the maximum amount for every array, so the limit needs to be fairly small. You can make this more flexible by allocating the array on the heap and storing the capacity in the array as well as the size:
struct long_array {
size_t size, capacity;
long *data;
};
but this requires more management to track when the array needs to be resized or freed.
that's fairly easy, just allocate two array with how many numbers are in cc using something like
int temp = cc, i = 0;
while (temp > 0) {i++; cc /= 10;}
Then calculate ur stuff like this:
while (cc > 0)
{
newNumber = cc/10;
newDigit = CC % 10
if (newNumber % 2 == 0) /*newDigit is even*/
else /*newDigit is odd*/
cc = newNumber;
}
You can use the modulo operator % to get each digit. The modulo operator basically gives you the remainder so if you do % 10 then it will give you the last digit. So 123 % 10 = 3. Then you divide the credit card number by 10 and repeat the process to get the next digit. Ex 123/10 = 12, then 12 % 10 is 2. If you make a counter variable to count how many times you've done the loop, that will give you the position. If you do position % 2, that will tell you if it is odd or even.
while (CC > 0)
digit = CC % 10
if (position % 2 == 1) //it's odd
else //its even
CC = CC/10 //to prepare for next iteration of the loop
position = position + 1 //position starts at right side of CC number
One of the other proposed answers here determines if the digit's value is odd or even, but you're trying to determine if the digit is in an even or odd position. The other proposed answer uses an array, which is something you learn about later in the course and isn't what the class is trying to teach you now.
The solution I've suggested is in line with what has been covered by your class so far. Later you will learn about arrays and you can approach this problem differently. Later in the course, you need to do this same problem in Python and that time I took in the value as a string because you can treat the full credit card number as an array and then each digit is just an element in that array. creditcardnumberarray[0] would be the first digit for example. You would need to change each digit from a Char to a Int before doing your checksum. You can do this conversion by subtracting the digit char from the char '0'. So int digitAsInt = digitAsChar - '0'

Segmentation fault in test cases

So, the question is as follows:
Given any array(reasonably large) of integers, return the maximum difference between any two elements in the array such that the larger element occurs at a higher index than the smaller element. Return -1, if no such pair is found.
Example:
7
2
3
10
2
4
8
1
where the first element is the size of the array(or the number of lines being entered), and the rest are the elements.
Sample output is 8(10-2) for the above.
My code is as follows:
int A[20],size;
scanf("%d",&size);
for(int i=0;i<size;i++){
scanf("%d\n",&A[i]);
}
int diff = A[1]-A[0];
int currsum = diff;
int maxsum = currsum;
for(int i=1; i<size-1; i++)
{
// Calculate current difference for the loop
diff = A[i+1]-A[i];
// Calculate current sum for the loop
if (currsum > 0)
currsum += diff;
else
currsum = diff;
// Update max sum(if needed)
if (currsum > maxsum)
maxsum = currsum;
}
printf("%d",maxsum);
This is a question from Hackerrank, but it runs for only three out of 10 possible testcases. The rest of the cases return a segmentation fault. Any idea would be helpful.
As mentioned in the comments, you've declared A to hold just 20 integers. But the question can send up to 1,000,000 integers. That's the mistake!
Using pointers make this more important. First declare A as pointer of integers, then, read the first element of the array, using this integer you can allocate memory dynamically (malloc() or calloc() function) for your array A. so the size of A will dynamic and you can resize it in function of the first element.

unwanted changing value of an array element being address/number of element for the second array in C

I have problem that really confuses me a lot. I want to have a sparse matrix stored in 3 arrays and perform matrix/vector multiplication. Matrix and vectorB are red from a file. That's the background. The problem is in unwanted changing the value of an integer array element being an "argument" of the double array. Here is what I am doing:
int row[ELEMENTS_NO] = {0};
int col[ELEMENTS_NO] = {0};
double values[ELEMENTS_NO] = {0.0};
double vectorB[M_SIZE] = {0.0};
double res[M_SIZE]={0.0};
...reading row,col,values, from the file...
printf("\n row[0]:%d, col[0]:%d",row[0],col[0]);
for (k = 0; k < ELEMENTS_NO; k++) {
res[row[k]] = res[row[k]] + values[k]*vectorB[col[k]];
}
printf("\n\n\n row[0]:%d, col[0]:%d",row[0],col[0]);
the output of the first print is correct:
row[0]:1, col[0]:1
while the second print gives me following output:
row[0]:1352932126, col[0]:1
Why the value of col array changed after executing for loop? How to solve my problem and remain row and col elements unchanged?
Thank you for any useful information!
Check the value of row[k] and make sure it's between 0 and ELEMENTS_NO
My best guess is that one of the elements of row is negative, thus res[row[k]] would be negative.
Try running the program using valgrind, this will tell you when you have out of bounds problems for arrays.
You are indexing res[] by a value from the row array. The first one is over 1 billion, so you are changing the (more than) billionth element of res[] which I suspect is beyond the end of the array. Then anything can happen, including overwriting other variables.

c beginner, vectors

I'm a c beginner and i've a problem (as usual). I wrote this simple program:
#include <stdio.h>
#define SIZE 10
main()
{
int vettore[9];
int contatore1,contatore2;
for(contatore1 = 0; contatore1 <= 9; ++contatore1)
{
vettore[contatore1] = contatore1*2;
}
printf("%d\n\n", vettore[9]);
for(contatore2 = 0; contatore2 < 10; ++contatore2)
{
printf("%d\n", vettore[contatore2]);
}
printf("\n%d\n", vettore[9]);
return 0;
}
The output of this program is:
18
0
2
4
6
8
10
12
14
16
9
10
Why the value of vettore[9] changes 3 times? And why it has the correct value only on the first line of the output? thank you :)
C arrays are zero based so valid indexes for a 9 element array are [0..8]. You are writing beyond the end of your array. This has undefined results but is likely corrupting the next stack variable.
In more detail... vettore has 9 elements, which can be accessed using vettore[0] ... vettore[8]. The final iteration of your first loop writes to vettore[9]. This accesses memory beyond the end of your array. This results in undefined behaviour (i.e. the C standard does not specify expected outcome here) but it is likely that the address of vettore[9] is the same as the address of contatore2, meaning that the latter variable is written to.
You have a similar problem in the next loop which prints more elements than vettore contains.
You can fix this by changing your loops to
for(contatore1 = 0; contatore1 < 9; ++contatore1)
for(contatore2 = 0; contatore2 < 9; ++contatore2)
Note that it would be safer if you changed to calculating the size of the array instead, by using sizeof(vettore)/sizeof(vettore[0]) in the exit test of your loops in place of hard-coding 9.
Your array vettore has 9 elements, but by referencing vettore[9], you're actually referencing the 10th element (since element indexing starts from 0). So it's some random location on the stack, without a well-defined value.
The solution is to index only up to vettore[8], or define vettore to have size 10.
check this out:
for(contatore2 = 0; contatore2 < 10; ++contatore2)
{
printf("%d\n", vettore[contatore2]);
}
you are displaying 11 elements of the vettore array (which is defined as a 9 ints array). I think that the error is in the random allocation on the stack
the vettore size as you defined is 9
int vettore[9];
and in your loop you start from 0 till 9 so you are playing with 10 elements of the array and not 9 (size of the array)
you should define the array with size 10
int vettore[10];
Arrays (i.e. "vectors") start at index zero NOT one; it's contents may be, for example, 5 but it will occupy index locations of 0,1,2,3,4....
[1][2][3][4][5] <- Five items
0 1 2 3 4 <- Their respective locations in the array
Same goes for visualizing characters in strings.....(technically the location in memory contains ASCII value-- look into that for fun ;) )
['c']['a']['t'] <- Three items
0 1 2 <- Their index location in the array
I suggest Kochan's C Programming book; great for starting out!!!

Resources