How to realloc based on size of array? - c

Say you malloc enough memory space to hold an array of size 20. The program is running and now I need enough memory for an array of size say 40. I tried to do this using realloc but it doesn't seem to be working. My code is the following(I'm trying to find the sum of all even-valued fibonacci terms below 4million):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
int i,sum,size;
int *fibo;
size = 20; //initial size of array
fibo = (int *) malloc(size*sizeof(int));
fibo[0]=1;
fibo[1]=1;
i=2;
sum=0;
while(fibo[i-1]<4000000){
fibo[i] = fibo[i-1]+fibo[i-2];
printf("fibo[%d] = %d\n", i, fibo[i]);
if(fibo[i]%2 == 0){
sum+= fibo[i];
}
i++;
if(i>size){
fibo = (int *) realloc(fibo, (size *= 2)*sizeof(int));
}
}
printf("Sum = %d\n", sum);
return 0;
}
Anyone know why realloc is failing, and how I can fix it?

During the last iteration, i equals 20 but the expression
if(i>size)
is false, so you do not actually use realloc, then by writing to
fibo[20]
the program is accessing part of the memory that does not belong to it. Changing the expression to
if(i>=size)
should fix it :)

Related

Why can't I see any change in used memory when I run my program?

I have written a program to allocate some memory as given by cmd line argument. It creates an array to consume some amount of memory, and it goes through the array for 30 seconds.
When I run it, I cant see any change in memory usage(edit: I didnt mean gradual change of memory usage, the problem was no memory was initialized due to a missing line of code) of the program. I have tried this both in Windows using Task Manager and in Linux with free() utility.
I am a beginner in C so I am afraid that I might be missing something basic. I thank you for your time to look into this and appreciate your help.
Edit: I for some reason deleted what C was meant to be. Feeling stupid now.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char* argv[]) //for getting cmd line arg of size in MB
{ int d=atoi(argv[1]), b=0, c=0, i=0; //store the value into an integer
b=d*1024*1024; //convert MB to B
/*initially missing line below, this fixes the original issue*/
c=b/4; //int being 4 bytes each elements will be 1/4th of total B
/*missing line ends*/
printf("value passed to array size\n- %d",b); //show total size to allocate in B
int *num = (int *)malloc(b); //allocating b bytes
time_t sec = 30; //setting timer to 30secand then looping for said time
time_t startT=time(NULL);
while (time(NULL) - startT < sec)
{
for(i=0;i<c;i++) //going through each entry in the array and assigning it its position as value
{
num[i]=i;
}
}
}
To see increased memory consumption increase you allocate some memory every iteration:
int main(int argc, char *argv[])
{
size_t size = atoi(argv[1]);
printf("value passed to array size %zu\n", size);
int *num = NULL;
time_t sec = 30;
time_t startT=time(NULL);
while (time(NULL) - startT < sec)
{
int *tmp = realloc(num, size * 1024 *1024);
if(!tmp)
{
free(num);
break;
}
num = tmp;
for(size_t i=0; i< size * 1024 *1024 / sizeof(*num);i++)
{
num[i]=i;
}
size *= 2;
}
}

Simple question on pointers and how to initialize an array in C

I have a question on a simple program that i wrote to initialize an array one element at a time, the few lines of code are below:
#include <stdio.h>
int main(void)
{
int *ptr;
int index;
for (index = 0; index < 4; index++)
{
ptr[index]=index;
printf("%d\n", ptr[index]);
}
return 0;
}
All plain and simple but when I run the program I incur in segmentation fault (core dumped) error, that to my understanding occurs when you try to write on something that is only readeable or if you have exceeded your allowed memory...
Excuse me for this probably nobbish question but I could not find a similar question on SO.
You cannot just use int *ptr and treat it as an array. You need to actually create an array and allocate space for it, by specifying the size. You can either make it as an array like in the first option, or allocate it using malloc() in the second option. I suggest the first one because it executes faster, and it seems your array is of fixed length. The second option is for applications where you do not know the array size until runtime.
#include <stdio.h>
int main(void)
{
int ptr[4]; //you need to specify array size first
int index;
for (index = 0; index < 4; index++)
{
ptr[index]=index;
printf("%d\n", ptr[index]);
}
return 0;
}
You can also use malloc() if you want to allocate it on the heap, but make sure to free() it, to free the memory, or there will be a memory leak.
#include <stdio.h>
int main(void)
{
int *ptr = malloc(4*sizeof(int));
int index;
for (index = 0; index < 4; index++)
{
ptr[index]=index;
printf("%d\n", ptr[index]);
}
free(ptr);
return 0;
}
This should solve your problem
Also you don't need a for loop to initialize populate the values of the array, in case that is what you are trying to do. You can do this:
int ptr[4] = {0, 1, 2, 3};
As stated in #ChristianGibbons comment, you just need to allocate memory for the array the address of your pointer.
#include <stdio.h>
int main(void)
{
int sizeOfArray = 4;
int *ptr = calloc(sizeOfArray, sizeof(int)); // line to fix
int index;
for (index = 0; index < sizeOfArray; index++)
{
ptr[index]=index;
printf("%d\n", ptr[index]);
}
free(ptr);
return 0;
}

Segmentation fault when trying to add elements of an array

I'm trying to create a function that returns as its result the sum of the elements in the array. When I try to run the program, I get a segmentation fault. Could someone please point me in the right direction? Thank you!
int arraySum (int array[], int numberOfElements) {
int result = 0;
for (int i = 0; i < numberOfElements; i++)
{
result += array[i];
}
return result;
}
int main (void) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
printf("\nPlease list the values of the elements in the array: ");
for (int i = 0; i < numberOfElements; i++)
{
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
return result;
}
The problem you have is, that in C you need to manually allocate the memory if you are using a pointer instead of say a fixed-size array.
This is usually done by calling malloc, which will return a void-pointer (void*), which you need to cast to the desired type (in your case (int*)) before assigning it.
It is also important to note, that, when using malloc, you need to specify the amount of Bytes you want to allocate. This means that you can't just call it with the number of integers you want to store inside, but rather have to multiply that number with the amount of Bytes that one integer occupies (which depends on the Hardware and Operating System you use, hence you should use sizeof(int) for that purpose, which evaluates to that size at compile time).
I modified your code with a working example of how it could be done:
#include <stdio.h>
#include <stdlib.h>
int arraySum (int array[], int numberOfElements) {
int result = 0;
int i;
for (i = 0; i < numberOfElements; i++) {
result += array[i];
}
return result;
}
int main(int argc, char **argv) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
array = (int*) malloc(numberOfElements * sizeof(int));
printf("\nPlease list the values of the elements in the array: ");
int i;
for (i = 0; i < numberOfElements; i++) {
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
printf("\n\nThe result is: %d\n", result);
return 0;
}
You are also trying to return the result in your main function, but the return value of main in C is used to signal whether your program terminated without errors (signalled by a return value of 0) or didn't encounter any issues (any value other than 0).
You need to allocate memory. It is not enough to just declare a pointer. You do it like this: array=malloc(numberOfElements*sizeof(*array));
Also, although it is possible to return result from the main function, you should not do that. The return value from main is usually used for error checking. Change the end of your program to
printf("Sum: %d\n", result);
return 0;
Returning 0 usually means that no error occurred.

Seg Fault when accessing an array initialised with malloc

Below is a simplified extract of a program I'm writing. I'm having issues accessing elements towards the end of the array.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int n, char *args[n]){
// create 4D array scores[10000][100][100][100] on heap
uint64_t arraySize = 1; // this avoids overflow
arraySize *= 10000;
arraySize *= 100;
arraySize *= 100;
arraySize *= 100;
int (*scores)[10000][100][100] = malloc(arraySize);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 100; j++) {
printf("%d, %d, %d\n", i, j, scores[i][j][0][0]);
}
}
}
The program loops through the 4D array score and as a test I'm printing the contents of the array. The loop starts off as planned, printing in the format "i, j, 0" for each i and j, until the last success "25, 0, 0".
From this point on I get random numbers rather than 0, starting with "25, 1, 1078528" up until "25, 45, 1241744152" which is then followed by "Segmentation fault (core dumped)".
After fiddling around I found the first non-zero array member to be scores[25][0][7][64].
So I guess I'm running out of space and so am accessing memory I shouldn't be? If anyone knows or has an idea as to how I could fix this I'd really appreciate it.
My PC is running Ubuntu 16.10 64bit, has 16GB RAM and 16GB swap
Edit
After implementing the following suggestions I get a return value of "calloc: Cannot allocate memory".
int (*scores)[100][100][100] = calloc(arraySize, sizeof(int));
if (scores == NULL) {
perror("calloc");
return 1;
}
If I comment out the new if statement (and run the for loop) I get an immediate seg fault. This also happens if I use malloc:
int (*scores)[100][100][100] = malloc(arraySize * sizeof(int));
Why could this be? Surely my system has enough memory
Cheers
Check the return value of malloc() and determine if it failed to allocate.
You forgot to multiply the size of int.
The type of result should be int (*)[100][100][100], not int (*)[10000][100][100].
Using value of buffer allocated via malloc() and not initialized invokes undefined behavior, so don't do that.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int n, char *args[n]){
// create 4D array scores[10000][100][100][100] on heap
uint64_t arraySize = 1; // this avoids overflow
arraySize *= 10000;
arraySize *= 100;
arraySize *= 100;
arraySize *= 100;
int (*scores)[100][100][100] = calloc(arraySize, sizeof(int));
if (scores == NULL) {
perror("calloc");
return 1;
}
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 100; j++) {
printf("%d, %d, %d\n", i, j, scores[i][j][0][0]);
}
}
}
Your pointer to a variable length array does not use correct array sizes.
The array is: [10000][100][100][100]
but the pointer is: [100][10000][100][100]
And you need to multiply the array size times the size of the object, in this case size of type int.
The pointer definition should be:
int (*scores)[100][100][100] = malloc(arraySize*sizeof(int));
The allocated elements are not initialized. Reading them will yield indeterminate values.
The correct type to store the size of bytes that need to be allocated, is size_t, not uint64_t.
One of the correct ways to allocate the array is:
const size_t bytes = sizeof( int[10000][100][100][100] );
int (*scores)[100][100][100] = malloc( bytes );
(This of course assumes that size_t can represent that value.)
Did you try:
int (*scores)[10000][100][100] = malloc(sizeof(int)*arraySize);
Bye.

Why won't changing this value work?

So I'm trying to change the value at x[2] from 0 to 8 using a method, the way I have this isn't working. How can I do this? I tried searching around but came to no avail.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void changevar(int* x){
int* y;
y = &x[2];
y = 8;
}
int main(int argc, char** argv){
int* c;
c = (int*) malloc(sizeof(int));
printf("here %d\n", c[2]);
changevar(&c);
printf("here %d\n", c[2]);
free(c);
}
EDIT: I'm new to pointers
You first need to allocate enough space:
c = malloc(3 * sizeof(int));
Notice that I didn't cast the return value.
The values are not initialized to zero. They can be anything ("undefined"). You can clear it with:
memset(c, 0, 3 * sizeof(int));
Next, you'll need to pass this value as is to your function. (It's already a pointer, after all.)
changevar(c);
Within your function, you'll need to dereference the address to access it:
*y = 8;
Those are the errors I see.
So there are two issues that are standing out to me.
You're only allocating memory for one int in your malloc call but trying to access memory that would suggest you allocated a minimum space for 3 ints.
Your function's parameter is supposed to be a int*, however with changevar(&c) you're passing in a int** because you giving the address of a pointer.
To fix these only a couple of changes need to be made...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void changevar(int* x){
x[2] = 8; // <-- can be simplified to this one line
}
int main(int argc, char** argv){
int* c;
int amt = 3; // <-- number of ints you want to be able to have space for
c = malloc(sizeof(int) * amt); // <-- multiply the size and the amount you want
printf("here %d\n", c[2]);
changevar(c); // <-- remove the '&' from the argument to just pass the pointer 'c'
printf("here %d\n", c[2]);
free(c);
}
The output becomes:
here 0
here 8
Garbage values are being printed because size of array c is 1.
c = (int*) malloc(sizeof(int));
will create an array c of size 1.
c[2] is a garbage value. (In most systems, 0 is printed instead of a garbage number.)
Your &c[2] and y do not refer to the same address.
What you want to do is probably this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void changevar(int** x){
*(*x+2)=8;
}
int main(int argc, char** argv){
int* c;
c = (int*) malloc(3*sizeof(int));
for(int i=0;i<3;i++){
c[i]=0;
}
printf("here %d\n", c[2]);
changevar(&c);
printf("\nhere %d\n", c[2]);
free(c);
}
Prints:
here 0
here 8

Resources