So I was just playing around with Array pointers to see how they work, my example below allocates space for 2 array pointers to an array with 10 ints.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int (*p)[10] = malloc(sizeof(int[10]) * 2);
for (int arrayI = 0; arrayI < 2; ++arrayI) {
for (int i = 0; i < 10; ++i) {
p[arrayI][i] = (arrayI+1) * i;
}
}
for (int arrayI = 0; arrayI < 2; ++arrayI) {
for (int i = 0; i < 10; ++i) {
printf("%d\n", p[arrayI][i]);
}
printf("\n");
}
}
This seems to work fine and gives me:
C:\Users\USERNAME\Desktop>gcc -Wall -Wextra --std=c18 a.c && a.exe
0
1
2
3
4
5
6
7
8
9
0
2
4
6
8
10
12
14
16
18
For my question, you rarely see code like this, if at all. Is there anything dangerous with doing things like this or is it just "bad code". And again, this is just me playing around with Array pointers.
Is there anything dangerous with doing things like this or is it just "bad code".
No. This is actually a correct way of making a dynamic allocated 2D array.
Instead of
int (*p)[10] = malloc(sizeof(int[10]) * 2);
I prefer
int (*p)[10] = malloc(2 * sizeof *p);
As p is a pointer to an array of 10 ints, *p is an array of 10 ints.
Many prefer to have an explicit release of memory. It's not required as the program terminates anyway. It's opinion based but I would add:
free(p);
return 0;
at the end of the program.
my example below allocates space for 2 array pointers to an array with 10 ints
No, this is one array pointer int (*p)[10]. This gives 2 arrays: sizeof(int[10]) * 2.
Is there anything dangerous with doing things like this
The only danger is the obscure de-referencing syntax. The most correct way to write your example is this:
int (*p)[2][10] = malloc(sizeof(int[2][10]));
or equivalent
int (*p)[2][10] = malloc(sizeof *p);
But if you do that, you have to write the strange-looking (*p)[i][j] when de-referencing. Therefore we drop the left-most dimension, a "manual array decay", and get a int (*)[10] which is actually a pointer to the first element in a int[2][10] array. If you want, you could also rewrite the code as:
int (*arr)[2][10] = malloc(sizeof *arr);
int (*p)[10] = *arr;
Also, you should always free the allocated memory, since free will often result in a crash in case you have any lurking pointer corruption bugs somewhere in the program.
Related
Have a look at the piece of code below. When I create an array by mallocating space for it I can always resize the array without loss of data. But when I create an array by fully initializing it with int test2[] = {3}; I am unable to realloc. Why is that? This is just a silly example but it presents the problem I am facing well.
I tried referencing test2 in different ways (*, &, **, etc) but at some point I found myself just hoping to magically find the solution without knowing what I was doing anymore.
I have been googling a lot but I cannot seem to find a proper explanation for this or solution that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int *test1 = malloc(1 * sizeof(int));
test1[0] = 1;
test1 = realloc(test1, 2 * sizeof(int));
test1[1] = 2;
for(int i = 0; i < 2; i++)
{
printf("%d\n", test1[i]);
}
int test2[] = {3};
test2 = realloc(test2, 2 * sizeof(int));
test2[1] = 4;
for(int i = 0; i < 2; i++)
{
printf("%d\n", test2[i]);
}
}
Output:
test.c: In function 'main':
test.c:17:8: error: assignment to expression with array type
test2 = realloc(test2, 2 * sizeof(int));
When I remove the code after the first for loop, the program compiles and executes nicely as it should.
The declaration int test2[] = {3}; does not create memory that can be later either freed or re-allocated! Rather, it defines an array of fixed length, most likely 'created' on the stack.
A call to malloc, on the other hand, allocates the requested amount of memory from the heap (essentially, a large pool of memory available to your running program); this memory 'chunk' can later be re-sized with realloc and must be released (when you're done with it) by calling free.
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.
Probably I just lack understanding of how malloc works, but I don't see an error with my code:
int amount_integers = 2;
int *pointer_to_allocated_memory = (int*)malloc(amount_integers * sizeof(int));
for (int i = 0; i < amount_integers; i++)
{
int *address = &(pointer_to_allocated_memory)[i * sizeof(int)];
*(address) = 0;
}
I'd like to initialize memory for an arbitrary amount of integers (amount_integers could be something else than 2). However, the malloc in line 2 seems to misfunction. MSVC's debugger will break at this point (without having defined a breakpoint). When continuing, it will encounter an access writing violation at line 6 (*(address) = 0;) when i is 1.
What I think I'm accessing:
v pointer_to_allocated_memory[0 * sizeof(int)]
... | sizeof(int) | sizeof(int) |
^ pointer_to_allocated_memory[1 * sizeof(int)]
These should be allocated. Why does the application crash?
The array index is not indexing bytes but array elements, in your case ints:
int *address = &(pointer_to_allocated_memory)[i];
valid values for i are 0 and 1
Because you misunderstand how pointer arithmetic works. It doesn't work with bytes, it works with chunks of memory of sizeof(T) bytes, T being the pointer's pointed type. So
int *address = &(pointer_to_allocated_memory)[i * sizeof(int)];
should be
int *address = &ptr[i];
instead. (Also note the lack of superfluous parenthesizing and simpler name...)
By the way, casting malloc is harmful.
I want to create an integer pointer p, allocate memory for a 10-element array, and then fill each element with the value of 5. Here's my code:
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
*p = 5;
printf("Current value of array: %p\n", *p);
*p += sizeof(int);
i += sizeof(int);
}
I've added some print statements around this code, but I'm not sure if it's actually filling each element with the value of 5.
So, is my code working correctly? Thanks for your time.
First:
*p += sizeof(int);
This takes the contents of what p points to and adds the size of an integer to it. That doesn't make much sense. What you probably want is just:
p++;
This makes p point to the next object.
But the problem is that p contains your only copy of the pointer to the first object. So if you change its value, you won't be able to access the memory anymore because you won't have a pointer to it. (So you should save a copy of the original value returned from malloc somewhere. If nothing else, you'll eventually need it to pass to free.)
while (i < sizeof(array)){
This doesn't make sense. You don't want to loop a number of times equal to the number of bytes the array occupies.
Lastly, you don't need the array for anything. Just remove it and use:
int *p = malloc(10 * sizeof(int));
For C, don't cast the return value of malloc. It's not needed and can mask other problems such as failing to include the correct headers. For the while loop, just keep track of the number of elements in a separate variable.
Here's a more idiomatic way of doing things:
/* Just allocate the array into your pointer */
int arraySize = 10;
int *p = malloc(sizeof(int) * arraySize);
printf("Size of array: %d\n", arraySize);
/* Use a for loop to iterate over the array */
int i;
for (i = 0; i < arraySize; ++i)
{
p[i] = 5;
printf("Value of index %d in the array: %d\n", i, p[i]);
}
Note that you need to keep track of your array size separately, either in a variable (as I have done) or a macro (#define statement) or just with the integer literal. Using the integer literal is error-prone, however, because if you need to change the array size later, you need to change more lines of code.
sizeof of an array returns the number of bytes the array occupies, in bytes.
int *p = (int *)malloc( sizeof(array) );
If you call malloc, you must #include <stdlib.h>. Also, the cast is unnecessary and can introduce dangerous bugs, especially when paired with the missing malloc definition.
If you increment a pointer by one, you reach the next element of the pointer's type. Therefore, you should write the bottom part as:
for (int i = 0;i < sizeof(array) / sizeof(array[0]);i++){
*p = 5;
p++;
}
*p += sizeof(int);
should be
p += 1;
since the pointer is of type int *
also the array size should be calculated like this:
sizeof (array) / sizeof (array[0]);
and indeed, the array is not needed for your code.
Nope it isn't. The following code will however. You should read up on pointer arithmetic. p + 1 is the next integer (this is one of the reasons why pointers have types). Also remember if you change the value of p it will no longer point to the beginning of your memory.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LEN 10
int main(void)
{
/* Allocate memory for a 10-element integer array. */
int array[LEN];
int i;
int *p;
int *tmp;
p = malloc(sizeof(array));
assert(p != NULL);
/* Fill each element with the value of 5. */
printf("Size of array: %d bytes\n", (int)sizeof(array));
for(i = 0, tmp = p; i < LEN; tmp++, i++) *tmp = 5;
for(i = 0, tmp = p; i < LEN; i++) printf("%d\n", tmp[i]);
free(p);
return EXIT_SUCCESS;
}
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
At this point you have allocated twice as much memory -- space for ten integers in the array allocated on the stack, and space for ten integers allocated on the heap. In a "real" program that needed to allocate space for ten integers and stack allocation wasn't the right thing to do, the allocation would be done like this:
int *p = malloc(10 * sizeof(int));
Note that there is no need to cast the return value from malloc(3). I expect you forgot to include the <stdlib> header, which would have properly prototyped the function, and given you the correct output. (Without the prototype in the header, the C compiler assumes the function would return an int, and the cast makes it treat it as a pointer instead. The cast hasn't been necessary for twenty years.)
Furthermore, be vary wary of learning the habit sizeof(array). This will work in code where the array is allocated in the same block as the sizeof() keyword, but it will fail when used like this:
int foo(char bar[]) {
int length = sizeof(bar); /* BUG */
}
It'll look correct, but sizeof() will in fact see an char * instead of the full array. C's new Variable Length Array support is keen, but not to be mistaken with the arrays that know their size available in many other langauges.
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
*p = 5;
*p += sizeof(int);
Aha! Someone else who has the same trouble with C pointers that I did! I presume you used to write mostly assembly code and had to increment your pointers yourself? :) The compiler knows the type of objects that p points to (int *p), so it'll properly move the pointer by the correct number of bytes if you just write p++. If you swap your code to using long or long long or float or double or long double or struct very_long_integers, the compiler will always do the right thing with p++.
i += sizeof(int);
}
While that's not wrong, it would certainly be more idiomatic to re-write the last loop a little:
for (i=0; i<array_length; i++)
p[i] = 5;
Of course, you'll have to store the array length into a variable or #define it, but it's easier to do this than rely on a sometimes-finicky calculation of the array length.
Update
After reading the other (excellent) answers, I realize I forgot to mention that since p is your only reference to the array, it'd be best to not update p without storing a copy of its value somewhere. My little 'idiomatic' rewrite side-steps the issue but doesn't point out why using subscription is more idiomatic than incrementing the pointer -- and this is one reason why the subscription is preferred. I also prefer the subscription because it is often far easier to reason about code where the base of an array doesn't change. (It Depends.)
//allocate an array of 10 elements on the stack
int array[10];
//allocate an array of 10 elements on the heap. p points at them
int *p = (int *)malloc( sizeof(array) );
// i equals 0
int i = 0;
//while i is less than 40
while (i < sizeof(array)){
//the first element of the dynamic array is five
*p = 5;
// the first element of the dynamic array is nine!
*p += sizeof(int);
// incrememnt i by 4
i += sizeof(int);
}
This sets the first element of the array to nine, 10 times. It looks like you want something more like:
//when you get something from malloc,
// make sure it's type is "____ * const" so
// you don't accidentally lose it
int * const p = (int *)malloc( 10*sizeof(int) );
for (int i=0; i<10; ++i)
p[i] = 5;
A ___ * const prevents you from changing p, so that it will always point to the data that was allocated. This means free(p); will always work. If you change p, you can't release the memory, and you get a memory leak.