프로그래밍
첫 페이지 회원가입 로그인
비공개 손님 2021-08-12 11:04:43
C 고차원 배열 포인터 함수 질문

포인터에 집어넣어진 3d 배열을 함수에 집어넣어서 그 값을 좀 바꾸고 싶은데요, 함수 선언할때 입력 값을 어떻게 처리해야 할지 모르겠습니다...

3d 배열을 다음과 같은 식으로 포인터에 집어넣었구요
float q_tf[Nz+2][Ny+2][Nx+2];
float (*p_tf)[Ny+2][Nx+2] = q_tf;

그 다음에 이걸 pbndry() 라는 함수에 넣어서 아래와 같이 for loop을 몇번 돌려서 값들을 좀 바꾸고 싶은데요, 이 경우 pbndry() 함수 선언 할때 입력 값을 float *in_arr 설정해야하나요 아니면 float **in_arr 또는 float in_arr로 선언 해야하나요? 그리고 이 3d 배열 포인터를 pbndry() 함수에서 인덱싱을 해야하는데 어떤식으로 처리를 해야하는지 궁금합니다.


#include <netcdf.h>


// netCDF constants
#define err(e) {printf("Error: %sn", nc_strerror(e)); return(2);}

#define fname "leap3d.nc"

// Variable sizes and dimensions (constants)
#define Nx 150
#define Ny 300
#define Nz 6
#define Nt 2000
#define ndims 4

void pbndry(float in_arr, int in_x_siz, int in_y_siz, int in_z_siz)
{
   int i,j,k;

   // Periodic boundary
   // x-direction
   for(k=1;k<in_z_siz+1;k++)
      for(j=1;j<in_y_siz+1;j++)
         in_arr[k][j][0]     =  in_arr[k][j][Nx];
         in_arr[k][j][Nx+1]  =  in_arr[k][j][1];
  
   // y-direction
   for(k=1;k<in_z_siz+1;k++)
      for(i=1;i<in_x_siz+1;i++)
         in_arr[k][0][i]     =  in_arr[k][Ny][i];
         in_arr[k][Ny+1][i]  =  in_arr[k][1][i];    
  
   // z-direction
   for(j=1;j<in_y_siz+1;j++)
      for(i=1;i<in_x_siz+1;i++)
         in_arr[0][j][i]     =  in_arr[Nz][j][i];
         in_arr[Nz+1][j][i]  =  in_arr[1][j][i];

   printf("Periodic boundary function call completen");
}


int main()
{
int    i,j,k,t;
float  u = 0.0,
       v = 3.0,
       w = 3.0,
       dtdl = 0.01;

// p_tf : p at future
// p_tn : p at now
// p_tp : p at past
float q_tf[Nz+2][Ny+2][Nx+2];
float q_tn[Nz+2][Ny+2][Nx+2];
float q_tp[Nz+2][Ny+2][Nx+2];

float (*p_tf)[Ny+2][Nx+2] = q_tf;
float (*p_tn)[Ny+2][Nx+2] = q_tn;
float (*p_tp)[Ny+2][Nx+2] = q_tp;


// netCDF variables
int    ncid, retval, varid, x_dimid, y_dimid, z_dimid, t_dimid;
int    dimids[ndims];
size_t start[ndims], count[ndims];


// netCDF file operation
// Creating netCDF file
if ((retval = nc_create(fname, NC_CLOBBER, &ncid)))
   err(retval);

// Define dimensions
if ((retval = nc_def_dim(ncid, "z", Nz+2, &z_dimid)))
   err(retval);
if ((retval = nc_def_dim(ncid, "y", Ny+2, &y_dimid)))
   err(retval);
if ((retval = nc_def_dim(ncid, "x", Nx+2, &x_dimid)))
   err(retval);
if ((retval = nc_def_dim(ncid, "t", NC_UNLIMITED, &t_dimid)))
   err(retval);

// Dimension ids
dimids[0] = t_dimid;
dimids[1] = z_dimid;
dimids[2] = y_dimid;
dimids[3] = x_dimid;


// Variable for writing netCDF data one timestep at a time
count[0] = 1;       // For time dimension : 1 timestep
count[1] = Nz+2;    // For z              : write everything
count[2] = Ny+2;    // For y              : write everything
count[3] = Nx+2;    // For x              : write everything

start[1] = 0;       // For z              : don't do anything
start[2] = 0;       // For y              : don't do anything
start[3] = 0;       // For x              : don't do anything

if ((retval = nc_def_var(ncid, "data", NC_FLOAT, ndims, dimids, &varid)))
   err(retval);

if ((retval = nc_enddef(ncid)))
   err(retval);


// Array initialization
for(k=0;k<Nz+2;k++)
{
   for(j=0;j<Ny+2;j++)
   {
      for(i=0;i<Nx+2;i++)
      {
         p_tf[k][j][i] = 0.0;
         p_tn[k][j][i] = 0.0;
         p_tp[k][j][i] = 0.0;
      }
   }
}


for(k=1;k<Nz+1;k++)
{
   for(j=100;j<139+3;j++)
   {
      for(i=100;i<139+3;i++)
      {
         p_tf[k][j][i] = 3.0;
         p_tn[k][j][i] = 3.0;
         p_tp[k][j][i] = 3.0;
      }
   }
}


// Euler scheme for the first time step
for(k=1;k<Nz+1;k++)
{
   for(j=1;j<Ny+1;j++)
   {
      for(i=1;i<Nx+1;i++)
      {
         p_tf[k][j][i] = p_tn[k][j][i]
                        - u * dtdl * (p_tn[k][j][i] - p_tn[k][j][i-1])
                        - v * dtdl * (p_tn[k][j][i] - p_tn[k][j-1][i])
                        - w * dtdl * (p_tn[k][j][i] - p_tn[k-1][j][i]);
      }
   }
}

// Periodic boundary condition
pbndry(&p_tf,Nx,Ny,Nz);



p_tp = p_tn;
p_tn = p_tf;


start[0] = 0;

if (retval = nc_put_vara_float(ncid, varid, start, count, &p_tf[0][0][0]))
   err(retval);


// Leapfrog scheme
for(t=1;t<Nt;t++)
{
   for(k=1;k<Nz+1;k++)
   {
      for (j=1;j<Ny+1;j++)
      {
         for(i=1;i<Nx+1;i++)
         {
            p_tf[k][j][i] = p_tp[k][j][i]
                         - u * dtdl * (p_tn[k][j][i+1] - p_tn[k][j][i-1])
                         - v * dtdl * (p_tn[k][j+1][i] - p_tn[k][j-1][i])
                         - w * dtdl * (p_tn[k+1][j][i] - p_tn[k-1][j][i]);
         }
      }
   }

   pbndry(&p_tf,Nx,Ny,Nz);


   p_tp = p_tn;
   p_tn = p_tf;

   start[0] = t;
   if ((retval = nc_put_vara_float(ncid, varid, start, count, &p_tf[0][0][0])))
      err(retval);
}

if ((retval = nc_close(ncid)))
   err(retval);


printf("nDonen");


return 0;
}

질문 | 1180명이 읽었어요. 44.210.132.31 |

0
1 비공개 손님 2021-08-12 12:26:32
3차원 배열의 2,3번째 인덱스의 크기가 고정 되어 있는 경우.
예) 배열이 항상 arr[10][20][30] 으로 , 첫 인덱스인 10은 변화할 수 있는 크기 이지만 20 과 30 이 고정되어 있다 -> function(int arr[][20][30]) 으로 선언 하고 arr[i][j][k] 로 접근 가능

3차원 배열이 모든 위치의 크기가 가변적인 경우 (아마도 작성자님 상황)
예) arr[n][m][p] 로 배열의 크기가 어떻게 될 지 예상 할 수 없다 -> function(int col, int row, int height, int *arr) 으로 선언후 함수 내부에서 arr[i * col * height + j * height + k] 식으로 접근

내 컴파일러가 선행 인자를 통한 동적 배열 크기 할당을 지원한다
예) gcc 익스텐션 사용 -> function(int row, int col, int height, int a[row][col][height]) 로 선언 하고 arr[i][j][k] 로 접근

https://gist.github.com/wurikiji/bfd87406b4406952f563138dcf0be222

참고 하세영
전 2번째 방식 (1차원 배열 접근법으로 인덱스 계산) 을 선호 합니당. 예시 코드 처럼 쓰지는 않고 Matrix3D 같이 따로 구조체 만들어서 구조체에, rows, cols, height, *arr 선언해서 한번에 전달 해줘서 씁니당.
2 비공개 손님 2021-08-12 12:45:36
정말 감사합니다. 두번째 방법은 (1차원 배열 접근법) 컴파일러 가리지 않고 작동 하나요?
3 비공개 손님 2021-08-12 13:14:31
넹 1차원 배열 접근법은 다 됩니당
그래서 다른 사람들 코드 보면 Matrix 라는 이름의 구조체들을 자주 사용하는게 보일 거에여
4 비공개 손님 2021-08-12 13:40:03
네. 감사합니다!
5 비공개 손님 2021-08-13 02:49:27
음...
메인함수에 위의 함수를 불러올때 function(int col, int row, int height, int *arr) 같이 배열 앞에 * 붙어야 하나요? 아니면 & 붙혀야 하나요?
6 비공개 손님 2021-08-13 02:59:43
아. 아닙니다. 예제를 끝까지 안봤네요. ㅎㅎㅎ
7 비공개 손님 2021-08-13 10:36:59
1차원 배열 접근법 사용하면 gcc 로 컴파일 할때 아래와 같은 경고 메시지 뜨는데 딱히 문제 없는건가요? 프로그램은 제대로 돌아가고 결과값도 맞습니다.

leapfrog.cpu.3d.c: In function ‘main’:
leapfrog.cpu.3d.c:184:17: warning: passing argument 4 of ‘pbndry’ from incompatible pointer type [-Wincompatible-pointer-types]
184 | pbndry(Nx,Ny,Nz,p_tf);
| ^~~~
| |
| float (*)[202][202]
leapfrog.cpu.3d.c:16:62: note: expected ‘float *’ but argument is of type ‘float (*)[202][202]’
16 | void pbndry(int in_x_siz, int in_y_siz, int in_z_siz, float *in_arr)
| ~~~~~~~^~~~~~
leapfrog.cpu.3d.c:232:20: warning: passing argument 4 of ‘pbndry’ from incompatible pointer type [-Wincompatible-pointer-types]
232 | pbndry(Nx,Ny,Nz,p_tf);
| ^~~~
| |
| float (*)[202][202]
leapfrog.cpu.3d.c:16:62: note: expected ‘float *’ but argument is of type ‘float (*)[202][202]’
16 | void pbndry(int in_x_siz, int in_y_siz, int in_z_siz, float *in_arr)
| ~~~~~~~^~~~~~
8 비공개 손님 2021-08-13 11:24:37
넹 딱히 문제 없습니당
워닝이 뜨는게 신경 쓰이시면 (float*) 식으로 캐스팅 해서 넘겨주시면 됩니당
9 비공개 손님 2021-08-13 12:09:09
답변 감사합니다. 정말 많은 도움 되었습니다.
댓글을 작성하실 수 없습니다.
(권한이 없는 회원레벨)
목록으로
이용약관 | 광고/제휴 | 개인정보취급방침 | 문의/신고 | 모바일 TE31 | 서버 부하 : 19.25%
실시간 Issue 커뮤니티 TE31 [알지롱] ⓒ 2002-2021
TOP arrow_upward