Problems with local pointer array - c

I've done some digging around but cant find the solution. In my code below, when I declare my float **array as a global variable my program runs as intended. However I'm attempting to declare it in main() and pass it into functions and I'm getting some nasty errors when I try to compile.
Sample run below:
lab2.c: In function ‘NumOfVal’:
lab2.c:116: error: incompatible types when assigning to type ‘float’ from type ‘void *’
lab2.c:118: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:119: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:124: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:125: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘calculateSum’:
lab2.c:137: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:140: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘calculateAvg’:
lab2.c:150: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:153: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘findMax’:
lab2.c:162: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:165: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:166: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘findMin’:
lab2.c:174: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:175: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:177: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:178: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘printVal’:
lab2.c:187: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:189: error: invalid type argument of ‘unary *’ (have ‘float’)
Now I realize the errors for my "calculation functions" are all the same and but the first error at line 116 is different. I don't understand why once I declare my pointer locally in main(), it gives me all these problems. I have to use pointer arithmetic and don't see how the statement:
*(array + index) = malloc();
Is no longer valid..
Why does a local declaration change the syntax for allocating memory and reading from/writing to an array??
Code below: Im not including some of the "calculation functions" to save space
/* Function declarations */
void printVal();
void userChoice();
void calculateSum();
void calculateAvg();
void findMin();
void findMax();
int main(){
float **array;
int numData;
/*get number of datasets */
numData = NumOfSet();
printf("%d\n",numData);
array = malloc(numData * sizeof(float*));
if(array != 0){
/* get # of values per dataset and enter those values */
NumOfVal(numData, array);
}
else{
printf("Memory Allocation Failed");
}
userChoice();
}
void userChoice(){
int flag = 1;
int setChoice;
int opChoice;
while(1){
if(flag == 0)
break;
printf("Which dataset would you like to perform operations on?: \n");
scanf("%d", &setChoice);
printf("Which operation would you like to perform on dataset #%d\n", setChoice);
printf("1. Calculate sum of all the values\n");
printf("2. Calculate average of all the values\n");
printf("3. Find the minimum value\n");
printf("4. Find the maximum value\n");
printf("5. Print values in dataset\n");
printf("6. Exit the program\n");
scanf("%d", &opChoice);
/* Switch statement which makes function calls to perform whatever the user specified */
switch(opChoice){
case 1:
calculateSum(setChoice);
break;
case 2:
calculateAvg(setChoice);
break;
case 3:
findMin(setChoice);
break;
case 4:
findMax(setChoice);
break;
case 5:
printVal(setChoice);
break;
case 6:
flag = 0;
printf("Thanks for playing!\n");
printf("%d", flag);
}
}
}
int NumOfSet(){
int numData;
printf("Enter number of Datasets: \n");
scanf("%d",&numData);
return(numData);
}
/* for each data set declare size and input float values */
int NumOfVal(int data, float *array){
int index; /* counters */
int array_index;
int copy;
float size;
float val;
for(index = 0; index < data;index++){
printf("Enter size of dataset %d:\n", index);
scanf("%f", &size);
copy = size;
printf("Size = %d\n", (int) size);
printf("Array #: %d\n", index);
/* malloc() for row */
/* array[index] */
*(array + index) = malloc(size * sizeof(float));
/*array[index][0] */
*(*(array + index) + 0) = size;
printf("%f\n", *(*(array + index) + 0));
/* loop for entering float values */
for(array_index = 1; array_index <= copy; array_index++){
printf("Enter each float value:");
scanf("%f", &val);
*(*(array + index) + array_index) = val;
printf("%f\n", *(*(array + index) + array_index));
printf("count: %d\n",array_index);
printf("size: %d\n",copy);
}
}
}
void calculateSum(int setChoice, float *array){
int i;
int first = *(*(array + setChoice-1) + 0);
float sum = 0;
for(i = 1; i <= first; i++){
sum += *(*(array + setChoice-1) + i);
}
printf("The sum of the values is: %.3f\n", sum);
}
P.S. Of course, when I had declared array as global, I didn't have array as a parameter of those functions.
So it seems if I declare pointer to a pointer to a float float **array in main(). I need to have float **array as the parameter of my functions and not just float *array.
**array --> a pointer which points to a list of float arrays(?)
*array --> simply a pointer to a single float array(?)
correct me if I'm wrong please

First you've got to understand what pointers are. A pointer is variable which
stores an address. It may be the address of another variable, it may be the
start of a memory block that you've got from dynamically allocating memory with
malloc & friends or the start of an array.
*array --> simply a pointer to a single float array(?)
Not necessarily.
Let's take a look at this:
float *array;
First, forget about the name of the variable, what really is important is the
type of the variable. In this case you've got a pointer to a float.
It may point to a single float variable
float n = 8.7;
float *array = &n;
but it also may point to the start of a sequence of floats (aka array):
float na[] = { 1.1, 2.2, 3.3, 4.4 };
float *array = na;
//or
float *array = na + 2;
Which one (pointing to a single object vs pointing to an array of objects) is the
correct one depends on the context. The documentation of the function will tell
you what it is expecting. That is what counts, not the variable name. If the
variable name is array, it may not be pointing to an array, the name is then
misleading, actually is a poorly chosen name.
**array --> a pointer which points to a list of float arrays(?)
Again, not necessarily.
Let's take one step further. A double pointer
float **array;
is a pointer that points to another pointer of float. Once again, forget about
the name of the variable, the context is important. It may point to a pointer
that points to a single variable:
float n = 8.7;
float *array = &n;
float **p2arr = &array;
or it may point to a pointer that points to the start of an array
float na[] = { 1.1, 2.2, 3.3, 4.4 };
float *array = na;
float **p2arr = &array;
// *p2arr[0] == 1.1
// *(p2arr[0] + 1) == 2.2
// *(p2arr[0] + 2) == 3.3
or it may point to an array of pointers that point to a single float values:
float a=1.1, b=2.2, c=3.3;
float **ppa = calloc(3, sizeof *ppa);
ppa[0] = &a;
ppa[1] = &b;
ppa[2] = &b;
or it may point to an array if pointers that point to an array of float
values:
float **ppa = calloc(3, sizeof *ppa);
ppa[0] = calloc(5, sizeof *ppa[0]);
ppa[1] = calloc(2, sizeof *ppa[1]);
ppa[2] = calloc(9, sizeof *ppa[2]);
ppa[0][0] = 1.1;
ppa[0][1] = 2.2;
ppa[1][0] = 10.8;
ppa[2][5] = 11.1;
The context matter, and if you are using a function that has a float **arg
argument, the function documentation will tell you what it will expect from such
a pointer. If you are creating a function, you decide the context,
because you know what you are working with.
So about your code. As far as I can see, float **array; in main allocates
memory for an array of pointers. I'd suggest in this case to use calloc
instead, because calloc sets the allocated memory to 0. It makes initializing
and freeing the whole block easier even if subsequent calls of
malloc/realloc/calloc fail.
array = calloc(numData, sizeof *array);
Also note that I'm not using the sizeof(float*) here but instead sizeof *array.
The former is not incorrect, but it is easier to make mistakes like forgetting
the * or adding more than needed, specially when
dealing with double pointer. The later however will always return the correct
size, regardless of the type.
Now you're array is allocated and initialized. All pointers array[0],
array[1], etc are initialized and point to NULL. The you call
NumOfVal(numData, array); and that's where all goes wrong.
Let's see the signature of the function:
int NumOfVal(int data, float *array);
It expects a single pointer, so that's not good, you cannot pass the double
pointer. Since you are writing the function yourself, you can change the
function and set your own context.
Before fixing the function, let's look at this line in NumOfVal:
*(array + index) = malloc(size * sizeof(float));
Again here, I'd suggest using calloc. Second let's take look at this:
*(array + index). It is the same as doing array[index] and will return you
a float. You are essentially doing:
float f = malloc(sizeof * sizeof(float));
This is just wrong, because malloc returns a void pointer, you cannot set a
float to a void pointer.
But also you train of thoughts are wrong here, because the array variable in
main is a double pointer, the memory layout is different. Why?
I will changed the name of the variable, to make it clear which variable I'm referring to.
*(array_main + index) is the same as doing array_main[index]. It returns you
a pointer to float. When you pass array_main to NumOfVal, you are now
treating it like a single pointer. The size of a float and the size of a
pointer to float might not be the same, so array_main + index and array + index will return you a
different memory location. In fact it will return you a memory location where a
pointer is saved, not where the float is saved, so you are destroying the
pointers saved in array_main.
pfs = sizeof(float*)
fs = sizeof(float)
real address base base+pfs base+2*pfs base+3*pfs
pointer arithmetic base base+1 base+2 base+3
+---------+----------+----------+
| float* | float * | float * |
+---------+----------+----------+
real address base base+fs base+2*fs base+3*fs
pointer arithmetic base base+1 base+2 base+3
+-----------+-----------+-----------+
| float | float | float |
+-----------+-----------+-----------+
The graph above shows you the same memory address base seen as a
float** (top) and seen as a float* (bottom). Basically the top representation
is what you have for array in main. The bottom one is what you have for
array in NumOfVal. You see the pointer arithmetic doesn't line up and so you
are accessing the incorrect memory locations and that yields undefined
behaviour.
How to fix it? Fix the NumOfVal like this:
int NumOfVal(int data, float **array) {
int index; /* counters */
int array_index;
int copy;
float size;
float val;
for(index = 0; index < data;index++){
printf("Enter size of dataset %d:\n", index);
scanf("%f", &size);
copy = size;
printf("Size = %d\n", (int) size);
printf("Array #: %d\n", index);
/* malloc() for row */
/* array[index] */
array[index] = calloc(size + 1, sizeof *index);
array[index][0] = size;
I see you want to use the first element to save the size. It's a nice strategy,
but you need to allocate one more element because of this, otherwise you for
loop will overflow.
You have the same problem in calculateSum, same fix:
void calculateSum(int setChoice, float **array){
int i;
int first = array[setChoice-1][0];
float sum = 0;
for(i = 1; i <= first; i++){
sum += array[setChoice - 1][i];
}
printf("The sum of the values is: %.3f\n", sum);
}
Never forget to check the return value of malloc & friends, if they return
NULL, you cannot access that memory. Also write a function that frees the
memory. Here calloc comes in handy because free(NULL); is legal.
void free_array(int size, float **array)
{
if(array == NULL)
return;
for(int i = 0; i < size; ++i)
free(array[i]);
free(array);
}
In your NumOfVal function you should do:
array[index] = calloc(size + 1, sizeof *index);
if(array[index] == NULL)
{
// error handling
return 0;
}
Also you are forgetting to return a value in NumOfVal. If your function is not
going to return a value anyway, declare it as void.
Now in main after doing your calculations:
free_array(numData, array);
to free the memory.

Related

C array to store the pointers of malloc'd arrays

I'd like to store the pointers of two arrays (*a and *b) created by malloc in a function.
For example, if &a[0]=0x0061FEC8 and &b[0]=0x007700FE, then the array to store these two pointers should be c[0]=0x0061FEC8 and c[1]=0x007700FE
void storePointers(int **ptrArray){
// create two arrays a and b by malloc
int *a = (int *)malloc(5*sizeof(int)); // a stores 5 integers
int *b = (int *)malloc(10*sizeof(int)); // b stores 10 integers
// create an array to store the pointers of a and b
*ptrArray = (int **)malloc(2*sizeof(int*));
(*ptrArray)[0] = a;
(*ptrArray)[1] = b;
}
int main(){
int *mArray = NULL;
storePointers(&mArray);
// these two lines should print 0x0061FEC8 and 0x007700FE
printf("mArray[0]: %p\n", mArray[0]);
printf("mArray[1]: %p\n", mArray[1]);
return 0;
}
This program actually worked. But the compiler displayed a warning message:
warning: assignment to 'int' from 'int *' makes integer from pointer without a cast [-Wint-conversion]
(*ptrArray)[0] = a;
warning: assignment to 'int' from 'int *' makes integer from pointer without a cast [-Wint-conversion]
(*ptrArray)[1] = b;
I assume int is common so the compiler fixed the problem by itself so that my program ran properly? I have another similar program, but it uses struct. So instead of a warning, I get an error of
Error: incompatible types when assigning to type 'myStruct' from type 'myStruct *'
I would like to know the root cause and solution to get rid of the warning and ultimately the error in my struct program.
If an array is int * then an array of arrays is int ** and if you want to return an array of arrays as an out parameter, then you need a pointer to that -- int ***. So you need to change the type of mArray as well as the ptrArray parameter:
void storePointers(int ***ptrArray){
// create two arrays a and b by malloc
int *a = (int *)malloc(5*sizeof(int)); // a stores 5 integers
int *b = (int *)malloc(10*sizeof(int)); // b stores 10 integers
// create an array to store the pointers of a and b
*ptrArray = (int **)malloc(2*sizeof(int*));
(*ptrArray)[0] = a;
(*ptrArray)[1] = b;
}
int main(){
int **mArray = NULL;
storePointers(&mArray);
// these two lines should print 0x0061FEC8 and 0x007700FE
printf("mArray[0]: %p\n", mArray[0]);
printf("mArray[1]: %p\n", mArray[1]);
return 0;
}
That should then work if you change the type from int to something else.

Warning: passing argument 2 of 'transform_labels' from incompatible pointer type [-Wincompatible-pointer-types]|

My compiler gives me this warning: passing argument 2 of 'transform_labels' from incompatible pointer type [-Wincompatible-pointer-types] with this note: expected 'int (*)[10]' but argument is of type 'int **'
My code:
void transform_labels(int array[60000], int labels[60000][10], int NPAT){
for(int i = 0; i < NPAT; i++){
int aux = array[i];
labels[i][aux] = 1;
printf("%d\n ",*labels[i]);
if ((i+1) % 10 == 0) putchar('>');
}
}
int main() {
load_mnist();
int loop;
int** labels;
allocate_mem(&labels, 60000, 10);
printf("HERE");
transform_labels(train_label, labels, 60000);
return 0;
}
A pointer to a pointer cannot be converted to a pointer to an array. While an array can be converted to a pointer that only applies to the outermost dimension of a multidimensional array.
You need to change the declaration of your function:
void transform_labels(int *array, int **labels, int NPAT){
You are allowed to pass a pointer instead of the first dimension of a function argument, and vice-versa, but all other dimensions must match. You have a second dimension [10].
You can pass it a pointer to an array of size 10, but that might just push your problem up to another point in the code, such as your allocate function. The following should compile, but it is not clear that this is what you want:
typedef int LabelSub[10];
LabelSub* labels;
allocate_mem(&labels, 60000, 10);

error: invalid type argument of unary '*' (have 'long int')

I need to read the contents of the stack after executing a function
since I know the highest and lowest address on the stack, I tried to read the contents of the stack
I creat this function into the code
int pile_start =0xd0000890;
int size =0x1890;
void read_stack()
ptrdiff_t i;
for ( i = pile_start; i < size; i++) {
printf("pile = %d", *(pile_start+i)); // error
}
but I had this error :
error: invalid type argument of unary '*' (have 'long int')
can be the way how I read the contents of the stack is not correct
I need your help please
The error message is clear enough. You are trying to apply the indirection operator to an object of the type long int
printf("pile = %d", *(pile_start+i));
^^^^^^^^^^^^^^^
Maybe you mean just
printf("pile = %ld", (pile_start+i));
Or you need to cast the variable pile_start to a pointer as for example
printf("pile = %d", *( unsigned char * )(pile_start+i));
printf("pile = %d", *(pile_start+i));
Here pile_start is a a number - an int, I am assuming i is a number as well as you are using it as index in for loop. (pile_start+1) results in datatype int and value at int is invalid.
To use "*", you need to have a pointer. So first convert (pile_start+1) to pointer and then read value at that location.
If you change your code to
printf("pile = %d", *(uint32_t*)(pile_start+i));
It should show contents at that address.

Passing a dynamically allocated array from main to another function

First off, I have already looked at the example presented here:
Passing dynamically allocated array as a parameter in C
I am trying to pass a dynamically allocated array as a parameter to another function.
void InputIterations(int *iterations);
void CalcE(long double *E, int iterations);
int main()
{
int iterations;
long double *E;
InputIterations(&iterations);
E = (long double *) malloc(iterations * sizeof(long double));
CalcE(&E, iterations);
}
void InputIterations(int *iterations)
{
printf("Enter a number of iterations: ");
scanf("%d", iterations);
}
void CalcE(long double *E, int iterations)
{
long double sum = 0;
int i;
for(i=0; i<iterations; i++)
{
sum = sum + /*formula for calculating irrational constant e*/
*E = sum;
E++;
}
}
However, when I compile my code I get the following error:
error: cannot convert ‘long double**’ to ‘long double*’ for argument
‘1’ to ‘void CalcE(long double*, int)’ CalcE( &E, iterations );
Does anyone knows why I am getting this error ?
If you could please explain my mistake or point me to a source that explains it I would greatly appreciate the help.
Here:
CalcE(&E, iterations);
you take address of E (of type long double *) and pass it as an argument to CalcE. CalcE accepts as first parameter a pointer to long double. But when you take an address of E you are given actually a pointer to pointer to long double (long double**), and that is not a pointer to long double. And this is what your error tells you:
error: cannot convert ‘long double**’ to ‘long double*’ for argument
‘1’ to ‘void CalcE(long double*, int)’ CalcE( &E, iterations );
So you should have:
CalcE(E, iterations);
CalcE(&E, iterations);
should be
CalcE(E, iterations);
Hope I helped

Why is there an asterisk after a function type declaration in C?

My question is in the title and is more of a syntax related question. Does anyone know what the * is doing in the function below? See here:
int* reat(int *n)
{
int i, *array;
do
{
printf("n="); scanf("%d", n);
} while (*n < 1);
array = (int *)malloc(*n * sizeof(int));
for (i = 0; i < *n; i++)
{
printf("%d. broj: ", i + 1);
scanf("%d", array + i);
}
return array;
}
The syntax
int i, *array;
declares i to be a variable of type int and array to be a variable of type int*. This sort of declaration isn't particularly common, but is legal C code.
Hope this helps!
The * in int* reat(int *n) indicates in the return that this function is returning a pointer to an integer value rather than the integer value itself. The * indicates in the argument list that this function also wants a pointer to an integer value rather than a "raw" integer value for its argument.
For example,
int x = reat(n); // assume n is a pointer to an int
probably won't compile on most systems. If it does, you'll be storing a memory address in x rather than the integer value you were expecting. Instead write
int *x = reat(n)
to store in x the pointer (to some integer value) returned by reat(). Consider this function:
int addone(int x) {
return 1 + x;
}
This function takes an integer value for its argument. To access the value of the integer pointed to by the return from reat() and use it in addone(), we'll need to call it like so:
int *x = reat(n)
addone(*x)
Thereby dereferencing x with the * operator to access the integer value it points to. addone(x) won't compile because x, without dereferencing, is a memory address and not an integer.
Understanding when the * is being used to define a pointer and when its being used to dereference one will become second nature over time. Trust that any time it shows up in a function definition, whether as an argument or a return, it indicates a pointer is being used.

Resources