Function passing of multidimensional array in c - c

#include <stdio.h>
void spiral(int a[10][10]) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int a[r][c];
for (i = 0; i < r; i++)
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
spiral(a);
return 0;
}
When I give a 3 x 6 array
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
The output is 14, while it should be 10
How to fix this issue?

If you enter 3 and 6 for r and c (respectively) then the type of a is not int[10][10] (or int(*)[10] as the spiral argument really is), it's int[3][6]. The memory layout is completely different for the arrays, leading to undefined behavior.
You can solve this by passing the size along to the function, and using it in the declaration of the array:
void spiral(const size_t r, const size_t c, int (*a)[c]) { ... }
Call it like expected:
spiral(r, c, a);
As noted using int a[r][c] as argument might be easier to read and understand, but it gives a false impression that a is actually an array. It's not. The compiler treats the argument as a pointer to an array of c integers, i.e. int (*a)[c].
This makes me a little conflicted... On the one hand I'm all for making things easier to read and understand (which means it will be easier to maintain), on the other hand newbies often get it wrong and think that one can pass an array intact when in fact it decays to a pointer which can lead to misunderstandings.

A few things are wrong: in void spiral() you ask for a 2D-array of 10*10, but you do not give that. Keep that part as a variable, so only ask the type you receive and not what you want to receive and with creating a dynamic array you should always do that with malloc or calloc and free them afterwards. This might be a bit hard at first, but when you start creating bigger programs this is a must if you have a question or do not understand the pointers in the program called (*) then ask me:
#include <stdio.h>
#include <stdlib.h>
void spiral(int **a) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int **a = malloc(r * sizeof(int*));
for (i = 0; i < r; i++) {
a[i] = malloc(c * sizeof(int));
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
}
spiral(a);
for (i = 0; i < r; i++) {
free(a[i]);
}
free(a);
return 0;
}

Related

C: how to give 2D Array to a function

I want to pass a 2D array already filled with chars to a different method to do something with it.
Background: I am trying to implement GameOfLife. And I have already successfully implement the gameboard with a random amount of living cells. But now I want to pass the board(Array) to a different method to continue working with it. How to do so?
//wow das wird hurenshon
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void spielStarten(int x, int amountOfLiving){
char feld[x][x];
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
feld[i][j] = 'o';
}
}
for(int i = 0; i < amountOfLiving; i++){
int a = (rand()%x);
int b = (rand()%x);
feld[a][b] = 'x';
}
printf("Gameboard: \n");
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
printf("%c ", feld[i][j]);
}
printf("\n");
}
spielRun(feld);
}
void spielRun(char feld[][]){
int neighbCount;
char feldNew[][] = feld[][];
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[x][y]);
// in progress
}
}
}
int main(int argc, char* argv[]){
srand(time(NULL));
int x = 16;
if(argc < 2 || argc > 3){
printf("2. Argument eine Zahl fuer Feldgroesse eingeben\n");
printf("1. Argument eine Zahl 0-10 fuer ungefähre prozentuale Belegung mit lebenden
Zellen eingeben \n");
return 0;
}
if(argv[2] != NULL){
x = atoi(argv[2]);
}
int i;
i = atoi(argv[1]);
i = (x^2)*(0,1*i);
spielStarten (x,i);
return 0;
}
In the last line of the Method "Spiel starten" i want to give the array to the next Method "spielRun".
Edit: thanks to an other user I found this struture:
void printarray( char (*array)[50], int SIZE )
But it doesn't work for me since I can´t hardcode the number, because the arraysize depends on a user input.
thanks!
The difficulty here is that the size of your array is not known statically (once upon a time, your code would even not compile for the same reason).
That, combined with the fact that 2D-arrays are not arrays of 1D arrays (contrarily to what happen when you malloc a int ** and then every int * in it), and so it doesn't make sense not to specify the size when passing it to a function.
When using arrays of arrays (technically, pointers to a bunch of pointers to ints), like this
void f(int **a){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int **t=malloc(10*sizeof(int *));
for(int i=0; i<10; i++) t[i]=malloc(20*sizeof(int));
f(t);
}
That code is useless, it prints only unitialized values. But point is, f understands what values it is supposed to print. Pointers arithmetics tells it what a[1] is, and then what a[1][0] is.
But if this 2D-array is not pointers to pointers, but real arrays, like this
void f(int a[][20]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Then, it is essential that the called function knows the size (or at least all sizes, but for the first dimension) of the array. Because it is not pointers to pointers. It is an area of 200 ints. The compiler needs to know the shape to deduce that t[5][3] is the 5×20+3=103th int at address t.
So, that is roughly what is (better) explained in the link that was given in comments: you need to specify the size.
Like I did here.
Now, in your case, it is more complicated, because you don't know (statically) the size.
So three methods. You could switch to pointers to pointers. You could cast your array into a char * and then do the index computation yourself (x*i+j). Or with modern enough C, you can just pass the size, and then use it, even in parameters, declaration
void f(int x, int a[][x]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Anyway, from an applicative point of view (or just to avoid segfault) you need to know the size. So you would have had to pass it. So why not pass it as first parameter (Note that the function in which you have this size problem, spielRun, does refers to a x, which it doesn't know. So, passing the size x would have been your next problem anyway)
So, spielRun could look like this (not commenting in other errors it contains)
void spielRun(int x, char feld[][x]){
int neighbCount;
char feldNew[][] = feld[][]; // Other error
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[i][j]); // Corrected one here
// in progress
}
}
}
And then calls to this spielRun could be
spielRun(x, feld);
Note that I address only the passing of array of size x here. There are plenty of other errors, and, anyway, it is obviously not a finished code. For example, you can't neither declare a double array char newFeld[][] = oldFeld[][]; nor affect it that way. You need to explicitly copy that yourself, and to specify size (which you can do, if you pass it).
I am also pretty sure that i = (x^2)*(0,1*i); does not remotely what you expect it to do.

Unexpected outputs, why?

This is simple, I am allocating a dynamic 2d array using functions. I limited the scanf() len and my problem is when input a value over the limit, something weird happen.
Example
Input: 111,222,333,444
Expected output: 11,22,33,44
Real output: 11,12,33,34
#include <stdio.h>
#include <stdlib.h>
#define gd 2
void get_mem(int ***arr);
void get_data(int **arr);
int main(){
int **arr;
arr = NULL;
get_mem(&arr);
get_data(arr);
free(*arr);
return 0;
}
void get_mem(int ***arr){
int i;
*arr = (int**)malloc(gd*sizeof(int*));
for(i=0;i<5;i++){
(*arr)[i] = (int*)malloc(gd*sizeof(int));
}
printf("oki\n");
}
void get_data(int **arr){
int c,f;
for(c=0;c<gd;c++){
for(f=0;f<gd;f++){
scanf("%2d",&*(*arr+c)+f);
fpurge(stdin);
fflush(stdin);
}
}
for(c=0;c<gd;c++){
for(f=0;f<gd;f++){
printf("%d ",*(*arr+c)+f);
printf("\n");
}
}
}
The value of macro gd is 2. In get_mem(), allocating memory for 2 int *:
*arr = (int**)malloc(gd*sizeof(int*));
and below it, accessing arr beyond it size:
for(i=0;i<5;i++){ //allocating memory to 5 int pointers
^^
(*arr)[i] = (int*)malloc(gd*sizeof(int));
}
Accessing an unallocated memory is undefined behaviour.
Instead of using magic number 5 in the loop condition, you should check i with gd, like this
for(i=0;i<gd;i++){
In get_data(), the way you are accessing elements of arr for input is wrong
scanf("%2d",&*(*arr+c)+f);
^^^^^^^^^^^^
because
&arr[c][f] --> &(*(arr[c] + f) --> &(*(*(arr + c) + f)) --> &*(*(arr + c) + f) --> (*(arr + c) + f)
Note: The operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another. Hence, &(*(arr + i)) is equivalent to arr + i.
That means, &arr[c][f] is equivalent to (*(arr + c) + f) and you should use &arr[c][f] which is less error prone and more readable:
for(f = 0; f < gd; f++) {
scanf("%2d", &arr[c][f]);
Same mistake you have made while printing the arr elements in second for loop:
for(f=0;f<gd;f++){
printf("%d ",*(*arr+c)+f);
^^^^^^^^^^^
It should be *(*(arr + c) + f). More readable form is arr[c][f]:
for(f = 0; f < gd; f++){
printf("%d ", arr[c][f]);
You should not use fflush() for input stream. It's undefined behavior. From C Standards#7.21.5.2p2 -
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
Also, fpurge() is nonstandard and not portable. Moreover, you don't need to use either of them.
Rather than using more & more pointers, I'd like to do it in this way:-
#include <stdio.h>
#include <stdlib.h>
//#define gd 2
#define ROW 2
#define COLUMN 2
void get_mem(int ***arr);
void get_data(int **arr);
int main(){
int **arr = NULL;
get_mem(&arr);
printf("Enter 4 int values: ");
get_data(arr);
free(*arr);
return 0;
}
void get_mem(int ***arr)
{
int i;
*arr = ( int ** )malloc( ROW * sizeof(int *) );
for(i = 0; i < COLUMN; i++)
{
(*arr)[i] = ( int * )malloc( COLUMN * sizeof(int) );
}
printf("Okay!\n");
}
void get_data(int **arr)
{
int c, f;
for(c = 0; c < ROW; c++)
{
for(f = 0; f < COLUMN; f++)
{
scanf("%2d", &arr[c][f]); //*(*arr+c)+f)
}
}
for(c = 0; c < ROW; c++)
{
for(f = 0; f < COLUMN; f++)
{
printf("%d ", arr[c][f]); //*(*arr+c)+f)
}
putchar('\n');
}
}
I don't know what that gd is but it was making code ambiguous so I removed that and replaced it with ROW & COLUMN everywhere in the program(where it was necessary).
After allocating space to int **arr via get_mem() function, at least ask the user to input values and use proper spacing & indenting.
There's no need of fflush or fpurge, so I removed them.
Now, here if you're accessing array this way you need to be very careful of using parenthesis at proper places. You should use *(*(arr+c)+f) instead of *(*arr+c)+f)(It was an error.) this. But I chose to access the elements or store values as we do in 2D arrays. That's easier.
If you want to access this array using pointers only, instead of arr[c][f] you can do it in this way:-
scanf("%2d", &(*(*(arr+c)+f)));
&
printf("%d ", *(*(arr+c)+f));
Note: Also, you should check for any error while allocating memory.
Hope, it helps.

C, passing 2 dimensional array

I haven't used pure C in a few years now, but I can't seem to make this really basic use case work. Here is the simple use-case in simple C, the actual situation is wrapped in the HDF library, but I need to start with this, first.
#include <stdio.h>
void print_data(float **data, int I, int J)
{
for(int i=0;i<I;i++)
{
for(int j=0;j<J;j++)
printf("%02.2f\t", data[i][j]);
printf("\n");
}
}
void initialize_data(float **data, int I, int J)
{
for(int i=0;i<I;i++)
for(int j=0;j<J;j++)
data[i][j] = i * 6 + j + 1;
}
int main(int argc, char *argv[])
{
float data[4][6];
int I=4;
int J=6;
initialize_data((float **)data, 4,6);
print_data((float **)data, 4, 6);
return 0;
}
The above program will cause a failure and raise a EXC_BAD_ACCESS signal. GDB outputs:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5fc0131a
0x0000000100000de6 in initialize_data (data=0x7fff5fbff348, I=4, J=6) at simple.c:16
16 data[i][j] = i * 6 + j + 1;
I know this is really stupid simple, but I'm at my wits' ends trying to figure out this simple thing. Could someone point me in the right direction for this?
void print_data(float **data, int I, int J)
expects an array of pointers to (the first element of arrays of) float.
But when you pass
float data[4][6];
you pass a pointer to float[6].
So in print_data, an access to
data[i]
reads sizeof(float*) bytes at an offset of i * sizeof(float*) bytes after what address data holds, and interprets these bytes as a float* that it then dereferences (after adding a suitable offset) in data[i][j].
So when you pass your 2D array, some float values are interpreted as pointers and then followed. That often leads to a segmentation fault.
You can either declare
void print_data(float (*data)[6], int I, int J)
and pass your 2D array, or you need to pass an array of pointers,
float *rows[4];
for(i = 0; i < 4; ++i) {
rows[i] = &data[i][0];
}
and pass rows. Or, the third possibility is to pass and expect a flat array
void initialize_data(float* data, int I, int J) {
for(i = 0; i < I; ++i) {
for(j = 0; j < J; ++j) {
data[i*J + j] = whatever;
}
}
}
and pass &data[0][0] from main.
A bi-dimensionnal array is not evaluated as a pointer to pointer, so you need to use an array of a pointer to array in your prototype:
void print_data(float data[4][6]);
void print_data(float (*data)[6]);

malloc a char[][]

I am trying to malloc a char to have rows and columns with one letter in each cell. Something similar to int x[i][j] where I have i*rows and j*columns. Basically I want to make this:
|
1
222
33333
4444444
I tried with this code but it gives me an error: assignment makes an integer from pointer without a cast
A=(char**) malloc (5*sizeof(char*));
for(i=0;i<N+2;i++)`{
A[i]=(char*) malloc(7*sizeof(char));
}
for(i=0;i<3;i++){
for(j=0;j<7;j++){
left=3;
right=3;
if((j>=left)&&(j<=right)){
A[i][j]=i;
}
}
left--;
right++;
}
I would go with different approach:
#define STEPS 5
#define ARRAY_SIZE STEPS*STEPS
The size of the array in your case can be easily calculated by the formula above.
Now, you just need to allocate fixed size of bytes, and fill it. That's it. Even more, the version below will simply out-beat your version in simplicity and performance.
int i, j;
char *array;
array = malloc(ARRAY_SIZE);
for (i = 0; i < STEPS; i++)
for (j = 0; j < (i * 2 + 1); j++)
*(array + i * STEPS + j) = i + 1;
Proof.
This compiles fine for me, as long as I add this around your code snippet; note that "A" was declared as being of type "char **". It won't work if you write, say "char A[][]".
#include <stdlib.h>
int main() {
const int N = 10;
int i, j, left, right;
char **A;
/* your code */
return 0;
}

c pointer understanding issue

Please have a look at the following code and tell me where does ***ptr locates ?
i.e. i have a feelings that ***ptr actually locates at ptr[0][0][0]
Am I wrong ? The following is a 3d representation of pointer. where I am trying to assign some characters and later i wanted to test what is the index of ***ptr? will be waiting
#include<stdio.h>
#include<conio.h>
#define row 5
#define rw 3
#define col 10
char ***ptr;
int i,j,k;
void main()
{
clrscr();
ptr=(char *)malloc(row*sizeof(char *));
for(i=0;i<row;i++)
{
*(ptr+row)=(char *)malloc(rw*sizeof(char *));
printf("\t:\n");
for(j=0;j<rw;j++)
{
*(*(ptr+row)+rw)=(char *)malloc(col*sizeof(char *));
if(i==0 && j==0)
{ // *(*(ptr+row)+rw)="kabul";
**ptr="zzz";
}
else
*(*(ptr+row)+rw)="abul";
printf("\taddress=%d %d%d = %s\n",((ptr+row)+rw),i,j,*(*(ptr+row)+rw));
}
printf("\n");
}
printf("%c %d",***ptr,ptr);
getch();
}
First of all, I find your coding style extremely hard to read.
Answering your question, yes, ptr[0][0][0] is a synonym of ***ptr. Thats because a[b] is by definition equal to *(a+b), so ptr[0] is equal to *ptr, etc.
Said that, here is my version of your code:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define row 5
#define rw 3
#define col 10
char ***ptr;
int main()
{
int i, j;
ptr = (char***)malloc(row * sizeof(char **));
for(i = 0; i < row; i++)
{
ptr[i]= (char**)malloc(rw * sizeof(char *));
printf("\t:\n");
for(j = 0; j < rw; j++)
{
ptr[i][j] = (char*)malloc(col * sizeof(char));
if (i == 0 && j == 0)
{
strcpy(ptr[i][j], "zzz");
}
else
{
strcpy(ptr[i][j], "abul");
}
printf("\taddress=%p %d,%d = %s\n", ptr[i][j], i, j, ptr[i][j]);
}
printf("\n");
}
return;
}
Note the following changes:
Never write void main in C or C++. And throw away any book that prints it.
The argument of malloc is usually the number of elements times the size of the element. Place special attention to the real type that you intend to use.
The return of malloc is usually cast to the type pointer-to-the-type-of-the-element.
The index in the arrays should be i and j, not row and rw.
Why all the *(ptr + x) stuff? That's why we have the ptr[x] syntax.
You probably want to use strcpy to fill your strings, but difficult to say without explaining the problem.
When you want to printf a pointer, use %p.
If you use malloc, include <stdlib.h>.
Prefer local variables (i, j) to global ones, particularly for loops.
And a few other minor changes here and there...
PS. <conio.h>? Really? Are you still using Turbo-C or what?

Resources