제 4 장배열 (Array) 배열은포인터의개념을파악하게하는좋은길잡이이다. 무차원배열로부터다차원배열로확장할때에, 배열에적용되는규칙성을발견하고관계된메모리주소를검침하며의미하는바를분석한다. 그리고수와문자에관계된배열이어떻게다른지비교한다. 4.1 정수및실수배열 Memory 저장순서배열은 float의경우원소당 2 bytes, int의경우 4 bytes, double의경우 8 bytes가배당된다. 1차원배열 : 원소순으로저장된다. 2차원배열 : 1행 1열, 2열... 2행 1열, 2열... 순으로순차적으로저장된다. 3차원배열 : 1면 1행 1열, 2열... 2면 1행 1열, 2열... 순으로순차적으로저장된다. 정적및외부변수배열은초기화하지않으면 default(0 for integer, 0.0 for double) 로자동초기화된다. 자동변수배열은항상초기화가필요하다. 편의를위하여 2차원배열의경우원소의값중에서첫자리는행의구분을두번째자리는열의순서를갖는값으로한다. 예 ) b[1][2]=23 23은 2행 3열의배열에있는수. 3차원배열의경우첫자리는면을두번째자리는행을그리고마지막자리는열을나타내는값으로표현한다. 예 ) c[0][0][0]=111 111은 1면 1행 1열의배열에있는수. 4.1.1 1 차원배열 초기화방법 int a[5]={1,2,3,4,5; 또는 int a[]={1,2,3,4,5; 또는원소대입법에의해 a[0]=1, a[1]=2, a[2]=3, a[3]=4, a[4]=5 1 차원배열의시작주소는배열명 a 또는 &a[0] 이다. 배열 a 의인지번호 (index): 0 1 2 3 4 들어가있는수 : 1 2 3 4 5 예제 ) 1차원배열초기화및출력과원소별주소 int i, a[5]={1,2,3,4,5; // or a[]={1,2,3,4,5; /* 배열원소별값과주소출력 */ for(i=0; i<5; i++) { printf("a[%d]=%d ",i,a[i]); // 원소값 printf("&a[%d]=%p ",i,&a[i]); // 원소주소
printf("*(a+%d)=%d ",i,*(a+i)); // 나열된원소값 printf("a+%d=%p\n",i,a+i); // 원소주소 printf("\n"); int i, a[5]={1,2,3,4,5; // or a[]={1,2,3,4,5; /* 배열원소별값과주소출력 */ for(i=0; i<5; i++) { cout<<"a["<<i<<"]="<<a[i]<<" "; // 원소값 cout<<"&a["<<i<<"]="<<&a[i]<<" "; // 원소주소 cout<<"*(a+"<<i<<")="<<*(a+i)<<" "; // 원소값 cout<<"a+"<<i<<"="<<a+i<<'\n'; // 원소주소 cout<<"\n"; 설명 : int의경우원소하나당 4 bytes씩증가. 만일 double이라면 8 bytes씩증가 4.1.2 2 차원배열 int b[2][3]; [2] 는행 (row), [3] 은열 (column) 을나타낸다. 2차원배열은행렬과같다. 0 (0 1 2) = [0][0] [0][1] [0][2] 1 [1][0] [1][1] [1][2] Memorry 기억순서 : 1행 1열, 2열, 3열, 2행 1열, 2열, 3열의순. 즉, [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] 2차원배열의시작주소는 b[0] 또는 &b[0][0] 이다. 2차원배열의초기화 int b[2][3]={{11,12,13, {21,22,23 또는 int b[2][3]={11,12,13, 21,22,23 int b[][3] 으로도초기화. 그러나 int b[2][] 는틀린선언이다. 또는원소대입법으로 int b[2][3]; b[0][0]=11; b[0][1]=12; b[0][2]=13; b[1][0]=21; b[1][1]=22; b[1][2]=23; 예제 ) 2 차원배열초기화및출력과원소별주소
int b[2][3]={{11,12,13, {21,22,23; int i, j; for(j=0; j<3; j++) { printf("b[%d][%d]=%d ",i,j,b[i][j]); // 원소값 printf("&b[%d][%d]=%p ",i,j,&b[i][j]); // 원소주소 printf("*(b[%d]+%d)=%d ", i,j,*(b[i]+j)); // 원소값 printf("b[%d]+%d=%p\n",i,j,b[i]+j); // 원소주소 putchar('\n'); int b[2][3]={{11,12,13, {21,22,23; int i, j; for(j=0; j<3; j++) { cout<<"b["<<i<<"]["<<j<<"]="<<b[i][j]<<" "; cout<<"&b["<<i<<"]["<<j<<"]="<<&b[i][j]<<" "; cout<<"*(b["<<i<<"]+"<<j<<")="<<*(b[i]+j)<<" "; cout<<"b["<<i<<"]+"<<j<<"="<<b[i]+j<<'\n'; cout<<'\n'; 설명 : 2차원배열에서 b[0] 는배열의첫원소가있는곳의주소를나타낸다. 즉이것은 b[0]= &b[0][0] 를의미하며주소에담긴내용은 *(b[0]) 혹은 *(&b[0][0]) 혹은 b[0][0] 이다. 다음원소의주소는 b[0]+1 혹은 &b[0][1] 이며주소에담긴내용은 *(b[0]+1) 혹은 b[0][1] 이다. 이것을통해서 int로정의된위의 2차원배열은 b[0][0], b[0][1], b[0][2], b[1][0], b[1][1], b[1][2] 가순차적으로연결된 4 bytes 방을각각하나씩점유하고있다. 4.1.3 3 차원배열 int c[2][3][4]; [2] 는면, [3] 은행, [4] 는열을나타내며다음과같은방법으로배열이나열되어있다. 0 0 (0 1 2 3) = 000 001 002 003 1 1 010 011 012 013 2 020 021 022 023 100 101 102 103 110 111 112 113
120 121 122 123 Memorry 기억순서 : 1 면 1 행 1 열,... 2 면 3 행 4 열의순으로연속적 4 byte 씩차지. 3 차원배열의시작주소는 c[0][0] 또는 &c[0][0][0] 이다. 3차원배열의초기화 a) 나열법 int c[2][3][4]={111,112,113,114, 121,122,123,124, 131,132,133,134, 211,212,213,214, 221,222,223,224, 231,232,233,234; b) 면에대한묶음법 int c[2][3][4]={{111,112,113,114, 121,122,123,124, 131,132,133,134, {211,212,213,214, 221,222,223,224, 231,232,233,234; c) 면과행에대한묶음법 int c[2][3][4]={{{111,112,113,114, {121,122,123,124,{131,132,133,134, {{211,212,213,214, {221,222,223,224, {231,232,233,234; int c[][3][4] 로도초기화. 예제 ) 3차원배열초기화와출력및원소별주소 2차원배열과같은방법에의해원소값과주소를알수있다. int i,j,k; int c[2][3][4]={{{111,112,113,114, {121,122,123,124,{131,132,133,134, {{211,212,213,214, {221,222,223,224, {231,232,233,234; for(j=0;j<3;j++) for(k=0;k<4;k++) { printf("c[%d][%d[%d]=%d ",i,j,k,c[i][j][k]); printf("&c[%d][%d[%d]=%p ",i,j,k,&c[i][j][k]); printf("*(c[%d][%d]+%d)=%d ",i,j,k,*(c[i][j]+k)); printf("c[%d][%d]+%d=%p\n",i,j,k,c[i][j]+k); int i,j,k; int c[2][3][4]={{{111,112,113,114, {121,122,123,124,{131,132,133,134, {{211,212,213,214, {221,222,223,224, {231,232,233,234; for(j=0;j<3;j++) for(k=0;k<4;k++) {
cout<<"c["<<i<<"]["<<j<<"]["<<k<<"]="<<c[i][j][k]<<" "; cout<<"&c["<<i<<"]["<<j<<"]["<<k<<"[="<<&c[i][j][k]<<" "; cout<<"*(c["<<i<<"]["<<j<<"]+"<<k<<")="<<*(c[i][j]+k)<<" "; cout<<"c["<<i<<"]["<<j<<"]+"<<k<<"="<<c[i][j]+k<<'\n'; 설명 : 3차원배열에서 c[0][0] 는배열이시작되는곳의주소를나타낸다. 즉이것은 c[0][0]= &c[0][0][0] 를의미하며주소에담긴내용은 *(c[0][0]+0) 혹은 c[0][0][0] 이다. 다음원소의주소는 c[0][0]+1 혹은 &c[0][0][1] 이며주소에담긴내용은 *(c[0][0]+1) 혹은 c[0][0][1] 이다. 이것을통해서 int로정의된위의 3차원배열은 c[0][0][0], c[0][0][1],.., c[0][1][0], c[0][1][1],.., c[0][2][0], c[0][2][1],.., c[1][0][0], c[1][0][1],.., c[1][1][0], c[1][1][1],......, c[1][2][2], c[1][2][3] 가순차적으로연결된 4 bytes 방을각각하나씩점유하고있다. 4.1.4 함수에의한정수 / 실수배열의호출 함수는배열명으로만호출될수있다. 예제 ) 실수배열로이루어진함수의호출 void int_array(int x[], int y[][4], int z[][2][2]) { printf("x[0]=%d y[0][0]=%d z[0][0][0]=%d\n\n",x[0],y[0][0],z[0][0][0]); printf("&x=%p &y=%p &z=%p\n",x,&y,&z); printf(" x=%p y=%p z=%p\n",x,y,z); printf(" x=%p y[0]=%p z[0][0]=%p\n\n",x,y[0],z[0][0]); int a[8]={1,2,3,4,5,6,7,8; int b[2][4]={{11,12,13,14, {21,22,23,24; int c[2][2][2]={{{111,112, {121,122, {{211,212, {221,222; int_array(a,b,c); // 배열명으로만호출 printf("a=%p b=%p c=%p\n",a,b,c); printf("a=%p b[0]=%p c[0][0]=%p\n",a,&b,c[0][0]); void int_array(int x[], int y[][4], int z[][2][2]) { cout<<"x[0]="<<x[0]<<'\t'<<"y[0][0]="<<y[0][0]<<'\t' <<"z[0][0][0]="<<z[0][0][0]<<"\n\n"; cout<<"&x="<<&x<<"\t"<<"&y="<<&y<<"\t"<<"&z="<<&z<<'\n'; cout<<" x="<<x<<"\t"<<" y="<<y<<"\t"<<" z="<<z<<'\n';
cout<<" x="<<x<<'\t'<<"y[0]="<<y[0]<<'\t'<<"z[0][0]="<<z[0][0]<<'\n'; cout<<"\n\n"; int a[8]={1,2,3,4,5,6,7,8; int b[2][4]={{11,12,13,14, {21,22,23,24; int c[2][2][2]={{{111,112, {121,122, {{211,212, {221,222; int_array(a,b,c); // 배열명으로만호출 cout<<"a="<<a<<'\t'<<"b="<<b<<'\t'<<"c="<<c<<'\n'; cout<<"a="<<a<<'\t'<<"b[0]="<<b[0]<<'\t'<<"c[0][0]="<<c[0][0]<<'\n'; 설명 : &x, &y, &z 번지에 a, b, c 배열의번지를복사하여사용한다. 그번지값은바로 x=a, y=b, z=c 이다. 이것은비록함수가다른명칭의배열명을사용하지만원본배열을대상으로작동하고있음을알수있다. 배열을호출하는함수에서전체배열을복사한다면시간소모적이고메모리공간을낭비할것이기때문이다. 따라서함수가인수로받아사용하는배열은명칭이다를수있으나, 원본배열이기때문에함수에서배열의원소값을변화시키면원본배열의값이변하게된다. 이것은함수가배열이아닌인수를전달받을때복사본을사용함으로, 원본은변하지않는것과는커다란차이점이다. 이것의예제를다음에서확인하자. 예제 ) 함수에서배열의변화는원본배열의변화를초래 void array(int x[]) { int i; printf(" 인수 x[] 로받아각원소에 10을더하고함수속에서출력 \n"); for(i=0; i<3; i++) { x[i] +=10; printf("x[%i]=%d\t",i,x[i]);// x[0]=10, x[1]=11, x[2]=12 printf("\n\n"); int i; int a[3]={0,1,2; printf(" 함수에넘겨주기전 main() 에서의 a[] 의원소값 \n"); for(i=0; i<3; i++) printf("a[%i]=%d\t",i,a[i]);// a[0]=0, a[1]=1, a[2]=2 printf("\n\n"); array(a); printf(" 함수에넘겨준후 main() 에서출력해본 a[] 의원소값 \n"); for(i=0; i<3; i++)
printf("\n\n"); printf("a[%i]=%d\t",i,a[i]);// a[0]=10, a[1]=11, a[2]=12 void array(int x[]) { int i; cout<<" 인수 x[] 로받아각원소에 10을더하고함수속에서출력 \n"; for(i=0; i<3; i++) { x[i] +=10; cout<<"x["<<i<<"]="<<x[i]<<'\t'; // x[0]=10, x[1]=11, x[2]=12 cout<<"\n\n"; int i; int a[3]={0,1,2; cout<<" 함수에넘겨주기전 main() 에서의 a[] 의원소값 \n"; for(i=0; i<3; i++) cout<<"a["<<i<<"]="<<a[i]<<'\t'; // a[0]=0, a[1]=1, a[2]=2 cout<<"\n\n"; array(a); cout<<" 함수에넘겨준후 main() 에서출력해본 a[] 의원소값 \n"; for(i=0; i<3; i++) cout<<"a["<<i<<"]="<<a[i]<<'\t'; // a[0]=10, a[1]=11, a[2]=12 cout<<"\n\n"; 설명 : 함수는배열을넘겨받고그배열의각원소에 10을더하였다. 그후원본배열을출력해보면각원소의값이변하였다. 함수속에서배열의 operation은원본배열의 operation 을의미한다. 즉함수는원본배열의복사본을사용하는것이아니라그원본자체를사용하고있다. 따라서배열은값에의한호출은없으며오직참조에의한호출만있다. 이와달리배열이아닌경우, 함수는복사본을사용하기때문에원본의값은변화지않는다. 예제 ) 함수인자의복사본 void fn(int x) { printf(" 인수 x로받아 10을더하고함수속에서출력 \n"); x +=10; printf("x=%d\n\n",x); // x=11
int a=1; printf(" 함수에넘겨주기전 main() 에서의 a의값 \n"); printf("a=%d\n\n",a); // a=1 fn(a); printf(" 함수에넘겨준후 main() 에서출력해본 a의값 \n"); printf("a=%d\n\n",a); // a=1 void fn(int x) { cout<<" 인수 x로받아 10을더하고함수속에서출력 \n"; x +=10; cout<<"x="<<x<<"\n\n"; // x=11 int a=1; cout<<" 함수에넘겨주기전 main() 에서의 a의값 \n"; cout<<"a="<<a<<"\n\n"; // a=1 fn(a); cout<<" 함수에넘겨준후 main() 에서출력해본 a의값 \n"; cout<<"a="<<a<<"\n\n"; // a=1 설명 : 배열이아닌인수인경우, 함수는복사본을사용하기때문에원본은변하지않는다. 따라서이것은값에의한호출이며만일원본이변하기를원한다면포인터를이용한참조에의한호출로변경하여야한다. Program 예제 연습 1) 배열에서최소값찾기 int fn(int x[], int m ) { int min, i; min=x[0]; for(i=0;i<m;++i) if(x[i]<min) min=x[i]; return (min);
int a[5]={34,56,-45,24,-88; int r; r=fn(a,5); printf("%d\n", r); int fn(int x[], int m) { int min, i; min=x[0]; for(i=0;i<m;++i) if(x[i]<min) min=x[i]; return (min); int a[5]={34,56,-45,24,-88; int r; r=fn(a,5); cout<<r<<'\n'; 연습 2) 최대, 최소값구하기 void fn(int x[]) { int i,j, tmp; for(i=0;i<7;i++) for(j=1+i;j<7;j++) if(x[j]<x[i]) { tmp=x[i]; x[i]=x[j]; x[j]=tmp; printf("min=%d \t max=%d\n",x[0],x[i-1]); int a[]={5,3,4,9,2,11,7; fn(a);
void fn(int x[]) { int i,j, tmp; for(i=0;i<7;i++) for(j=1+i;j<7;j++) if(x[j]<x[i]) { tmp=x[i]; x[i]=x[j]; x[j]=tmp; cout<<"min="<<x[0]<<"\t"<<"max="<<x[i-1]<<'\n'; int a[]={5,3,4,9,2,11,7; fn(a); 연습 3) Transpose Matrix void fn(int y[][5]) { int i,j; for(i=0;i<5;++i) { for(j=0;j<4;++j) printf("%5d", y[j][i]); putchar('\n'); int b[4][5]= { { 3,4,5,6,7, {2,6,3,4,1, {6,2,9,3,1, {3,6,3,1,0 ; fn(b); #include <iomanip.h> void fn(int y[][5]) { int i,j; for(i=0;i<5;++i) { for(j=0;j<4;++j)
cout<<setw(5)<<y[j][i]; cout<<'\n'; int b[4][5]= { { 3,4,5,6,7, {2,6,3,4,1, {6,2,9,3,1, {3,6,3,1,0 ; fn(b); 4.1.5 주소표기법 다음은배열변수의주소를알수있는다양한주소표기법이다. 예제 ) 정수 / 실수배열의주소표기법 int a[8]={1,2,3,4,5,6,7,8; int b[2][4]={{11,12,13,14,{21,22,23,24; int c[2][2][2]={{{111,112,{121,122,{{211,212,{221,222; printf("a=%p\n",a); printf("b=%p\tb[0]=%p\n",b,b[0]); printf("c=%p\tc[0]=%p\t c[0][0]=%p\n\n",c,c[0],c[0][0]); printf("&a=%p\t&a[0]=%p\n",&a,&a[0]); printf("&b=%p\t&b[0]=%p\t &b[0][0]=%p\n",&b,&b[0],&b[0][0]); printf("&c=%p\t&c[0]=%p\t &c[0][0]=%p\t &c[0][0][0]=%p\n", &c,&c[0],&c[0][0],&c[0][0][0]); int a[8]={1,2,3,4,5,6,7,8; int b[2][4]={{11,12,13,14,{21,22,23,24; int c[2][2][2]={{{111,112,{121,122,{{211,212,{221,222; cout<<"a="<<a<<'\n'; cout<<"b="<<b<<'\t'<<"b[0]="<<b[0]<<'\n'; cout<<"c="<<c<<'\t'<<"c[0]="<<c[0]<<" "<<"c[0][0]="<<c[0][0]<<"\n\n";
cout<<"&a="<<&a<<'\t'<<"&a[0]="<<&a[0]<<'\n'; cout<<"&b="<<&b<<'\t'<<"&b[0]="<<&b[0]<<" "<<"&b[0][0]="<<&b[0][0]<<'\n'; cout<<"&c="<<&c<<'\t'<<"&c[0]="<<&c[0]<<" "<<"&c[0][0]="<<&c[0][0]<<'\t' <<"&c[0][0][0]="<<&c[0][0][0]<<"\n\n"; 설명 : 위에기술된주소표기법중배열명 a, b, c는함수인자로배열을호출할때사용하며, 아래와같은규칙을갖는주소표기법은주소번지를변수로갖는포인터에사용한다. 차원 배열 포인터대입주소표기법 무차원배열 : int x; &x 1차원배열 int a[]; &a[0] a 2차원배열 int b[][3]; &b[0][0] b[0] 3차원배열 int c[][2][3]; &c[0][0][0] c[0][0] 4차원배열 int d[][2][3][4]; &d[0][0][0][0] d[0][0][0] 이외의것들은단순히변수의시작주소를알아보는데사용할수있는주소표기법이다. 4.2 문자배열 char 배열은원소당 1 byte가배당된다. global과 static char 배열은인위적으로초기화하지않는한 default(null,'\0') 로초기화된다. 자동변수배열은인위적인초기화가필요하다. 문자배열의끝원소는 NULL(\0) 이어야만한다. NULL은출력과관계가있고한문자열 (string) 의출력은 NULL에서끝난다. 4.2.1 1 차원배열 초기화방법 char a[5]={'s','t','p','q','\0'; 또는 a[]={'s','t','p','q','\0'; 또는 a[]="stpq"; \0 는끝을알리는 NULL문자이다. 마지막예의경우끝에자동으로 NULL이들어간다. 또는원소대입법으로초기화 char a[5]; a[0]='s'; a[1]='t'; a[2]='p'; a[3]='q'; a[4]=null; 수에관한배열과마찬가지로 1차원배열의시작주소는배열명 a 또는 &a[0] 이다. 주의 : C에서포인터대입주소표기법은 %p format에의해배열원소의주소가출력되고, 동시에 %s format에의해그주소로부터 NULL('\0') 을만날때까지의문자열이출력된다. 그러나 C++ 에서는 %p format이없기때문에오직문자열만출력된다. 따라서 C++ 에서변수의주소는 4.1.5에기술된여러표기법중문자열출력과관계없는하나를선택하여사용한다.
예제 ) 1차원배열초기화및출력과원소별주소 int i; char a[5]={'a','b','c','d','\0'; /* 배열원소별값과주소및문자열출력 */ for(i=0; i<5; i++) { printf("a[%d]=%c ",i,a[i]); printf("&a[%d]=%p ",i,&a[i]); printf("&a[%d]=%s\n",i,&a[i]); printf("\n"); /* 나열된원소값과주소및문자열 (string) 출력 */ for(i=0;i<5;i++) { printf("*(a+%d)=%c ",i,*(a+i)); printf("&*(a+%d)=%p ",i,&*(a+i)); printf("a+%d=%p ",i,a+i); printf("a+%d=%s\n",i,a+i); printf("&a=%p\n",&a); int i; char a[5]={'a','b','c','d','\0'; /* 배열원소별값과주소출력 */ for(i=0; i<5; i++) { cout<<"a["<<i<<"]="<<a[i]<<" "; cout<<"&a["<<i<<"]="<<&a[i]<<'\n'; cout<<'\n'; /* 나열된원소값과주소출력방법 */ for(i=0;i<5;i++) { cout<<"*(a+"<<i<<")="<<*(a+i)<<"\t"; cout<<"&*(a+"<<i<<")="<<&*(a+i)<<"\t"; cout<<"a+"<<i<<"="<<a+i<<'\n'; cout<<'\n'; cout<<" 배열 a의시작주소 &a="<<&a<<'\n';
설명 : C에서는 %p format에의해 a, a+1, a+2,... 또는 &a[0], &a[1], &a[2],... 등으로원소별주소를출력할수있다. 그리고동시에 %s format로그주소로부터 NULL을만날때까지의모든문자열을출력한다. 그러나 C++ 에서는주소를알아내는 %p format이없기때문에그주소로부터 NULL까지의문자열만출력한다. 이것은모든차원의문자배열에적용되는공통사항이며정수나실수배열과구별되는특성이다. 즉포인터에사용할수있는문자배열의주소표기법은그것이곧그주소로부터 NULL까지의문자열을출력하라는뜻이된다. 따라서 C++ 에서는배열원소각각의주소를출력할수있는뚜렷한방법이없다. 4.2.2 2 차원배열 초기화방법 char b[2][3]={{'a',b,'c', {'D','E','\0' 또는 char b[2][3]={'a',b,'c','d','e','\0' char b[][3]={{'a',b,'c', {'D','E','\0' 또는 char b[][3]={'a',b,'c','d','e','\0' 원소대입법으로초기화 b[0][0]= A, b[0][1]= B, b[0][2]= C b[1][0]= D, b[1][1]= E, b[1][2]= \0 NULL은여러곳에들어갈수있다. 각행의끝을알리는방법으로초기화하면 char b[2][3]={{'a',b,'\0', {'D','E','\0' 또는 char b[2][3]={'a',b,'\0','d','e','\0' char b[][3]={{'a',b,'\0', {'D','E','\0' 또는 char b[][3]={'a',b,'\0','d','e','\0' 원소대입법으로초기화 b[0][0]= A, b[0][1]= B, b[0][2]= \0 b[1][0]= D, b[1][1]= E, b[1][2]= \0 문자열 (string) 로초기화열의마지막문자가 NULL이되지않으면초기화할수없다. 따라서열의수보다항상 1개적은글자수이어야한다. char b[2][3]={ {AB", "{DE"; 이것은 char b[2][3]={{'a',b,'\0', {'D','E','\0' 나또는 b[2][3]={"ab", "DE" ; 또는 char b[2][3]={'a', B,'\0','D','E','\0' 와동등하다. int b[][3] 로도초기화. char b[2][]; 는틀린선언이다. 예제 ) 2차원배열초기화및출력과원소별주소 char b[2][3]={{'a','b','c', {'D','E','\0'; int i, j; for(j=0; j<3; j++) {
printf("b[%d][%d]=%c ",i,j,b[i][j]); // 원소값 printf("&b[%d][%d]=%p ",i,j,&b[i][j]); // 원소주소 printf("&b[%d][%d]=%s\n",i,j,&b[i][j]); // 문자열 putchar('\n'); for(j=0; j<3; j++) { printf("*(b[%d]+%d)=%c ", i,j,*(b[i]+j)); // 원소값 printf("b[%d]+%d=%p ",i,j,b[i]+j); // 원소주소 printf("b[%d]+%d=%s\n",i,j,b[i]+j); // 문자열 putchar('\n'); printf("b=%p &b=%p &b[0]=%p\n",b,&b,&b[0]); char b[2][3]={{'a','b','c', {'D','E','\0'; int i, j; for(j=0; j<3; j++) { cout<<"b["<<i<<"]["<<j<<"]="<<b[i][j]<<" "; // 원소값 cout<<"&b["<<i<<"]["<<j<<"]="<<&b[i][j]<<'\n'; // 문자열 cout<<'\n'; for(j=0; j<3; j++) { cout<<"*(b["<<i<<"]+"<<j<<")="<<*(b[i]+j)<<" "; // 원소값 cout<<"b["<<i<<"]+"<<j<<"="<<b[i]+j<<'\n'; // 문자열 cout<<'\n'; cout<<"b="<<b<<" &b="<<&b<<" &b[0]="<<&b[0]<<'\n'; 위에서언급한바와같이 C++ 에서원소각각의주소를알아내는 format은항상문자열이 출력된다. 4.2.3 3 차원배열 초기화의가장보편적방법은열의마지막원소를 NULL 로하는것이다. 문자열로초기화하려면열의마지막원소는항상 NULL 이어야만가능하다.
1) 나열법으로의초기화 char c[2][3][4]={'a','b','c','d', 'e','f','g','h', 'i','j','k','l', 'm','n','o','p', 'q','r','s','t', 'u','v','w','\0'; char c[2][3][4]={'a','b','c','d', 'e','f','g','h', 'i','j','k','\0', 'm','n','o','p', 'q','r','s','t', 'u','v','w','\0'; char c[2][3][4]={'a','b','c','\0', 'e','f','g','\0', 'i','j','k','\0', 'm','n','o','\0', 'q','r','s','\0', 'u','v','w','\0'; 문자열로초기화 : char c[2][3][4]={ abc, efg, ijk, mno, qrs, uvw ; 문자열로초기화시, 각열의원소수는자동으로 NULL 이들어가게하기위하여배열의열의 수보다항상 1 이작다. 즉, c[][3][4] 의경우, 배열의열수 =4, 문자수 =3 2) 면에대한묶음법 char c[2][3][4]={{'a','b','c','d', 'e','f','g','h', 'i','j','k','l',{'m','n','o','p', 'q','r','s','t', 'u','v','w','\0'; or char c[2][3][4]={{'a','b','c','d', 'e','f','g','h', 'i','j','k','\0',{'m','n','o','p', 'q','r','s','t', 'u','v','w','\0'; or char c[2][3][4]={{'a','b','c','\0','e','f','g','\0','i','j','k','\0',{'m','n','o','\0','q','r','s','\0', 'u','v','w','\0'; 문자열로초기화 : char c[2][3][4]={{ abc, efg, ijk,{ mno, qrs, uvw ; 3) 면과행에대한묶음법 char c[2][3][4]={{{'a','b','c','d', {'e','f','g','h', {'i','j','k','l', {{'m','n','o','p', {'q','r','s','t', {'u','v','w','\0'; or char c[2][3][4]={{{'a','b','c','d', {'e','f','g','h', {'i','j','k','\0', {{'m','n','o','p', {'q','r','s','t', {'u','v','w','\0'; or char c[2][3][4]={{{'a','b','c','\0',{'e','f','g','\0',{'i','j','k','\0', {{'m','n','o','\0',{'q','r','s','\0', {'u','v','w','\0'; 문자열로초기화 : char c[2][3][4]={{{ abc,{ efg,{ ijk,{{ mno,{ qrs,{ uvw ; int c[][3][4] 로도초기화가가능. 예제 ) 3차원배열초기화와원소별및문자열출력 int i,j,k; char c[2][3][4]={{{'a','b','c','d', {'e','f','g','h', {'i','j','k','\0', {{'m','n','o','p', {'q','r','s','t', {'u','v','w','\0'; for(j=0;j<3;j++) for(k=0;k<4;k++) { printf("c[%d][%d[%d]=%c ",i,j,k,c[i][j][k]);
printf("&c[%d][%d[%d]=%p ",i,j,k,&c[i][j][k]); printf("&c[%d][%d[%d]=%s\n",i,j,k,&c[i][j][k]); putchar('\n'); for(j=0;j<3;j++) for(k=0;k<4;k++) { printf("*(c[%d][%d]+%d)=%c ",i,j,k,*(c[i][j]+k)); printf("c[%d][%d]+%d=%p ",i,j,k,c[i][j]+k); printf("c[%d][%d]+%d=%s\n",i,j,k,c[i][j]+k); int i,j,k; char c[2][3][4]={{{'a','b','c','d', {'e','f','g','h', {'i','j','k','\0', {{'m','n','o','p', {'q','r','s','t', {'u','v','w','\0'; for(j=0;j<3;j++) for(k=0;k<4;k++) { cout<<"c["<<i<<"]["<<j<<"]["<<k<<"]="<<c[i][j][k]<<" "; cout<<"&c["<<i<<"]["<<j<<"]["<<k<<"]="<<&c[i][j][k]<<'\n'; cout<<'\n'; for(j=0;j<3;j++) for(k=0;k<4;k++) { cout<<"*(c["<<i<<"]["<<j<<"]+"<<k<<")="<<*(c[i][j]+k)<<" "; cout<<"c["<<i<<"]["<<j<<"]+"<<k<<"="<<c[i][j]+k<<'\n'; 설명 : 문자열출력은시작되는주소로부터처음만나는 NULL까지가출력되므로다음과같은형태로나타난다. abcdefghijk mnopqrstuvw bcdefghijk nopqrstuvw.... jk vw k w
문자열입력시공백문자의역할 문자열입력시 C 의 scanf() 나 C++ 의 cin 은공백문자를 NULL 로간주한다. 따라서그이후의 문자는입력되지않는다. const int MAX=80; char str[max]; printf("enter a string with a space\n"); scanf("%s",&str); printf("%s\n",str); const int MAX=80; char str[max]; cout<<"enter a string without a space\n"; cin>>str; cout<<str<<'\n'; 설명 : 예제에서보듯, 만약공백을가진두단어이상의문자열을입력하려고시도하면 C의 scanf() 와 C++ 의 cin은공백문자를종료문자인 NULL로간주한다. 따라서공백이후에입력되는문자는출력되지않는다. 이것을방지하기위하여다음의프로그램으로고쳐야한다. const int MAX=80; char str[max]; printf("enter a string with a space\n"); gets(str); puts(str); const int MAX=80; char str[max]; cout<<"enter a string with a space\n"; cin.get(str, MAX); cout<<str<<'\n';
cin.get( 배열명, 배열크기 ) 은 get() 함수가 cin 의멤버함수이며객체지향형에서언급될것이 다. 다중라인입력 const int MAX=80; char str[max]; cout<<"enter strings with returns\n"; cout<<"if you stop entering, $ then return\n"; cin.get(str, MAX, '$'); cout<<str<<'\n'; cin::get() 함수는세번째인자로입력의종료를알리는문자를넣음으로서다중라인의입력을할수있다. 예제 ) 문자열로초기화및배열의각행문자열출력 int i,j,k; char c[2][2][4]={{"abc","efg",{"mno","qrs"; /* "ABC\0", "EFG\0" 등으로초기화된다. */ for(j=0;j<2;j++) for(k=0;k<4;k++) { printf("c[%d][%d[%d]=%c ",i,j,k,c[i][j][k]); printf("&c[%d][%d[%d]=%p ",i,j,k,&c[i][j][k]); printf("&c[%d][%d[%d]=%s\n",i,j,k,&c[i][j][k]); putchar('\n'); for(j=0;j<2;j++) for(k=0;k<4;k++) { printf("*(c[%d][%d]+%d)=%c ",i,j,k,*(c[i][j]+k)); printf("c[%d][%d]+%d=%p ",i,j,k,c[i][j]+k); printf("c[%d][%d]+%d=%s\n",i,j,k,c[i][j]+k);
int i,j,k; char c[2][2][4]={{{"abc",{"efg",{{"mno",{"qrs"; /* "ABC\0", "EFG\0" 등으로초기화된다. */ for(j=0;j<2;j++) for(k=0;k<4;k++) { cout<<"c["<<i<<"]["<<j<<"]["<<k<<"]="<<c[i][j][k]<<" "; cout<<"&c["<<i<<"]["<<j<<"]["<<k<<"[="<<&c[i][j][k]<<" \t"; cout<<"*(c["<<i<<"]["<<j<<"]+"<<k<<")="<<*(c[i][j]+k)<<" "; cout<<"c["<<i<<"]["<<j<<"]+"<<k<<"="<<c[i][j]+k<<'\n'; cout<<'\n'; 4.2.4 배열명으로의출력 C에서각차원배열명 a, b, c의 %p format은배열이시작되는주소즉 &a[0], &b[0][0], &c[0][0][0] 값과같으므로출력시 %s format을사용하면시작주소부터처음만나는 NULL 까지의문자들을출력한다. 그러나포인터변수의주소대입에배열명을 1차에는사용할수있으나 2차또는 3차원에는사용할수없다. 배열명은주로함수인수전달에서만사용한다 (C++ 에서도동등 ). 포인터는아래의규칙으로기술된주소표기법만을대입받을수있다. 이것은이미배운정수나실수배열에서도같다. %p format이없는 C++ 에서의무차원및 1차원배열명은문자나문자열을출력하고 2차원이상의배열명은주소를출력한다. 그리고 C++ 에서문자배열에대한아래표기법은오직문자열만출력하고주소는출력하지못한다. 포인터에대입주소표기법및문자배열의문자열출력표기법 차원 배열 포인터및문자열출력주소표기법 무차원배열 : char ch; &ch 1차원배열 char a[]; &a[0] a 2차원배열 char b[][3]; &b[0][0] b[0] 3차원배열 char c[][2][3]; &c[0][0][0] c[0][0] 4차원배열 char d[][2][3][4]; &d[0][0][0][0] d[0][0][0] 예제 ) 문자및문자열출력 char ch='a';
char a[6]={'a','b','c','d','e','\0'; char b[2][3]={{'a','b','\0', {'d','e','\0'; char c[2][2][4]={{"abc","efg",{"mno","qrs"; printf("ch=%c &ch=%p\n\n",ch, &ch); printf("a=%s a=%p\n",a,a); printf("a+1=%s a+1=%p\n\n",a+1,a+1); printf("b=%s b=%p\n",b,b); // 1행출력 : abc printf("b+1=%s b+1=%p\n\n",b+1, b+1); // 2행출력 : de printf("c=%s c=%p\n",c,c); // 1면출력 : ABC printf("c+1=%s c+1=%p\n\n",c+1,c+1); // 1면출력 : MNO char ch='a'; char a[6]={'a','b','c','d','e','\0'; char b[2][3]={{'a','b','\0', {'d','e','\0'; char c[2][2][4]={{"abc","efg",{"mno","qrs"; cout<<"ch="<<ch<<"\n\n"; cout<<"a="<<a<<"\t\t"<<"&a="<<&a<<"\n"; cout<<"b[0]="<<b[0]<<"\t\t"<<"b="<<b<<"\n"; // ab cout<<"b[0]+1="<<b[0]+1<<"\t"<<"b+1="<<b+1<<'\n'; // b cout<<"c[0][0]="<<c[0][0]<<'\t'<<"c="<<c<<'\n'; // ABC cout<<"c[0][0]+1="<<c[0][0]+1<<'\t'<<"c+1="<<c+1<<'\n'; // BC 설명 : C에서는차수에관계없이배열명만으로 %s format에의해문자열을출력하고있다. 이와달리 C++ 에서 1차원배열명은문자열을, 2, 3차배열명은주소를각각출력한다. 따라서 C++ 에서문자열을얻으려면위에기술된포인터및문자열출력주소표기법을사용하여야한다. 이것은 C에도공통적으로사용되는방법이다. 4.2.5 함수에의한문자배열의호출 정수및실수배열에서사용한방법과같다. 예제 ) 문자배열로이루어진함수의호출 void ch_array(char x[], char y[][4], char z[][2][2]) { int i,j,k; /* 배열의각원소별출력 */ for(i=0; i<8; i++) printf("a[%i]=%c\t",i,x[i]);
printf("\n\n"); for(i=0;i<2;i++) for(j=0;j<4;j++) printf("b[%d][%d]=%c\t",i,j,y[i][j]); printf("\n\n"); for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) printf("c[%d][%d][%d]=%c\t",i,j,k,z[i][j][k]); putchar('\n'); char a[8]={'a','b','c','d','e','f','g','\0'; char b[2][4]={ {'a','b','c','d',{'e','f','g','\0'; char c[2][2][2]={{{'a','b', {'C','D', {{'E','F', {'G',NULL; ch_array(a,b,c); void ch_array(char x[], char y[][4], char z[][2][2]) { int i,j,k; /* 배열의각원소별출력 */ for(i=0; i<8; i++) cout<<"a["<<i<<"]="<<x[i]<<"\t"; cout<<"\n\n"; for(i=0;i<2;i++) for(j=0;j<4;j++) cout<<"b["<<i<<"]["<<j<<"]="<<y[i][j]<<'\t'; cout<<"\n\n"; for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) cout<<"c["<<i<<"]["<<j<<"]["<<k<<"]="<<z[i][j][k]<<'\t'; cout<<'\n'; char a[8]={'a','b','c','d','e','f','g','\0'; char b[2][4]={ {'a','b','c','d',{'e','f','g','\0'; char c[2][2][2]={{{'a','b', {'C','D', {{'E','F', {'G',NULL; ch_array(a,b,c);
설명 : 함수속의인수는같은차원의배열로표기되어야한다. 1 차원의경우 x[] 또는 x[8], 2 차원의경우 y[][4] 또는 y[2][4], 3 차원의경우 z[][2][2] 또는 z[2][2][2] 로호출자의인수를넘 겨받는다.