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.
Related
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]);}
I use to program with FORTRAN, but I decided to learn C and C++. I started with C language, and the one thing that I never used are pointers, because FORTRAN pass values by reference. I built the sample code below to understand how pointers work with multidimensional arrays:
#include <stdio.h>
#include <stdlib.h>
#define DIM1 3
#define DIM2 2
#define DIM3 4
void display3DArray1(int, int , int n, int (*arr)[][n]);
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]);
int main(void)
{
int matrix3D[DIM1][DIM2][DIM3] = {
{{1, 2, 3, 4}, {5, 6, 7, 8}},
{{9, 10, 11, 12}, {13, 14, 15, 16}},
{{17, 18, 19, 20}, {21, 22, 23, 24}}
};
int (*pmatrix3D)[DIM2][DIM3] = matrix3D;
display3DArray1(DIM1, DIM2, DIM3,pmatrix3D);
display3DArray2(DIM1, DIM2, DIM3,pmatrix3D);
return 0;
}
void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
}
}
}
}
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
}
}
}
}
The code works, but there is something that I wasn't able to understand. When I try to use the second printf of the second function in the first one I get a compilation error:
"invalid use of array with unspecified bounds" -- under gcc.
Why *(arr + i) doesn't work in the first function?
You can use the following two ways to pass/print the matrix:
void display3DArray1(int rows, int cols1, int cols2, int *A) {
int *a, i, j, k;
printf("\n");
for(i=0; i<rows; i++) {
for(j=0; j<cols1; j++) {
for(k=0; k<cols2; k++) {
a= A+(i*cols1*cols2)+(j*cols2)+k;
printf("%d, %p\n", *a, a);
}
}
}
}
void display3DArray2(int A[DIM1][DIM2][DIM3]) {
int i, j, k;
printf("\n");
for(i=0; i<DIM1; i++) {
for(j=0; j<DIM2; j++) {
for(k=0; k<DIM3; k++) {
printf("%d, %p\n", A[i][j][k], &A[i][j][k]);
}
}
}
}
The first method does not rely on the dimensions of the matrix; the second one does. As a result, the first one needs explicit address calculations (row i, col j, cell k).
Use calls respectively:
display3DArray1(DIM1, DIM2, DIM3, (int *)matrix3D);
display3DArray2(matrix3D);
Note the cast of the matrix to an int pointer.
In your code, you used parameter names to specify the dimensions of the matrix. In my C version, that is not legal; they must be constants.
Just a complement to Paul Ogilvie's answer.
The correct usage of Variable Length Arrays would be:
void display3DArray3(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n", arr[i][j][k], &arr[i][j][k]);
}
}
}
}
I was a bit puzzled, to be honest. The core issue is that the declaration of a function parameter like in f(T arr[]) declares an incomplete type whose size is not known (neither at compile time nor at run time). Originally I thought empty square brackets in function parameter declarations simply declare a pointer — notation notwithstanding —, but that is not the case. The parameter still has array type, albeit incomplete.1
When you write
void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2])
you declare a pointer to such an incomplete type of unknown size. This pointer cannot be manipulated in all the usual ways; in particular, adding to it in order to jump to the next element is impossible because we don't know where the current element ends (and hence the next element starts). But you try that in
printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
with the innermost arr+1. Just dereferencing it works, because the variable holds the address of the first element all right. This is what the print in the first function does:
printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
with *arr. The element size of the incomplete array to which arr points is known (these elements are arrays of cols2 ints), so that we can add to *arr, even if we can't add to arr proper.
For completeness: Why can you access arr that way in the second function? Well:
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2])
declares arr as an incomplete array type, true; but the size of its elements is well known: Those are cols1 x cols2 int matrices. The declaration just doesn't specify how many are there, but we can surely iterate them if we somehow know when to stop.
1 Of course this array, like any other, "decays" to a pointer in most contexts, so that the missing type information doesn't matter. But it matters if we have pointers to them.
I had trouble finding the correct syntax for dereferencing matrices of rank2 and rank3. The intent is to remove a level of indexing for faster execution. Here's some pseudo code that will get you started. This is more about getting the syntax right (MSVC 2019) than an example of working code.
int recurse(int n, unsigned char rank2[13][4], unsigned char rank3[13][4][13])
{
if (n < 13)
{
unsigned char (*deRefRank1)[4] = &rank2[n]; // deref matrix rank 2 to rank 1
unsigned char(*deRefRank2)[4][13] = &rank3[n]; // deref matrix rank 3 to 2
// insert pre-recurse code here ... use (*deRefRank1)[] and (*deRefRank2)[][]
if (recurse(n + 1, rank2[n], rank3[n])
return -1;
// insert post-recurse code here ...
}
return 0;
}
Your array indexing in the 'print' routines is invalid. The declaration of 'matrix3D' implies that the type of that name is 'pointer to int'. NOTE: Only one level of indirection there. The indexing expressions have a bunch of ''-s in front of terms; in C that means 'the item to the right of the '' is a pointer which must be dereferenced to get to the value'. That means you are in effect treating 'matrix3D' as 'pointer to (pointer to (pointer to int))' which is too many indirections.
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.
as the title says im attempting to create a program that searches through a 3x4 predefined grid for words that the user enters in the command line, i have the code completed but i am encountering these pointer warnings when i try to compile, the errors are as follow:
In function 'main':
59: warning: passing argument 1 of 'horizontalrow' makes pointer from integer without a cast
59: warning: passing argument 2 of 'horizontalrow' from incompatible pointer type
60: warning: passing argument 1 of 'verticalrow' from incompatible pointer type
60: warning: passing argument 2 of 'verticalrow' from incompatible pointer type
61: warning: passing argument 1 of 'diagonalrow' from incompatible pointer type
61: warning: passing argument 2 of 'diagonalrow' from incompatible pointer type
my code is as follows:
#include<stdio.h>
#include<string.h>
#define ROW 3
#define COL 4
void horizontalrow(char *a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k =0;
for(i = 0; i < ROW - 1; i++){
for(j = 0;j < COL; j++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j],argv[k])!=0){
printf("%s appears horizontally at a[%d][%d]", a[i][j],i,j);
}
}
}
}
}
void verticalrow(char *a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k=0;
for(j = 0; j< COL - 1; j++){
for(i = 0; i < ROW; i++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j], argv[k])!=0){
printf("%s found veritcally at a[%d][%d]",a[i][j],i,j);
}
}
}
}
}
void diagonalrow(char *a[ROW][COL], char *argv[], int argc)
{
int slice = 0, i = 0, j =0, z1 = 0, z2 =0, k=0;
for(slice = 0; slice < ROW + COL -1; slice++){
for(j = z2; j <= slice - z2; j++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j],argv[k])!=0){
printf("%s is found diagonally at a[%d][%d]", a[i][j], i, j);
}
}
}
}
}
int main(int argc, char *argv[])
{
int i=0,j=0,k=0;
char a[ROW][COL] ={ {'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'}};
horizontalrow(a[ROW][COL],argv[k], argc);
verticalrow(a[ROW],argv[k], argc);
diagonalrow(a[ROW],argv[k], argc);
return 0;
}
There are too many errors in your code. Here's a working program to get you going in the right direction. I have removed verticalrow and diagonalrow to simplify things.
#include <stdio.h>
#include <string.h>
#define ROW 3
#define COL 4
void horizontalrow(char a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k =0;
for(i = 0; i < ROW - 1; i++)
{
for(j = 0;j < COL; j++)
{
for(k=0;k<argc;k++)
{
if(a[i][j] == *argv[k] )
{
printf("%c appears horizontally at a[%d][%d]\n", a[i][j], i, j);
}
}
}
}
}
int main(int argc, char* argv[])
{
char a[ROW][COL] = { {'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'} };
horizontalrow(a, argv+1, argc-1);
return 0;
}
Changes made to your program
Signature of the function.
You had:
void horizontalrow(char *a[ROW][COL], char *argv[], int argc)
I changed it to
void horizontalrow(char a[ROW][COL], char *argv[], int argc)
// ^^^ no pointer, just the array.
You declaration expects the argument to be a two dimensional array of pointers to char. What you need is just a two dimensional array chars.
Comparing the command line arguments.
You had:
if(strcmp(a[i][j],argv[k])!=0){
I changed it to:
if(a[i][j] == *argv[k] )
Your code was syntactically correct but didn't make any sense semantically. My changes assume that the command line arguments you use to run the program are single character strings, such as
myprogram a b c
If you had a different idea for the command line arguments, you'll need to adapt the code.
Format specifier in printf.
You had:
printf("%s appears horizontally at a[%d][%d]", a[i][j],i,j);
I changed it to:
printf("%c appears horizontally at a[%d][%d]\n", a[i][j], i, j);
You had a syntactically valid format specifier. Since I changed the argument type, I had to change the format specifier too.
Removed unnecessary variables from main.
I removed the line
int i=0,j=0,k=0;
You don't need these variables.
Changed the syntax used to call the function.
You had:
horizontalrow(a[ROW][COL],argv[k], argc);
I changed it to:
horizontalrow(a, argv+1, argc-1);
Use of a[ROW][COL] as an argument calls the function by using the value obtained from evaluating a[ROW][COL]. It is syntactically wrong. The expected type of the function does not match the value type. The value type is char. Also, evaluation of a[ROW][COL] leads to undefined behavior since you are accessing the array out of bounds. The valid range of indices to access a are a[0][0] through a[ROW-1][COL-1].
It's not clear to me what you were hoping to pass to the function by using argv[k]. The value type of argv[k] does not match the argument type of the function. You can read more about using command line arguments at http://en.cppreference.com/w/c/language/main_function. Hopefully when you have finished reading that page, you will understand why I am using argc-1 as the third argument to horizontalrow.
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.