C - Dynamic Memory - c

I'm learning about dynamic memory at the moment, but my book is not clear about this. Why does the declaration of the dynArray doesn't not have the [ ] brackets which is used for array declaration when not using malloc. Why is the [ ] not needed when declaring, but needed in the loop.
int * dynArray;
dynArray = malloc(sizeof(int)*5);
srand ( time(NULL) );
for(i=0; i<=myInt; i++){
dynArray[i] = rand()%100;
}

It is not needed in the loop; pointers can be accessed as arrays and arrays can be accessed as pointers
This is equivalent
for(i=0; i<=myInt; i++){
*(dynArray+i) = rand()%100;
}

The difference is in when its address is known.
For a simple int a[5] array, the compiler knows where it is, so its address is constant (or stack- or struct-relative, which is the same thing).
OTOH int* a means a is just a variable, not a constant, that happens to point to one or more int. The running program can do its own allocation and set a, and it's up to the programmer to know what he/she is doing.
But indexing a[i] works the same in either case. It takes a as the address of the array, then adds to it i times the size of an int, and that's the address of the actual integer.

This defines an array of a certain size:
int array1[10];
This defines a pointer to integer:
int * array2;
Both definitions allocate some memory. The first one allocates space to hold 10 ints. The second one allocates space to hold a pointer to integer.
When the array1 is used in an expression as an rvalue, it degenerates to a pointer. So using array1 rvalue is equivalent to taking its address: &array1. In an expression, array1 and array2 rvalues are equivalent: they act as pointer-to-int values. The difference is that you can't use array1 as an lvalue: you can't assign to it, and you can't modify it - because it's not a pointer you can write to. You can certainly, of course, modify the values pointed-to by either array1-acting-as-a-pointer, or by array2.
Both definitions above give you uninitialized variables: the contents of array1 are not defined, neither are the contents of array2. So, for example, it'd be an error to dereference the array2 pointer before a value was assigned to it.
You can set array2 to the address of the 10 integer-long area allocated in array1, and both are then equivalent:
int array1[10];
int * array2 = array1;
array1[0] = 1;
array2[0] ++; // Increment the first item of the array
assert(array1[0] == 2);
But while you can certainly make array2 point to the second item in the first array, you can't change where array1 points to:
array2 ++; // Increment the pointer so that it points to the second item of the array
assert(array2 == &array1[1]);
array1 ++; // Triggers a compile-time error diagnostic
The assert, from #include <assert.h>, is simply a way to assert certain facts. If they prove false at runtime, the program will abort. It's also a way to succinctly express, in the C language, that certain things are true at certain points in the program. It's better than writing comments, since the assertion will be checked for you in a debug build, at runtime.

Related

terminating array looping using pointer notation in C

I’m taking a C class on Udemy. Unfortunately the instructor isn’t replying to my question so I thought I’d try this site. My assumption is that it is probably fairly common when developing a program to not know how many elements may be part of an array. When initializing an array the instructor recommends not specifying a size but to let the compiler do it.
Example: int array[ ] = {2,3,4,5,6,7,8};
Obviously, using this method there is no index to use to terminate looping. According to “C Primer Plus” by Stephen Prata the element after the last element in the array is a valid pointer location:
(pg. 406) - C guarantees that when it allocates space for an array, a
pointer to the first location after the end of the array is a valid
pointer.
If I’m using pointer notation (array++) to loop through the array, what condition can I use to terminate the looping? Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
In C pointers are signed. That has consequences dealing with array-like data structures where you might:
while (a <= a+last) {
...
a++;
}
if the index one beyond the end of a could have a change of sign, then that code could fail. Idiomatic C does not suggest the above; but it needs to be preserved, thus this limitation.
In system code, it is possible that you deal with allocations that do not conform to this, thus you should try to work with the idiomatic:
while (a < a+len) {
...
a++
}
So, for your exact question:
for (size_t i = 0; i < sizeof array/sizeof array[0]; i++) {
...
}
or
for (int *p = array; p < array + sizeof array / sizeof array[0]; p++) {
...
}
Your basic idea (looping through an array using pointers) is sound; however, there are a number of points in your question that need some attention.
Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
Yes, there is a (almost certainly) some value in that location, but it's not something you can ever use! The pointer to the 'one-past-the-end' element is valid only for use in pointer arithmetic or comparison operations; attempting to dereference it (to read the value at that address) is undefined behaviour.
You can get that 'one-past-the-end' pointer by adding the number of elements in the array to the address of the array's first element (or the array 'name' itself). The idiomatic way to get the number of elements in an array is to divide the size of the entire array by the size of its first element. So, for your array, we can declare and initialize our "end pointer" like this, using the sizeof operator:
int* end = array + sizeof(array) / sizeof(*array);
// int* end = array + sizeof array / sizeof *array; // Alternative form: "()" optional
Another important point: In your question you mention using array++ to loop through your array variable. You cannot do this, because array isn't actually a (modifiable) pointer variable – it's the name of a variable (an array) whose location is fixed at the point when main (or whatever function it is declared inside) is entered. Instead, you will need to copy the address of the array into another int* pointer, and increment that in the loop.
With those points in mind, here's an illustrative example of how you can loop through your array using a pointer:
#include <stdio.h>
int main(void)
{
int array[] = { 2,3,4,5,6,7,8 };
int* end = array + sizeof(array) / sizeof(*array);
for (int* p = array; p < end; ++p) {
// Note that, when we reach p == end, the loop will not run, so ...
printf("%d\n", *p); // ...we never attempt the *p operation on that
}
return 0;
}
A couple of other points of clarification:
The int* p = array assignment works (and is perfectly valid C) because an array variable name can readily decay into a pointer to its first element (as it will if you pass that array as an argument to a function, for example). See: What is array to pointer decay?
Because of that last point above, you cannot use the sizeof(a)/sizeof(*a) paradigm to determine the size of an array in a function it is passed to as an argument; in such cases, you need to pass the array's size as an additional argument. See: How do I determine the size of my array in C?

How do array pointers work in C and how to change pointers

I'm very new to C and I have trouble understanding array pointers. I'm trying to make a array bigger,I copy all of its element to new bigger array but I can't make original variable to point the new array. I'm use to C# where you can do
double[] array1 = new double[5];
double[] array2 = new double[10];
array1 = array2;
I did something similar using int array
int array1 [5];
int array2 [10];
*array1 = &array2;
and it compile but crash the program. Same lines but double or char[] (I was told to use char[] instead of sting in C) do not even compile
[Error] incompatible types when assigning to type 'double' from type 'double (*)[(sizetype)(newsize)]'
The results I found on the topic told me to use double* array1 for variable type but this change the interactions with that variable.
If someone can explain the concept to me or at least tell me what to search for that will be huge help.
I do know the basics of pointers!
There are a few things you need to know about arrays (and pointers):
The first is that arrays and pointers are two different things;
The second is that an array can decay to a pointer to its first element. So if you use array1 (from your example) when a pointer is expected, that's the same as doing &array1[0]. The type of such a pointer is a pointer to a single element type (so for array1 the type will be int *);
The third thing is that for any array of pointer a and index i, the expression a[i] is exactly equal to *(a + i). That means *array1 (again from your example) is the same as array1[0] (*array1 is equal to *(array1 + 0) which is equal to array1[0]);
An array will have a fixed size. Once defined the size of an array can't change;
Lastly when you get a pointer to an array (as in &array2) then you get a pointer to the actual array, not to one of its elements. The type of e.g. &array2 is int (*)[10].
Now we can puzzle together the statement
*array1 = &array2;
If we do the array-indexing replacement for *array1 then we get
array[0] = &array2;
And here we can see a big problem: The type of a single element of array1 is a plain int. So what the assignment is trying to do is to assign a pointer to an array (of type int (*)[10]) to a single int.
If you want to copy all the elements from one array to another, then use the memcpy function. You're not allowed to assign between arrays.
But beware of the different sizes for array1 and array2. If you go out of bounds of an array (or other allocated memory) you will have undefined behavior.
In C there is no way to make an array variable "reference" a different variable. If you need to use "references" they can be emulated using pointers:
int *pointer1 = array1; // array1 here will decay to &array[0]
int *pointer2 = array2; // Same here for array2
With the above definition pointer1 is (in a way) "referencing" array1. You can now use pointer1 and array1 almost interchangeably.
One major difference between using pointers and arrays is how their sizes are calculated: When you do sizeof on an array you get the size (in bytes) of the whole array. Assuming 32-bit int (the most common) then sizeof array1 will return 5 * 4 (or 20) as the size. If you get the size of a pointer, you get the size of the pointer itself, not what it might point to. So sizeof pointer1 will return either 4 or 8 (depending on if you're in a 32-bit or 64-bit system).
Going back to references, we can now change where pointer1 is pointing:
pointer1 = pointer2; // Assuming pointer2 is unchanged, equivalent to pointer1 = array2
Now pointer1 and pointer2 are pointing to the same array, array2.
In C# you can overload the = to copy the arrays. In C it is just simple assignment.
In C arrays decays to pointers for the sake of simplicity. In C *(array + N) == array[N] and *array == array[0]
int array1 [5]; it is not the array of pointers only integers so *array1 = &array2; assigns array[0] with address of the first element of the the array2 converted to signed integer which generally doesn't make too much sense and it does not copy array2 to array
To copy array you need to use memcpy or the loop to copy the element. You need to make sure that the destination array is large enough to accommodate the second array. C will not change the destination array size.
The assignments that your are doing is wrong. Basically a pointer points to a block of memory. from your code I can understand that array1 = array2; and *array1 = &array2; is wrong.
Syntax in C is something like this data-type* pointer-variable = (data-type*)malloc(no. of bytes you want);
See consider you want 10 block of memory of type int
int *p = (int *)malloc(10 * sizeof(int))
sizeof(int) return 4 bytes.
Now p points to 10 * 4 = 40 bytes of memory, I multiplied by 4 because int is usually of 4 bytes and double is of 8 bytes and so on.
Follow this link to understand C - Data Types
Now regarding changing pointers refer below example and read the comments
int *q = NULL // declare a pointer of same type as the block of memory it is going to point
q = p; //now q and p point same memory of 40 bytes, means value at q[0] is equal to p[0]
When you have an integer pointer and you increment it by p++ it will point to next memory location p[1], pointer will be exactly incremented by 4 bytes as int size is 4 bytes and for double it will be 8 bytes, for char it will be 1 byte and so on.
Now if you want to increase the size of dynamically allocated memory you can use realloc please follow this link to understand more.
Dynamic Memory Allocation in C
int *p = NULL;
// Dynamically allocate memory using malloc()
p = (int*)malloc(no. of bytes, sizeof(int));
// Dynamically re-allocate memory using realloc()
p = realloc(p, (no. of bytes) * sizeof(int));
// Avoid memory leaks
free(p);
Syntax in C++ is something like this data-type* pointer-variable = new data-type[size];
See consider you want 10 block of memory of type int
int *p = new int[10]
Just use new operator to allocate block of memory and use delete to free allocated memory to avoid memory leaks.follow this link
new and delete operators in C++ for dynamic memory
Or If you are looking for containers where you don't know how much memory should be allocated the use standard template library vector, it helps creating dynamic arrays.follow this link
Vector in C++ STL

Is a 2D Array an Array of Pointers?

If I have:
int A[10][20];
printf("%p",A[3]);
it will print the address of A[3][0].
However, I'd like to know if this one dimensional array A[3] containing pointers really exists, or it is calculated in some way.
The way you have defined A means that the compiler will allocate for it a contiguous block of memory large enough to hold 10 x 20 (200) integers; see here (scroll down to "Multidimesional arrays"). As I'm sure you realize, if you were to do printf("%p", A); you would see the address of the beginning of that allocated block.
Now, when the compiler sees the expression A[3], it will add what it calculates as the necessary amount of "integer sizes" to the base address (that of A, or A[0][0]); in this case, it will add "3" (the index specified) multiplied by the combined size of all the other dimensions (in this case, there's only one, which is 20).
So, in your case, there is no actual array of pointers; just a memory block that the compiler can interpret according to how you described any part(s) of it.
However, in a more versatile approach, one can actually define a 2D array in terms of an actual array of pointers, like so:
int **A;
A = malloc(10 * sizeof(int*));
for (int n = 0; n < 10; ++n) A[n] = malloc(20 * sizeof(int));
In this case, using printf("%p",A[3]); would still be valid, but it would give a very different offset value from printf("%p",A); or printf("%p",A[0]);.
It's also, perhaps, worth noting that, even though these two different declarations for A can both resolve an individual element through an expression like A[i][j] (but the compiler would evaluate the addresses differently), there is here scope for major confusion! When, for example, passing such an array to a function: if the function expects data allocated in the second form, and you give it an array defined in the first form (and vice versa), you're gonna get major undefined behaviour .
yes there is a way to calculate the position:
for A[i][j]
the position of the memory block will be
pos = A + i*(number_of_columns_in_each_row) + j
here A is the pointer to the first element of the array
However, I'd like to know if this one dimensional array A containing pointers really exists, or it is calculated in some way.
The way you defined the array A :
int A[10][20];
does not contain any pointers as elements of the array. it contains only integer elements.
if you want to make an array of pointers, which should be assigned to int-variables is defined like that:
int *A[10][20];
You also can set a pointer to the start of the array, which means element [0] [0]
by using:
int *pointer;
int *A[10][20];
pointer = &A;
You also be able to set the pointer slightly forwards according to each element by increase the pointer.
pointer++;

Is an int pointer an array of ints?

I have been following some examples that declare an int pointer
int *myInt;
and then turn that pointer into an array
myInt = (int*)malloc(1024);
this checks out
myInt[0] = 5;
cout << myInt[0]; // prints 5
myInt[1] = 7;
cout << myInt[1]; // prints 7
I thought an int pointer was a pointer to an int and never anything else. I know that pointers to strings just point to the first character of the string but it looks like the same sort of thing is happening here with an array of ints. But then if what we want is an array of ints why not just create an array of ints instead of a pointer to an int?
By the way I am interested in how this works in C not C++. This is in a C++ file but the relevant code is in C.
Is an int pointer an array of ints?
No.
I thought an int pointer was a pointer to an int and never anything else
That's right. Pointers are pointers, arrays are arrays.
What confuses you is that pointers can point to the first element of arrays, and arrays can decay into pointers to their first element. And what's even more confusing: pointers have the same syntax for dereferencing and pointer arithmetic that arrays utilize for indexing. Namely,
ptr[i]
is equivalent with
*(ptr + i)
if ptr is a pointer. Of course, similarly, arr[i] is the ith element of the arr array too. The similarity arises out of the common nature of pointers and arrays: they are both used to access (potentially blocks of) memory indirectly.
The consequence of this strong relation is that in some situations (and with some constraints), arrays and pointers can be used as if they were interchangeable. This still doesn't mean that they are the same, but they exhibit enough common properties so that their usage often appears to be "identical".
There is an alternative syntax for accessing items pointed by a pointer - the square brackets. This syntax lets you access data through pointers as if the pointer were an array (of course, pointers are not arrays). An expression a[i] is simply an alternative form of writing *(a+i)* .
When you allocate dynamic storage and assign it to myInt, you can use the pointer like a dynamic array that can change size at runtime:
myInt = malloc(1024*sizeof(int)); // You do not need a cast in C, only in C++
for (int i = 0 ; i != 1024 ; i++) {
myInt[i] = i; // Use square bracket syntax
}
for (int i = 0 ; i != 1024 ; i++) {
printf("%d ", *(myInt+i)); // Use the equivalent pointer syntax
}
* Incidentally, commutativity of + lets you write 4[array] instead of array[4]; don't do that!
Sort of, and technically no. An int pointer does point to the int. But an array of ints is contiguous in memory, so the next int can be referenced using *(myInt+1). The array notation myInt[1] is equivalent, in that it uses myInt pointer, adds 1 unit to it (the size of an int), and reference that new address.
So in general, this is true:
myInt[i] == *(myint + i)
So you can use an int pointer to access the array. Just be careful to look out for the '\0' character and stop.
An int pointer is not an array of ints. But your bigger question seems to be why both arrays and pointers are needed.
An array represents the actual storage in memory of data. Once that storage is allocated, it makes no significant difference whether you refer to the data stored using array notation or pointer notation.
However, this storage can also be allocated without using array notation, meaning that arrays are not necessarily needed. The main benefit of arrays is convenient allocation of small blocks of memory, i.e., int x[20] and the slightly more convenient notation array[i] rather than *(array+i). Thankfully, this more convenient notation can be used regardless of whether array came from an array declaration or is just a pointer. (Essentially, once an array has been allocated, its variable name from that point onwards is no different than a pointer that has been assigned to point to the location in memory of the first value in the array.)
Note that the compiler will complain if you try to directly allocate too big of a block of memory in an array.
Arrays:
represent the actual memory that is allocated
the variable name of the array is the same as a pointer that references the point in memory where the array begins (and the variable name + 1 is the same as a pointer that references the point in memory where the second element of the array begins (if it exists), etc.)
values in the array can be accessed using array notation like array[i]
Pointers:
are a place to store the location of something in memory
can refer to the memory that is allocated in an array
or can refer to memory that has been allocated by functions like malloc
the value stored in the memory pointed to by the pointer can be accessed by dereferencing the pointer, i.e., *pointer.
since the name of the array is also a pointer, the value of the first element in the array can be accessed by *array, the second element by *(array+1), etc.
an integer can be added or subtracted to a pointer to create a new pointer that points to other values within the same block of memory your program has allocated. For example, array+5 points to the place in memory where the value array[5] is stored.
a pointer can be incremented or decremented to point to other values with the same block of memory.
In many situations one notation will be more convenient than the other, so it is extremely beneficial that both notations are available and so easily interchanged with each other.
They are not the same. Here is the visible difference.
int array[10];
int *pointer;
printf ("Size of array = %d\nSize of pointer = %d\n",
sizeof (array), sizeof (pointer));
The result is,
Size of array = 40
Size of pointer = 4
If You do "array + 1", the resulting address will be address of array[0] + 40. If You do "pointer + 1", resulting address will be address of pointer[0] + 4.
Array declaration results in compile time memory allocation. Pointer declaration does not result in compile time memory allocation and dynamic allocation is needed using calloc() or malloc()
When you do following assignment, it is actually implicit type cast of integer array to integer pointer.
pointer = array;

Questions about pointers and arrays

Sanity-check questions:
I did a bit of googling and discovered the correct way to return a one-dimensional integer array in C is
int * function(args);
If I did this, the function would return a pointer, right? And if the return value is r, I could find the nth element of the array by typing r[n]?
If I had the function return the number "3", would that be interpreted as a pointer to the address "3?"
Say my function was something like
int * function(int * a);
Would this be a legal function body?
int * b;
b = a;
return b;
Are we allowed to just assign arrays to other arrays like that?
If pointers and arrays are actually the same thing, can I just declare a pointer without specifying the size of the array? I feel like
int a[10];
conveys more information than
int * a;
but aren't they both ways of declaring an array? If I use the latter declaration, can I assign values to a[10000000]?
Main question:
How can I return a two-dimensional array in C? I don't think I could just return a pointer to the start of the array, because I don't know what dimensions the array has.
Thanks for all your help!
Yes
Yes but it would require a cast: return (int *)3;
Yes but you are not assigning an array to another array, you are assigning a pointer to a pointer.
Pointers and arrays are not the same thing. int a[10] reserves space for ten ints. int *a is an uninitialized variable pointing to who knows what. Accessing a[10000000] will most likely crash your program as you are trying to access memory you don't have access to or doesn't exist.
To return a 2d array return a pointer-to-pointer: int ** f() {}
Yes; array indexing is done in terms of pointer arithmetic: a[i] is defined as *(a + i); we find the address of the i'th element after a and dereference the result. So a could be declared as either a pointer or an array.
It would be interpreted as an address, yes (most likely an invalid address). You would need to cast the literal 3 as a pointer, because values of type int and int * are not compatible.
Yes, it would be legal. Pointless, but legal.
Pointers and arrays are not the same thing; in most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type and its value will be the address of the first element of the array. Declaring a pointer by itself is not sufficient, because unless you initialize it to point to a block of memory (either the result of a malloc call or another array) its value will be indeterminate, and may not point to valid memory.
You really don't want to return arrays; remember that an array expression is converted to a pointer expression, so you're returning the address of the first element. However, when the function exits, that array no longer exists and the pointer value is no longer valid. It's better to pass the array you want to modify as an argument to the function, such as
void foo (int *a, size_t asize)
{
size_t i;
for (i = 0; i < asize; i++)
a[i] = some_value();
}
Pointers contain no metadata about the number of elements they point to, so you must pass that as a separate parameter.
For a 2D array, you'd do something like
void foo(size_t rows, size_t columns, int (*a)[columns])
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < columns; j++)
a[i][j] = some_value;
}
This assumes you're using a C99 compiler or a C2011 compiler that supports variable length arrays; otherwise the number of columns must be a constant expression (i.e., known at compile time).
These answers certainly call for a bit more depth. The better you understand pointers, the less bad code you will write.
An array and a pointer are not the same, EXCEPT when they are. Off the top of my head:
int a[2][2] = { 1, 2, 3, 4 };
int (* p)[2] = a;
ASSERT (p[1][1] == a[1][1]);
Array "a" functions exactly the same way as pointer "p." And the compiler knows just as much from each, specifically an address, and how to calculate indexed addresses. But note that array a can't take on new values at run time, whereas p can. So the "pointer" aspect of a is gone by the time the program runs, and only the array is left. Conversely, p itself is only a pointer, it can point to anything or nothing at run time.
Note that the syntax for the pointer declaration is complicated. (That is why I came to stackoverflow in the first place today.) But the need is simple. You need to tell the compiler how to calculate addresses for elements past the first column. (I'm using "column" for the rightmost index.) In this case, we might assume it needs to increment the address ((2*1) + 1) to index [1][1].
However, there are a couple of more things the compiler knows (hopefully), that you might not.
The compiler knows two things: 1) whether the elements are stored sequentially in memory, and 2) whether there really are additional arrays of pointers, or just one pointer/address to the start of the array.
In general, a compile time array is stored sequentially, regardless of dimension(s), with no extra pointers. But to be sure, check the compiler documentation. Thus if the compiler allows you to index a[0][2] it is actually a[1][0], etc. A run time array is however you make it. You can make one dimensional arrays of whatever length you choose, and put their addresses into other arrays, also of whatever length you choose.
And, of course, one reason to muck with any of these is because you are choosing from using run time multiplies, or shifts, or pointer dereferences to index the array. If pointer dereferences are the cheapest, you might need to make arrays of pointers so there is no need to do arithmetic to calculate row addresses. One downside is it requires memory to store the addtional pointers. And note that if the column length is a power of two, the address can be calculated with a shift instead of a multiply. So this might be a good reason to pad the length up--and the compiler could, at least theoretically, do this without telling you! And it might depend on whether you select optimization for speed or space.
Any architecture that is described as "modern" and "powerful" probably does multiplies as fast as dereferences, and these issues go away completely--except for whether your code is correct.

Resources