Question about the difference between Integer triple pointer and float triple pointer - c

I'm doing a project for school and they force us to use a type float triple pointer in a function that multiply two matrices,
and for the last day i can't figure out why when I'm using int triple pointer I get the numbers needed but when I'm using float I get zeros.
I wrote something simple just for example for the problem.
Thank you !!
int ***ptr3;
int Matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int i;
ptr3 = malloc(sizeof(int));
ptr3 = Matrix;
for (i = 0; i < 9; i++) {printf_s("%d ", ptr3[i]);}
printf_s("\n");
float ***ptr3_f;
float Matrix_f[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
ptr3_f = malloc(sizeof(float));
ptr3_f = Matrix_f;
for (i = 0; i < 9; i++) {printf_s("%.1f ", ptr3_f[i]);}
enter image description here

There is a whole lot of misconceptions here and your teacher does unfortunately not seem to know C very well. You simply can't use a type*** and it doesn't make any sense to use either.
A pointer of the type type*** cannot point at a 3D array of type. Nor can it point at a 2D array. It cannot point at any array type at all.
Sometimes when using dynamic memory allocation, we allocate an array of type*, each pointing at the first item in an array. A type** can then be used to point at the first type* element, to emulate the syntax of a 2D array with [i][j] access.
This does however not magically make the array of type* an array type[] at the same time. Nor does it magically make type** an array type[][]. If someone taught you that, they are confused.
Most of the time, we should not use type** to emulate a 2D array in the first place, because doing so is horribly inefficient. See Correctly allocating multi-dimensional arrays.
Thus when you attempt ptr3 = Matrix;, you get a C language constraint violation error by the compiler. Some lax compilers "only" give you a warning, but that doesn't make the code valid C. The type*** cannot be used to point at a 3D array, period.
If you somehow got the correct output in some scenario, that's by luck, since the behavior of your code isn't well-defined. On some system, int happened to have the same size as the pointer or such.
ptr3 = malloc(sizeof(int)); ptr3 = ... is senseless, since all that you achieve with the malloc is a memory leak. Because the first thing you do is to overwrite the pointer address to the data you just allocated. I'm not sure why you want to allocate a single int to begin with.
Getting rid of all misconceptions, you can perhaps salvage the program in the following manner:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int (*iptr)[3];
int imatrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
iptr = imatrix;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
printf_s("%d ", iptr[i][j]);
}
printf("\n");
}
printf("\n");
float (*fptr)[3];
float fmatrix [3][3] = { {1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f},{7.0f,8.0f,9.0f} };
fptr = fmatrix;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
printf_s("%.1f ", fptr[i][j]);
}
printf("\n");
}
}

You don't need triple pointer for such arrays.
With:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr3_i;
int Matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
float *ptr3_f;
float Matrix_f[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int i;
ptr3_i = (int *)Matrix;
printf("ptr3_i:");
for (i = 0; i < 9; i++)
printf("%d ", ptr3_i[i]);
printf("\n");
ptr3_f = (float *)Matrix_f;
printf("ptr3_f:");
for (i = 0; i < 9; i++)
printf("%.1f ", ptr3_f[i]);
printf("\n");
return 0;
}
I get:
ptr3_i:1 2 3 4 5 6 7 8 9
ptr3_f:1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0

Did you see the warning when you compile your code:
warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int **’ [-Wformat=]
assignment from incompatible pointer type [-Wincompatible-pointer-types]
warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘float **’ [-Wformat=]
You can do something like:
ptr3 = malloc(sizeof(int**)); // allocate the memory for storing one double pointer
*ptr3 = malloc(sizeof(int*)); // allocate the memory for storing one single pointer
**ptr3 = Matrix[0]; // point to first row of the matrix
// it's similar to float pointer type
ptr3_f = malloc(sizeof(float**));
*ptr3_f = malloc(sizeof(float*));
**ptr3_f = Matrix_f[0];
Then when you want to print:
for (i = 0; i < 9; i++) {printf("%d ", (**ptr3)[i]);}
for (i = 0; i < 9; i++) {printf("%.1f ", (**ptr3_f)[i]);}

Related

warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'; take the address with &

I have this code and I'm trying to debug it now and I get this error:
warning: incompatible integer to pointer conversion initializing
'int *' with an expression of type 'int'; take the address with &
[-Wint-conversion]
int * b = a[1];
The code I'm debugging is this:
#include<stdio.h>
int main() {
int ii;
int a[] = {1,2,3,4,5,6};
int * b = a[1];
for (ii=0;ii<6;ii++) {
printf("%d ",*(b+ii));
}
printf("\n");
return 0;
}
Given
int a[] = {1,2,3,4,5,6};
The array name variable a acts as a pointer i.e. the starting address for the consecutive memory block storing the values.
Thus, you can access the addresses in the loop either by incrementing the pointer i.e.
int *b=a;
for (int i = 0; i < 6; ++i) {
printf("%p\n",b++);
}
or through the pointer of the value at that index
for (int i = 0; i < 6; ++i) {
printf("%p\n", &a[i]);
}
int *b;
b is a pointer, a[1] is an integer...
Try:
int *b;
*b=a[1];
That will take us to the funny part. You have no memory for it!
Other way:
int *b=(a+1);
Yet another:
int *b=&a[1];

Using memset with pointer to an array

How do I memset an array using a pointer to that array?
int *A, n;
printf("\n Enter the size of array : ");
scanf("%d",&n);
A = (int*) malloc(sizeof(*A) * n);
int i = 0;
memset(*A,5,n * sizeof(*A));
for(i = 0; i < n; i++)
printf("%d ", A[i]);
The compiler doesn't emit warnings for no reason:
warning: passing argument 1 of 'memset' makes pointer from integer without a cast
expected 'void *' but argument is of type 'int'
This means that you are not passing the right type to the first argument of memset(), which indeed wants a pointer, while you are passing an integer.
Your pointer A is fine as is, dereferencing it (*A) is not needed and is wrong, the correct call is:
memset(A, 5, n * sizeof(*A));
More importantly though, this is not what you want to do! If you think the above sets all the elements of the allocated array to 5 that's not the case. Instead, memset() sets every single byte to 5 (see the manual page). Since an int is more than one byte (usually 4), this will fill your array with the value 0x05050505 (decimal 84215045) instead of 5.
In order to set every element to 5 you'll need a for loop:
int i = 0;
for (i = 0; i < n; i++)
A[i] = 5;
Finally, don't cast the return value of malloc():
A = malloc(sizeof(*A) * n);

how do i pass an array with a pointer into a function?

here is my code:
#include <stdio.h>
#include <stdlib.h>
void AverageOfAss(float marks[][101], int numStudents, int numAss, float *avg[]) {
int i, j;
for (j=0; j<numAss; j++) {
*avg[j] = 0;
for (i=0; i<numStudents; i++) {
*avg[j] += marks[i][j];
*avg[j] = *avg[j]/(float)numStudents*100;
return ;
}
}
}
void PrintAvg(float *avg[], int numAss) {
int i;
for (i=0; i<numAss; i++) {
printf("Average for Exam %d = %.1f\n", i, *avg[i]);
return;
}
}
int main(int argc, char* argv[]) {
float grades[1001][101], avgAss[1001];
float *p;
int i, j, row, col;
p = avgAss;
row = atoi(argv[1]);
col = atoi(argv[2]);
FILE *input_grades;
input_grades = fopen("grades.txt", "r");
// READ IN GRADES
for (i=0; i<row; i++) {
for (j=0; j<col; j++) {
fscanf(input_grades, "%f, ", &grades[i][j]);
}
}
// OUTPUT GRADES LIST
printf("==================================\n");
printf("Student grades from the input file\n");
printf("==================================\n");
for (i=0; i<row; i++) {
printf("\n");
for (j=0; j<col; j++) {
printf("%.1f, ", grades[i][j]);
}
}
printf("\n\n");
AverageOfAss(grades, row, col, &avgAss);
PrintAvg(&avgAss, col);
fclose(input_grades);
}
Everything is alright except that when i tried to execute the code on the terminal, it showed some warnings:
incompatible pointer types passing 'float (*)[1001]' to parameter
of type 'float **'
AverageOfAss(grades, row, col, &avgAss);
passing argument to parameter 'avg' here
void AverageOfAss(float marks[][101], int numStudents, int numAss, float *avg[]) {
incompatible pointer types passing 'float (*)[1001]' to parameter
of type 'float **'
PrintAvg(&avgAss, col);
passing argument to parameter 'avg' here
void PrintAvg(float *avg[], int numAss) {
Does anyone know what happened to my codes? And how should i fix it? (newbie here)
The problem is that a pointer to an array of float is not the same as a pointer to a pointer to a float.
The error message actually tells you exactly how you should solve your problem... What the compiler is telling you is that &avgAss is of type float(*)[1001] while your argument is of type float **. So you need to change your function argument type to match what the compiler expects, like e.g. float (*avg)[1001]. Then you have a problem that *avg[j] actually means *(avg[j]) and not what you need (*avg)[j].
However you don't need to pass a pointer to the array at all. All you need is to let the array naturally decay to a pointer to its first element, so what you really should do is to change the function argument to float *avg and use it like a normal array avg[j]. And of course don't pass a pointer to the array, use only avgAss in the call.
If you want to pass an array as argument to a function, modify the content of the array in that function and retain the modified array, there is no need to pass a pointer to a pointer to the array, just pass the pointer to the array (i.e. the name of the array without the [] or & operators).
In C, data of basic types are passed to functions by copy, so you need to pass pointers to them to retain the modifications. Arrays cannot be passed by copy and one level of indirection is enough.

warning passing argument 1 of " " from incompatible pointer type enabled by default

randomAssign(int **grid, int size){
int m = rand()%size;
int n = rand()%size;
grid[m][n] = 1;
}
int main()
{
srand(time(NULL));
int i, j, size;
scanf("%d", &size);
int grid[size][size];
for(i=0; i<size; i++){
for(j=0; j<size; j++){
grid[i][j] = 0;
}
}
randomAssign(grid,size); //warning
return 0;
}
I am getting warning when i call the function. I tried all i can do but i couldn't find the mistake. Where is the mistake? Regards...
Arrays and pointers are different. An array is a series of contiguous elements of a particular type. A pointer is a small object that holds the address of another object.
Your function expects a pointer that points to another pointer. However you tried to supply an array to it. This can't possibly work.
One way to fix your code would be to make the function accept a pointer to an array (not a pointer to a pointer). This could be written:
void randomAssign(int size, int grid[size][size])
This is actually the same as having int (*grid)[size], the first size is redundant (see here for detail) however it serves some documentary purpose.

Pointers for a beginner (with code)

I am doing my first ever homework assignment in C and I'm trying to grasp pointers. They make sense in theory, but in execution I'm a little fuzzy. I have this code, which is supposed to take an integer x, find its least significant byte, and replace y with that byte in the same location. GCC returns with:
"2.59.c:34:2: warning: passing argument 1 of ‘replace_with_lowest_byte_in_x’ makes pointer from integer without a cast [enabled by default]
2.59.c:15:6: note: expected ‘byte_pointer’ but argument is of type ‘int’"
And the same for argument 2. Would someone be so kind as to explain to me what is going on here?
#include <stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int length) {
int i;
for (i=0; i < length; i++) {
printf(" %.2x", start[i]);
}
printf("\n");
}
void replace_with_lowest_byte_in_x(byte_pointer x, byte_pointer y) {
int length = sizeof(int);
show_bytes(x, length);
show_bytes(y, length);
int i;
int lowest;
lowest = x[0];
for (i=0; i < length; i++) {
if (x[i] < x[lowest]) {
lowest = i;
}
}
y[lowest] = x[lowest];
show_bytes(y, length);
}
int main(void) {
replace_with_lowest_byte_in_x(12345,54321);
return 0;
}
The function expects two pointers but you're passing integer(-constant)s. What you probably want is to put the numbers in their own variables and pass the addresses of those to the function: (in main):
int a = 12345, b = 54321;
replace_with_lowest_byte_in_x(&a, &b);
Note that you're still passing incompatible pointers.
The compiler is right, your replace_with_lowest_byte_in_x() expects two unsigned char *, but you pass two ints to it. Yes, the ints can be regarded as memory address, but it's dangerous, so there is a warning. &variable gives you the address of variable.

Resources