why do I have a runtime #2 failure in C when I have enough space and there isn't many data in the array - c

I'm writing this code in C for some offline games but when I run this code, it says "runtime failure #2" and "stack around the variable has corrupted". I searched the internet and saw some answers but I think there's nothing wrong with this.
#include <stdio.h>
int main(void) {
int a[16];
int player = 32;
for (int i = 0; i < sizeof(a); i++) {
if (player+1 == i) {
a[i] = 254;
}
else {
a[i] = 32;
}
}
printf("%d", a[15]);
return 0;
}

Your loop runs from 0 to sizeof(a), and sizeof(a) is the size in bytes of your array.
Each int is (typically) 4-bytes, and the total size of the array is 64-bytes. So variable i goes from 0 to 63.
But the valid indices of the array are only 0-15, because the array was declared [16].
The standard way to iterate over an array like this is:
#define count_of_array(x) (sizeof(x) / sizeof(*x))
for (int i = 0; i < count_of_array(a); i++) { ... }
The count_of_array macro calculates the number of elements in the array by taking the total size of the array, and dividing by the size of one element.
In your example, it would be (64 / 4) == 16.

sizeof(a) is not the size of a, but rather how many bytes a consumes.
a has 16 ints. The size of int depends on the implementation. A lot of C implementations make int has 4 bytes, but some implementations make int has 2 bytes. So sizeof(a) == 64 or sizeof(a) == 32. Either way, that's not what you want.
You define int a[16];, so the size of a is 16.
So, change your for loop into:
for (int i = 0; i < 16; i++)

You're indexing too far off the size of the array, trying to touch parts of memory that doesn't belong to your program. sizeof(a) returns 64 (depending on C implementation, actually), which is the total amount of bytes your int array is taking up.
There are good reasons for trying not to statically declare the number of iterations in a loop when iterating over an array.
For example, you might realloc memory (if you've declared the array using malloc) in order to grow or shrink the array, thus making it harder to keep track of the size of the array at any given point. Or maybe the size of the array depends on user input. Or something else altogether.
There's no good reason to avoid saying for (int i = 0; i < 16; i++) in this particular case, though. What I would do is declare const int foo = 16; and then use foo instead of any number, both in the array declaration and the for loop, so that if you ever need to change it, you only need to change it in one place. Else, if you really want to use sizeof() (maybe because one of the reasons above) you should divide the return value of sizeof(array) by the return value of sizeof(type of array). For example:
#include <stdio.h>
const int ARRAY_SIZE = 30;
int main(void)
{
int a[ARRAY_SIZE];
for(int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = 100;
// I'd use for(int i = 0; i < ARRAY_SIZE; i++) though
}

Related

How to reduce the reserved memory that is not currently being used in an array in C?

Let's say we reserved 32 bytes for an array in C, but it turns out we are only using 24 bytes, how can I reduce the reserved memory that is not currently in use? Is this even possible?
I am not using malloc, but I could.
This is the working minimal reproducible example:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
FILE *input;
input = fopen("1.txt", "r");
int arr[4][300];
if (input == NULL) {
printf( "ERROR. Coundn't open the file.\n" ) ;
} else {
for (int i = 0; i < 300; i++) {
fscanf(input, "%d %d %d %d", &arr[0][i], &arr[1][i],
&arr[2][i], &arr[3][i]);
}
fclose(input);
int sze = 0;
for (int i = 0; i < 300; i++) {
for (int j = 0; j < 4; j++) {
if (abs(arr[j][i]) >= 1)
sze += log10(abs(arr[j][i])) + 1;
else
sze++;
if (arr[j][i] < 0)
sze++;
}
}
printf("Size %d kB\n", sze);
}
return 0;
}
Clarification: What I need is to reduce the memory used by each element in the array, if possible. Let's say I have the number 45 stored, it doesn't take up all 4 bytes of an int, so I need to reduce the memory allocated to only 1 byte. As I said, I am not currently using malloc, but I could switch to malloc, if there's a way to what I want to.
If you want to reduce the used space for a value, you need to assign it to an object of different type.
In your example, you start with an int that probably uses 4 bytes on your system. Then you store the value "45" in it, which needs just one byte. Types with size of 1 byte are for example int8_t or signed char.
First, you cannot change the type of a variable, once it is defined. You may store it in another variable.
Second, all elements of an array have to be of the same type.
So the answer for the given example is simply "No."
If you want to "compress" the stored values, you need to roll your own type. You can invent some kind of "vector" that stores each value in as few bytes as necessary. You will need to store the size of each value, too. And you will need to implement access function to each vector element. This is not a simple task.

Why am I geting floating point exception?

This program worked fine when i manually iterated over 5 individual variables but when I substituted them for those arrays and for loop, I started getting floating point exceptions. I have tried debugging but i can't find were the error comes out from.
#include <stdio.h>
int main(void) {
long int secIns;
int multiplicadors[4] = {60, 60, 24, 7};
int variables[5];
int i;
printf("insereix un aquantitat entera de segons: \n");
scanf("%ld", &secIns);
variables[0] = secIns;
for (i = 1; i < sizeof variables; i++) {
variables[i] = variables[i - 1]/multiplicadors[i - 1];
variables[i - 1] -= variables[i]*multiplicadors[i - 1];
}
printf("\n%ld segons són %d setmanes %d dies %d hores %d minuts %d segons\n", secIns, variables[4], variables[3], variables[2], variables[1], variables[0]);
return 0;
}
The problem is you're iterating past the ends of your arrays. The reason is that your sizeof expression isn't what you want. sizeof returns the size in bytes, not the number of elements.
To fix it, change the loop to:
for (i = 1; i < sizeof(variables)/sizeof(*variables); i++) {
On an unrelated note, you might consider changing secIns from long int to int, since it's being assigned to an element of an int array, so the added precision isn't really helping.
Consider this line of code:
for (i = 1; i < sizeof variables; i++) {
sizeof isn't doing what you think it's doing. You've declared an array of 5 ints. In this case, ints are 32-bit, which means they each use 4 bytes of memory. If you print the output of sizeof variables you'll get 20 because 4 * 5 = 20.
You'd need to divide the sizeof variables by the size of its first element.
As mentioned before, sizeOf returns the size of bytes the array holds.
Unlike java's .length that returns the actual length of the array. Takes a little bit more of knowledge with bytes when it comes to C.
https://www.geeksforgeeks.org/data-types-in-c/
This link tells you a bit more about data types and the memory(bytes) they take up.
You could also do sizeOf yourArrayName/sizeOf (int). sizeOf(datatype) returns the size of bytes the data type takes up.
sizeof will give the size (in bytes) of the variables and will yield different results depending on the data type.
Try:
for (i = 1; i < 5; i++) {
...
}

Do arrays in C have a maximum index size of 2048?

I've written a piece of code that uses a static array of size 3000.
Ordinarily, I would just use a for loop to scan in 3000 values, but it appears that I can only ever scan in a maximum of 2048 numbers. To me that seems like an issue with memory allocation, but I'm not sure.
The problem arises because I do not want a user to input the amount of numbers they intend to input. They should only input whatever amount of numbers they want, terminate the scan by inputting 0, after which the program does its work. (Otherwise I would just use malloc.)
The code is a fairly simple number occurrence counter, found below:
int main(int argc, char **argv)
{
int c;
int d;
int j = 0;
int temp;
int array[3000];
int i;
// scanning in elements to array (have just used 3000 because no explicit value for the length of the sequence is included)
for (i = 0; i < 3000; i++)
{
scanf("%d", &array[i]);
if (array[i] == 0)
{
break;
}
}
// sorting
for(c = 0; c < i-1; c++) {
for(d = 0; d < i-c-1; d++) {
if(array[d] > array[d+1]) {
temp = array[d]; // swaps
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
int arrayLength = i + 1; // saving current 'i' value to use as 'n' value before reset
for(i = 0; i < arrayLength; i = j)
{
int numToCount = array[i];
int occurrence = 1; // if a number has been found the occurence is at least 1
for(j = i+1; j < arrayLength; j++) // new loops starts at current position in array +1 to check for duplicates
{
if(array[j] != numToCount) // prints immediately after finding out how many occurences there are, else adds another
{
printf("%d: %d\n", numToCount, occurrence);
break; // this break keeps 'j' at whatever value is NOT the numToCount, thus making the 'i = j' iterator restart the process at the right number
} else {
occurrence++;
}
}
}
return 0;
}
This code works perfectly for any number of inputs below 2048. An example of it not working would be inputting: 1000 1s, 1000 2s, and 1000 3s, after which the program would output:
1: 1000
2: 1000
3: 48
My question is whether there is any way to fix this so that the program will output the right amount of occurrences.
To answer your title question: The size of an array in C is limited (in theory) only by the maximum value that can be represented by a size_t variable. This is typically a 32- or 64-bit unsigned integer, so you can have (for the 32-bit case) over 4 billion elements (or much, much more in 64-bit systems).
However, what you are probably encountering in your code is a limit on the memory available to the program, where the line int array[3000]; declares an automatic variable. Space for these is generally allocated on the stack - which is a chunk of memory of limited size made available when the function (or main) is called. This memory has limited size and, in your case (assuming 32-bit, 4-byte integers), you are taking 12,000 bytes from the stack, which may cause problems.
There are two (maybe more?) ways to fix the problem. First, you could declared the array static - this would make the compiler pre-allocate the memory, so it would not need to be taken from the stack at run-time:
static int array[3000];
A second, probably better, approach would be to call malloc to allocate memory for the array; this assigns memory from the heap - which has (on almost all systems) considerably more space than the stack. It is often limited only by the available virtual memory of the operating system (many gigabytes on most modern PCs):
int *array = malloc(3000 * sizeof(int));
Also, the advantage of using malloc is that if, for some reason, there isn't enough memory available, the function will return NULL, and you can test for this.
You can access the elements of the array in the same way, using array[i] for example. Of course, you should be sure to release the memory when you've done with it, at the end of your function:
free(array);
(This will be done automatically in your case, when the program exits, but it's good coding style to get used to doing it explicitly!)

Getting the size of my array

I am trying to get the size of my array but am having no luck...
I've read from various other threads that the way to grab the size of an array is:
theSize = (sizeof(array) / sizeof(array[0]))
But that seems to grab the empty elements of the array too.
How would we grab just the elements that are used up... for example:
char array[200][40];
for (i = 1; i < (sizeof(array) / sizeof(array[0])); i++) {
printf("%s", array[i-1]);
The output for an array that used 3 of its 200 elements would be...
First
Second
Third
(This is where it should stop, however it gives a bunch of question marks,
so I assume I'm grabbing memory i'm not supposed to use.
Note: I want it so that i < 3 for the loop (since the array has 3 elements used up)
There are two ways to do this.
The first way is to keep track of how many elements are used in a separate variable. Note that you must ensure that used is always less than of equal to the size of the array.
char array[200][40];
size_t used = 3;
for (int i = 0; i < used; ++i) {
printf("%s", array[i]);
}
The second way is to flag the first unused element with a special value, such as 0, and output all values until the flagged one. In your case, it would be natural to mark the end of the array with an empty string.
char array[200][40];
size_t size = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < size && array[i][0] != 0; ++i) {
printf("%s", array[i]);
}

Does making the iterator a pointer speed up a C loop?

I ran the following:
#include <stdio.h>
typedef unsigned short boolean;
#define false 0
#define true (!false)
int main()
{
int STATUS = 0;
int i = 0;
boolean ret = true;
for(i = 0; i < 99999; i++)
{
ret = ret && printf("Hello, World.");
}
if(!ret)
{
STATUS = -1;
}
return STATUS;
}
It completes in just under a second. Typically 0.9 - 0.92.
Then I changed int i = 0; to int *i = 0; and now I am getting execution times under 0.2 seconds. Why the speed change?
Your runtime is dominated by the time required to print to the console. i++ on an int* will increment the pointer by the size of a pointer. That will be either 4 or 8 depending on your computer and compiler settings. Based on the numbers you report, presumably it would be 4. So printf is executed only a quarter as many times.
Typically, printing to a console will be several orders of magnitude larger than any gain with micro optimization you could do to such a loop.
Are you really sure your second version prints hello world 99999 times as well ?
When you're doing for(int *i = 0; i++ ; i < 99999 ) , you're cheking if the pointer value(an address) is less than 99999, which doesn't normally make a lot of sense. Incrementing a pointer means you step it up to point at the next element, and since you have an int*, you'll increment the pointer by sizeof(int) bytes.
You're just iterating 99999/sizeof(int) times.
Your comment on nos's answer confirmed my suspicion: it's pointer arithmetic. When you increment an int pointer using ++, it doesn't just add one to the number, but it actually jumps up by the size of an integer, which is usually 4 (bytes). So i++ is actually adding 4 to the numeric value of i.
Similarly, if you use += on a pointer, like i += 5, it won't just add 5 (or whatever) to the numeric value of i, it'll advance i by the size of that many integers, so 5*4 = 20 bytes in that case.
The reasoning behind this is that if you have a chunk of memory that you're treating as an array,
int array[100]; // for example
you can iterate over the elements in the array by incrementing a pointer.
int* i = array;
int* end = array + 100;
for (i = array; i < end; i++) { /* do whatever */ }
and you won't have to rewrite the loop if you use a data type of a different size.
The reason is because the increment operates differently on pointers.
On ints, i++ increments i by 1.
For pointers, i++ increments by the size of the pointed-to object, which will be 4 or 8 depending on your architecture.
So your loop runs for only 1/4 or 1/8 of the iteration count when i is a pointer vs when i is an int.
The correct way to do this test with a pointer would be something like:
int i;
int *i_ptr = &i;
for (*i_ptr = 0; *i_ptr < 99999; *i_ptr++) {
...

Resources