Reputation: 177
As the title says, I'm dense. I'm trying to allocate space on the heap to store the values of an array of uint64_t. (It could be any kind of number but that's what I used to differentiate values from pointers.) I got the answer to one of my questions here. I think I understand. What I'm trying to do is get a pointer to an array of numbers, and then assign values to the array at run-time.
Edit: updated 12:15pm EST. To save people reading, I've left the original question below, and based on comments and answers narrowed down the questions to the following. This is my C code:
#include "stdafx.h"
#include <stdlib.h>
#include <stdint.h>
#define NBRPTR 3
int main()
{
uint64_t (*LngArr3)[NBRPTR]; // pointer to array of 3 uint64_t
uint64_t s; // subscript
// WHen the next line of code is not commented, I get the following message:
// Error C2440 '=': cannot convert from 'uint64_t *' to 'uint64_t (*)[3]'
// LngArr3 = (uint64_t *)calloc(NBRPTR, sizeof(LngArr3[0]));
LngArr3 = (uint64_t(*)[NBRPTR])calloc(NBRPTR, sizeof(*LngArr3)); // this compiles fine
printf("&lngarr3=%p\n", &LngArr3);
printf("LngArr3 =%p\n", LngArr3);
printf("*LngArr3=%llu\n", *LngArr3);
for (s = 0; s < NBRPTR; s++) {
// The following line causes: Error C3863 array type 'uint64_t [3]' is not assignable
// LngArr3[s] = s;
*LngArr3[s] = s;
printf("lngarr3s=%llu ", LngArr3[s]);
}
putchar('\n');
return 0;
}
My output is the following:
&lngarr3=002BFE88
Lngarr3 =0042E8C0
*LngArr3=4384960
lngarr3s=4384960 lngarr3s=4384984 lngarr3s=4385008
I have the following questions: I'm new and really don't understand: what does the cast on the calloc do? Also, the values of lngarr3 seem to be addresses separated by 24 rather than the numbers 0, 1, 2 like I'd hoped. How can I assign values at run-time to the 3 elements of the LngArr3 array? Contrary to what I've been told it doesn't make any difference if the assignment is (*LngArr3)[s] = s;
rather than the above. I've tried it both ways and the only difference is the addresses produced.
I'm running VS 2015 Community Edition; compiled in x86 mode.
===========================================================================
For historical purposes I've left the original question as follows. My Visual Studio C code is below:
#include "stdafx.h"
#include <stdlib.h>
#include <stdint.h>
#define NBRPTR 3
#define NBRSAVPTR 2
int main()
{
uint64_t (* LngArr1)[NBRPTR]; // pointer to array of 3 uint64_t
uint64_t (* LngArr2)[NBRPTR]; // pointer to array of 3 uint64_t
uint64_t * (SavPtrArr[NBRSAVPTR]); // array of 2 pointers, hopefully pointing to above
uint64_t * PtrLngArr[NBRPTR]; // array of 3 pointers to uint64_t
uint64_t s; // subscript
(uint64_t *) SavPtrArr[0] = (uint64_t *) malloc(NBRPTR * sizeof(LngArr1[0]));
printf("&savptrarr0=%p\n", &SavPtrArr[0]);
printf("savptrarr0 =%p\n", SavPtrArr[0]);
printf("*savptrarr0=%llu\n", *SavPtrArr[0]);
for (s = 0; s < NBRPTR; s++) {
// get compile time error: "uninitialized local variable 'LngArr1' used" on next 2 lines
// *LngArr1[s] = s;
// printf("%llu ", LngArr1[s]);
// get compile time warning: "'printf': %u in format string conflicts with
// argument 1 of type 'unint64_t' *" on above line
// is it trying to print an address instead of a value?
}
putchar('\n');
(uint64_t *) SavPtrArr[1] = (uint64_t *) calloc(NBRPTR, sizeof(LngArr2[0]));
printf("&savptrarr1=%p\n", &SavPtrArr[1]);
printf("savptrarr1 =%p\n", SavPtrArr[1]);
printf("*savptrarr1=%llu\n", *SavPtrArr[1]);
for (s = 0; s < NBRPTR; s++) {
// get compile time error: "uninitialized local variable 'LngArr2' used" on next 2 lines
// *LngArr2[s] = s;
// printf("%llu ", *LngArr2[s]);
}
putchar('\n');
for (s = 0; s < NBRSAVPTR; s++)
free(SavPtrArr[s]);
putchar('\n');
putchar('\n');
for (s = 0; s < NBRPTR; s++) {
// the next line gives *PtrLinArr[s] values of the same 20 digits of garbage numbers
(uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(1, sizeof(PtrLngArr[0]));
// the next line gives all three *PtrLinArr[s] values of 0
// (uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(NBRPTR, sizeof(PtrLngArr[0]));
printf("&ptrlngarrs=%p\n", &PtrLngArr[s]);
printf("ptrlngarrs =%p\n", PtrLngArr[s]);
printf("*ptrlngarrs=%llu\n", *PtrLngArr[s]);
putchar('\n');
free(PtrLngArr[s]);
}
return 0;
}
My results are below:
&savptrarr0=003BF6EC
savptrarr0 =004EE8B0
*savptrarr0=14829735431805717965
&savptrarr1=003BF6F0
savptrarr1 =004F0C50
*savptrarr1=0
&ptrlngarrs=003BF6D8
ptrlgnarrs =004EE8B0
*ptrlgnarrs=18302063723772116992
&ptrlngarrs=003BF6DC
ptrlgnarrs =004EE8B0
*ptrlgnarrs=18302063723772116992
&ptrlngarrs=003BF6E0
ptrlgnarrs =004EE8B0
*ptrlgnarrs=18302063723772116992
First off, I understand from this answer that I'm not supposed to cast the pointer for malloc
and calloc
, however that gives me the compile time error of C2440 '=': cannot convert from 'void *' to 'uint64_t *'
. I don't know if this is particular to Windows or Visual Studio.
Anyway, I almost understand the results. The SavPtrArr
contains 2 pointers to different addresses. The value of element 0 is garbage and element 1 is 0 because I used calloc
instead of malloc
. But what I want to do is to assign different values to the different 3 elements of LngArr1
and LngArr2
at run time (not by assigning values in the definition of the variables). I don't know how to do this because I don't understand the correct way to assign a value to a pointer to an array.
The less important question is why the 3 elements of pointers to uint64_t (PtrLngArr
) point to the same address, and why the different number of blocks on the calloc
make a difference in the values of the results. Why garbage in one case and 0 in the other case.
I hope this isn't too long, but I wanted to show the confusion I have on this, and why the results surprised me. Can anyone change the test code to show how to assign values to the 3 element arrays? Or change it to better explain how this stuff works. Thank you.
Edit: I also tried adding the following lines but it wouldn't even compile:
uint64_t (*LngArr3)[NBRPTR]; // pointer to array of 3 uint64_t
(uint64_t *)LngArr3 = (uint64_t *)calloc(NBRPTR, sizeof(LngArr3[0]));
printf("&lngarr3=%p\n", &LngArr3);
printf("LngArr3 =%p\n", LngArr3);
printf("*LngArr3=%llu\n", *LngArr3);
for (s = 0; s < NBRPTR; s++) {
LgnArr3[s] = s;
printf("lngarr3s=%llu", LngArr3[s]);
}
putchar('\n');
I got C2106 '=': left operand must be l-value
on the calloc
and somehow got C2065 'LgnArr3': undeclared identifier
on the assign of the value of LgnArr3[s]
.
Upvotes: 2
Views: 445
Reputation: 177
Thanks to both Ian Abbott and Ilya. A lot of views but you two are almost all the comments. A new attempt:
#include "stdafx.h"
#include <stdlib.h>
#include <stdint.h>
#define NBRPTR 3
int main()
{
uint64_t * foo;
uint64_t s; // subscript
foo = calloc(NBRPTR, sizeof(foo[0])); // this compiles fine as C code
printf("sizeof(foo[0])=%zd\n", sizeof(foo[0]));
printf("&foo=%p\n", &foo);
printf("foo =%p\n", foo);
printf("*foo=%llu\n", *foo);
for (s = 0; s < NBRPTR; s++)
printf("foos%d ptr=%p ", s, foo[s]);
putchar('\n');
for (s = 0; s < NBRPTR; s++) {
foo[s] = s;
printf("foos=%llu ", foo[s]);
}
putchar('\n');
return 0;
}
New results:
sizeof(foo[0])=8
&foo=0022F920
foo =0041E8C0
*foo=0
foos0 ptr=00000000 foos1 ptr=00000000 foos2 ptr=00000000
foos=0 foos=1 foos=2
I'm almost satisfied. Still some more questions I'm afraid. How many elements can foo hold? Can I #define NBRPTR
to be any arbitrary value and not have to change the definition of foo
? Also, why is *foo and the 3 foo pointers all equal to 0? I'm sure I'm allocating only 24 bytes total, but I just wondered about the pointers not showing up.
Finally I changed that last print statement to do this:
printf("foos%d=%llu ", s, foo[s]);
just to print which element s was printing. The last line of the result became:
foos0=0 foos1=4294967296 foos2=8589934592
I'm not making this up! It doesn't make much difference in the whole scheme of things. The main questions I had were the first two. But is there any reason for this new result?
Upvotes: 0
Reputation: 177
Primarily due to the help of Ian Abbott the code at the beginning of the revised question works with the following change to the printf
.
printf("lngarr3s=%llu ", LngArr3[s]);
needed to be changed to printf("lngarr3s=%llu ", *LngArr3[s]);
I still don't understand the cast on the calloc, but I can study that at my leisure. The desired output was:
&lngarr3=0043FCA0
LngArr3 =0055E8C0
*LngArr3=5630144
lngarr3s=0 lngarr3s=1 lngarr3s=2
Thanks to all.
Upvotes: 0
Reputation: 5557
First off, I understand from this answer that I'm not supposed to cast the pointer for malloc and calloc
That's for C, you have to cast for a C++ compiler, and that's what Visual Studio is defaulting to (not sure about that, please someone correct me if I'm wrong).
don't know how to do this because I don't understand the correct way to assign a value to a pointer to an array.
For LngArr1 and 2, you have to allocate the actual int array, I think it's missing:
LngArr2 = (uint64_t *) malloc(NBRPTR * sizeof(uint64_t));
Then write the int:
(*LngArr2)[s] = s;
NB about the last array, it's an array of pointers to int, so for each pointer you have to allocate an int:
PtrLngArr[s] = (uint64_t *)calloc(1, sizeof(uint64_t));
Instead, in your code you allocate the size of a pointer that's probably less than the size of uint64_t:
(uint64_t *)PtrLngArr[s] = (uint64_t *)calloc(NBRPTR, sizeof(PtrLngArr[0]));
And what is the (uint64_t *)... in front ...?
Upvotes: 3
Reputation: 17438
Judging from the output, you are compiling and running a 32-bit Windows program. PtrLngArr[s]
is of type uint64_t *
, so sizeof(PtrLngArr[0])
will be 4
(since all pointers are size 4 in this program). So PtrLngArr[s]
points to an area of memory 4 bytes long, allocated and initialized to all-zeros by calloc
.
When you print *PtrLngArr[s]
, you get the uint64_t
value pointed to by PtrLngArr[s]
. However, sizeof(uint64_t)
is 8
, but the object pointed to is only 4 bytes long. This is undefined behavior.
If instead, you had set PtrLngArr[s] = calloc(1, sizeof(*PtrLngArr[0]))
, you would have allocated 8 bytes of memory initialized to all-zeros, and *PtrLngArr[s]
would have the value 0
.
Upvotes: 1