This question already has answers here:
Resizing an array with C
(3 answers)
Closed 5 years ago.
#define n 10
int a[n];
I wanted to declare an array globally and modify the size in other function
int main(){
int b;
printf("Enter the number of elements\n");
scanf("%d",&b);
#undef n
#define n b
for(int i = 0;i < n; i++)
scanf("%d",&a[i]);
display();
}
I modified the size in the main function
void display()
{
for(int i=0;i<n;i++)
printf("%d ",a[i]);
}
when i enter a size like 5 and enter the elements 1 2 3 4 5
the output shows 5 elements followed by 5 zeroes 1 2 3 4 5 0 0 0 0 0
how to remove the zeroes?
You can't. Once you declare an array you can't change it's size. As an alternative you can emulate this behavior perfectly using a pointer and then allocating dynamically memory and assigning the chunk address to this pointer. You can then realloc memory to incorporate this size change.
It will be something like:-
size_t sz = 10;
int *arr = malloc(sizeof *arr * sz); // sizeof(*arr)*sz (sizeof is operator)
if(!arr){
perror("malloc");
exit(1);
}
...
sz/=2; //correcting the size
int *p =realloc(arr,sizeof *arr * sz);
if(!p){
perror("realloc");
exit(1);
}
arr = p;
...
free(arr);
Also macro is not a runtime thing - it is expanded at compile time. And more over you want the array to be resized in run time not compile time. Otherwise you can set the array size to be that size from the very beginning when you wrote the code. That's why macro won't work here.
Note that arr here is not an array - it is a pointer pointing to an allocated memory (the starting address of the memory chunk that was created using malloc). Nothing else.
What you did was just changing a preprocessor constant. They are evaluated at compile time, so your redefinition is effectively pointless and takes no effect.
Not sure what you're trying to achieve here, since this array is not going to be reallocated. If you only want to limit the amount of entries you are iterating through, ditch your n and replace it with something like:
static const size_t n = 10;
static size_t num_entries = n;
Then instead of redefining n, you should just do
num_entries = b;
and later on use this to iterate through the array. However, do note that this does not reallocate the array so things are going to go terribly wrong if b is bigger than n!
If you want to reallocate the array, you're better off reading up about malloc, realloc and free. As well as some fundamental tutorials about C in the meantime, since basing on your misunderstanding of what preprocessor (#define'd variables) are, you most likely just started with C.
Related
I tried to find similar title questions with mine, but I didn't find what I wanted. So here is my question.
If I malloc an array with size of 10, is it able to realloc the size and make it 9? And the 8 etc etc ? And if it's able, if I have this array:
[1,2,3,4,5,6,7,8,9,10] How can I know which cell will be deleted ? Is it able to choose which one to delete every time ?
When you realloc with a smaller size, many implementation just do nothing: you have a bloc that can hold at least 10 elements, it can hold at least 8 elements. Simply you shall no longer use the elements past the declared size. Nothing will prevent you to do it, but it just invokes Undefined Behaviour.
It can be surprising for beginners:
int *arr = malloc(10 * sizeof(int)); // allocate an array of 10 int
for (int i=0; i<10; i++) { // initialize it with 0-9
arr[i] = i;
}
arr = realloc(arr, 8*sizeof(int)); // realloc the array to 8 elements
for (int i=0, i<8; i++) {
printf(" %d", i);
}
printf("\n"); // should have correctly printed 0 1 ... 7
// the interesting part
for (int i=8; i<10; i++) {
printf(" %d", i); // Oops, UB!
}
printf("\n"); // but what is to be expected is just 8 9...
Now it works but is UB. Say differently never pretend that I said that it was correct code. But most implementations will accept it and will give the expected result (which is allowed by UB...) without any other side effect.
The realloc() and reallocarray() functions serve this purpose.
The method header is actually:
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
Where *ptr is the pointer to the memory that you want to reallocate.
However, you can't choose. If you increase the size, the old elements will remain as they are, and there will be some elements at the end that are undefined (null). If you decrease it, the memory space will be "cut", that means, if you have space for 10 elements, and you realloc for 6, the last 4 elements will not be accessible.
If you want to achieve that behaviour, arrange your array before reallocating
Much more information can be found in the man pages (enter link description here) and in several websites.
If I'm trying to create a global array to hold an arbitrary number of integers in this case 2 ints. How is it possible that I can assign more numbers to it if I only allocate enough space for just two integers.
int *globalarray;
int main(int argc, char *argv[]) {
int size = 2;
globalarray = malloc(size * sizeof(globalarray[0]));
// How is it possible to initialize this array pass
// the two location that I allocated.
for (size_t i = 0; i < 10; i++) {
globalarray[i] = i;
}
for (size_t i = 0; i < 10; i++) {
printf("%d ", globalarray[i]);
}
printf("%s\n", "");
int arrayLength = sizeof(*globalarray)/sizeof(globalarray[0]);
printf("Array Length: %d\n", arrayLength);
}
When I run this it gives me
0 1 2 3 4 5 6 7 8 9
Array Length: 1
So I wanted to know if someone could clarify this for me.
(1) Am I creating the global array correctly?
(2) Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
And background info on why I want to know this is because I want to create a global array (shared array) so that threads can later access the array and change the values.
How is it possible to initialize this array pass the two location that I allocated.
Short answer: This is undefined behaviour and anything can happen, also the appearance that it worked.
Long answer: You can only initialize the memory you've allocated, it
doesn't matter that the variable is a global variable. C doesn't prevent you from
stepping out of bounds, but if you do, then you get undefined behaviour and anything can happen
(it can "work" but it also can crash immediately or it can crash later).
So if you know that you need 10 ints, then allocate memory for 10 int.
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
}
And if you later need more, let's say 15, then you can use realloc to increase
the memory allocation:
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
// do not contiue
}
....
// needs more space
int *tmp = realloc(globalarray, 15 * sizeof *globalarray);
if(tmp == NULL)
{
// error handling
// globalarray still points to the previously allocated
// memory
// do not continue
}
globalarray = tmp;
Am I creating the global array correctly?
Yes and no. It is syntactically correct, but semantically it is not, because you are
allocating space for only 2 ints, but it's clear from the next lines that
you need 10 ints.
Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
That's because
sizeof(*globalarray)/sizeof(globalarray[0]);
only works with arrays, not pointers. Note also that you are using it wrong in
two ways:
The correct formula is sizeof(globalarray) / sizeof(globalarray[0])
This only works for arrays, not pointers (see below)
We sometimes use the term array as a visual representation when we do stuff
like
int *arr = malloc(size * sizeof *arr)
but arr (and globalarray) are not arrays,
they are pointers. sizeof returns the amount in bytes that the
expression/variable needs. In your case *globalarray has type int and
globalarray[0] has also type int. So you are doing sizeof(int)/sizeof(int)
which is obviously 1.
Like I said, this only works for arrays, for example, this is correct
// not that arr here is not an array
int arr[] = { 1, 2, 3, 4 };
size_t len = sizeof arr / sizeof arr[0]; // returns 4
but this is incorrect:
int *ptr = malloc(4 * sizeof *ptr);
size_t len = sizeof ptr / sizeof ptr[0]; // this is wrong
because sizeof ptr does not returns the total amount of allocated
bytes, it returns the amount of bytes that a pointer needs to be stored in memory. When you are dealing with
pointers, you have to have a separate variable that holds the size.
C does not prevent you from writing outside allocated memory. When coding in C it is of the utmost importance that you manage your memory properly.
For your second question, this is how you would want to allocate your buffer:
globalarray = malloc(sizeof(int) * size);
And if you are on an older version of C than c11:
globalarray = (int*) malloc(sizeof(int) * size);
I'm having some trouble with using the malloc/realloc command with arrays. I've created a small array with some integers in it, and tried to add one value to it by expanding the size with realloc and adding the value, but when I do that the 0 index's value is not preserved and is seen as garbage.
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
printf("Enter size of array\n");
scanf("%d",&n);
int *A = malloc(n*sizeof(int));
for(int i = 0; i < n; i++){
A[i] = i + 1;
}
*A = realloc(A, sizeof(A)+ sizeof(int));
A[n] = 1234;
for(int i = 0; i < n + 1; i++){
printf("%d\n",A[i]);
}
return 0;
}
and when i run the program this happens:
Enter size of array
5
14643216
2
3
4
5
1234
Does anyone know why the 0 index of the array is getting this value and not 1?
$ gcc a.c
a.c: In function ‘main’:
a.c:12:12: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
*A = realloc(A, sizeof(A)+ sizeof(int));
^
Make sure to configure your compiler to emit warnings on code that looks suspicious. Any remotely decent compiler would raise at least a warning, if not an error, on this line. realloc returns a pointer, which you're trying to assign to an int object.
You need to assign the resulting pointer to A, not *A. Furthermore, there's another error, which compilers can't warn you about. sizeof(A)+ sizeof(int) is too small, and does not make much sense in context. Note that sizeof(A) is the size of the pointer A. There's no way to use sizeof to find the number of items in the array that A points to, because sizeof relies on compile-time information. To extend the array by one element, you need to add sizeof(int) to the current allocated size, which is n*sizeof(int), i.e. the new size should be (n+1) * sizeof(int).
In addition, it would be better to use sizeof(*A) than sizeof(int). The two are equivalent, but sizeof(*A) has the advantage that it'll still be correct if you decide to change the array elements, e.g. to make them long.
A = realloc(A, (n+1) * sizeof(*A));
Write A = realloc(A, (n + 1) * sizeof(int)); instead of *A = realloc(A, sizeof(A)+ sizeof(int));
*A = ... will overwrite the value of the first index with a "address value" if A is not moved to another place in memory (undefined behaviour otherwise).
Note that sizeof(A) is a constant value (probably 8, and not the amount of memory allocated previously), such that you had a good chance that realloc did not move the memory.
I run in a problem with a program and I'm not sure how to solve it. I'm processing a file and to do so I get the size with ftell and store it in M_size. After that I declare a unsigned char pointer array with N. The array is then used in two functions a() and b().
...
unsigned long N = (M_size/ x);
int LstElemSize = M_size % x;
if(LstElemSize != 0){
N += 1;
}
unsigned char *ptr_M[N]
a(ptr_M)
b(ptr_M)
...
Function a() actually initializes each element of ptr_M in a for loop:
a(){
int i;
for(i = 0; i < N-1; i ++){
ptr_M[i] = malloc(sizeof(unsigned char) * x);
}
}
Function b() iterates then over each element and calculates stuff and at the end each element is freed.
My problem is now that when I try to process a file e.g. 1 GB the array size will be around 4 000 000 and a Segmentation error occurs (In the line i declare my array). If I calculated it correctly that is 8 byte (char pointer) times 4 000 000 = 32MB. The server running the program has enough memory to hold the file, but i guess as mentioned in Response 1 the stack space is not enough.
What can I do to solve my problem? Increase my stack space? Thanks!
The problem is that you're defining ptr_M in the stack, which has a small size limit. The heap does not have such a small size limit and is able to use more of your system's memory. You need to use malloc() to allocate ptr_M just like you allocate the subarrays. (Make sure to free it at some point too along with all those subarrays!)
unsigned char **ptr_M = malloc(sizeof(unsigned char*) * N);
Also, your a() has an off-by-one error. It ignores the last item of the array. Use this:
for(i = 0; i < N; i ++){
unsigned char *ptr_M[N] is a variable-length array declaring N number of unsigned char on the stack in your case. You should dynamically allocate the space for the array as well.
unsigned char **ptr_M = malloc(sizeof(unsigned char*) * N);
a(ptr_M);
b(ptr_M);
...
//After you free each element in ptr_M
free(ptr_M);
malloc allocates space from heap, not from stack. You may try increasing your heapsize looking at the compiler option. Check the upper limit of heapsize that is supported there.
I am new to C and was writing a function to insert an element to sorted list. But my code does not display the last digit correctly. Though i know there are variety of ways to correct it but i want to know why my code isnt working, here's the code
#include <stdio.h>
int insert(int array[],int val);
int main (void)
{
int arr[5],j;
for (j = 0; j<5; j++)
{
scanf("%d",&arr[j]);
}
insert(arr,2);
for(j = 0;j<6;j++)
printf("%d",arr[j]);
return(0);
}
int insert(int array[],int val)
{
int k,i;
for (k = 0;k<5;k++)
if(val<array[k])
break;
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
}
array[k] = val;
return(1);
}
You are writing out of the range of the array here:
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
Where i+1 == 5 and you array has a range of 0 ...
4
Then you try to print the array but you go out of bounds again:
for(j = 0;j<6;j++)
printf("%d",arr[j]);
First make sure your array is large enough.
When you give a static / auto array to a function for insertion of elements, you must give: Address, Valid length, and Buffer Space unless guaranteed large enough.
When giving a dynamically allocated array, you must give pointer and valid length, you might give buffer space or guarantee enough space left to avoid reallocations.
Otherwise, you risk a buffer overrun, and UB means anything may happen, as in your example.
You're trying to make arr[6] out of arr[5] adding one val - it's impossible in C using statically allocated arrays.
To accomplish what you're trying to do you'd need to use dynamical arrays allocation:
int *arr;
int N = 5;
arr = (int *)malloc(N*sizeof(int));
then you use this arr same way as you did with arr[5] for loading data here via scanf.
And later on , while adding extra value to array - you'd need to reallocate your arr to make it bigger (read about malloc/realloc C functions):
arr = (int *)realloc((N+1)*sizeof(int));
Now your arr is of 6 int-s size.
Unfortunately if you don't know array sizes (number of elements) a priori you would need to deal with dynamical memory allocations in C.
Don't forget to release that memory in the end of the main() function:
free(arr);
You have to increase your array size from 5 to 6 as you are inserting one new element in your array, so there should be some space for that.
int arr[6];
you can also find more information in the link below:
https://learndswithvishal.blogspot.com/2020/06/insert-element-in-sorted-array.html