2010. 7. 10. 02:16

제 25장 다차원 배열

  


※ 포인터, 배열은 무엇인지를...잘 숙지해야 합니다.
    ->> 더블포인터를 위한 공부를 위해서 집중하세요
        >> 포인터 개념이 이해가 안되시면 다시 포인터/배열부분 강의를
              한번 더 공부하고 오시기 바랍니다.


다차원 배열이란? ; 2차원 이상의 배열

 - 배열 선언 예)
   
   int arr[5];             // 1차원 구조
   int arr1[10][6];     // 2차원 구조
   int arr2[4][4][5];  // 3차원 구조

 ※ 2차원배열만 이해를 한다면 나머지 2+n 차원 배열이 이해가 빨라요
    tip => 2차원 이상은 실제 쓰일 경우가 거의 없습니다.

 

 


2차원 배열의 선언

  - 2차원적 메모리를 구성

 

 ex)

 int main()
{
 arr1[4]; 
 arr2[3][4]; // 3은 세로, 4는 가로를 의미라고 생각
                  // 3 X 4 인 배열 선언
 ......           // 배열크기는 3x4(12)x4byte = 48 byte

 return 0;
}

 

예제)=============================================================  

 

/* 2차원 배열 요소의 접근 방법 */

 

#include <stdio.h>

int main()
{
 int arr[3][3];
 arr[0][0] = 1;
 arr[1][0] = 2;
 arr[2][0] = 3;

                                                         
 ....

}     // 참고 : 배열 ; 상수포인터

      // 그림 : 예제이해

 

 

 

예제)=============================================================  


#include <stdio.h>

int main(void)
{
 int Array[4][2];
 int i, j;

 int number;

 for(i=0; i<4; i++)
 {
  for(j=0; j<2; j++)
  {
   printf("%d 층 %d호 인구입력 : ", i+1, j+1);
   scanf("%d", &Array[i][j]);
  }
 }

 for(i=0; i<4; i++)
 {
  number = 0;

  for(j=0; j<2; j++)
  {
   number += Array[i][j];
  }

 printf("%d 층, 총인구 : %d \n", i+1, number);

 }

 return 0;
}

================================================================  

 

 

 

다차원 배열의 실제 메모리 구성
 
 - 접근 방법을 2차원적으로 해석할뿐, 1차원 배열과 동일하다.

 

 - 2차원배열이라고해서 메모리구조는 2차적으로 되는것이 아니다.
    >> 배열선언시 2차원배열선언시, 1차원적인 배열메모리를 생각하세요
 


 - 그림참고(배열선언시 메모리구조의 모습)

 

 

 

2차원 배열 ! 선언과 동시에 초기화

 

 - 방법 1 : 행 단위로 모든 요소들을 초기화

 

 - 방법 2 : 행 단위로 일부 요소들만 초기화
   
 ex 1)

int Array[3][3] = {
 
 {1, 2, 3},
 {3, 4, 5},
 {5, 6, 7}

}


 ex 2)

int Array_1[3][3] = {

{0},       // 나머지 Array_1[0][1], Array_1[0][2]는 0으로 초기화
{1, 2},   // 나머지 Array_1[1][2]는 0으로 초기화 
{4, 5, 6}

}


 ex 3)

int Array_2[3][3] = {1, 2, 3, 4, 5, 6}; // 이렇게 해도 문법적으로 문제 없다


 

초기화 리스트에 의한 배열 크기의 결정

 

 - 1차원 배열의 예
  >> int Array[] = {1, 2, 3}; // 정상 OK

 

 - 2차원 배열의 예
  >> int Array[][] = {1, 2, 3, 4, 5, 6}        // Error!
  >> int Array[][4] = {1, 2, 3, 4, 5, 6, 7, 8} // OK
  >> int Array[][2] = {1, 2, 3, 4, 5, 6, 7, 8} // OK

 

   ===> 두개의 인덱스 모두를 생략할 수는 없다.
           둘 중에 한개의 인덱스만 선언해주면 컴파일러가 자동으로 인덱스를 인식한다.
 


3차원 배열의 선언과 의미

 

  - 3차원적 메모리를 구성(있다는것만 아시면 되요)

 

  - 일반적으로 거의 쓰이지 않는다.(배열과 포인터를 이용하기 위한 용도만...)

 

  - 4차원 이상은 4차원형태이므로 구조적인 이해가 불가

 
 

 
Posted by 토실토실천재
2010. 7. 10. 02:14

 

제 24장 포인터와 함수에 대한 이해 - 2

 

 


Call by Value (call : 함수를 호출한다)

 

 - 값의 복사에 의한 함수 호출
 
 - 가장 일반적인 함수 호출 형태

 

예제)=============================================================  

 

#include <stdio.h>

int Add(int num1, int num2); // 더하기 함수 선언

int main()
{
 int val1 = 100;
 int val2 = 200;
 
 printf("더하기값(Add 함수값) : %d \n", Add(val1, val2));

 return 0;
}

int Add(int num1, int num2) // 더하기 함수 정의
{
 return num1 + num2;
}

// main 함수내의 val1, val2값을
// Add함수에 매개변수에 복사한다는 의미

 

 

 

예제)=============================================================  


#include <stdio.h>

 

void swap(int a, int b);


int main(void)
{
 int number_1 = 10;
 int number_2 = 300;

 printf("number_1 = %d \n", number_1);
 printf("number_2 = %d \n", number_2);

 swap(number_1, number_2);

 return 0;
}

 

void swap(int a, int b)
{
 int temp;

 temp = a;
 a = b;
 b = temp;

 printf("a = %d \n", a);
 printf("b = %d \n", b);

}


// val1, val2의 값이 그대로 복사해서 Add함수의 num1, num2에 전달된다.
// 즉, val1, val2와 num1, num2는 별개의 변수다



================================================================  

 

call by Reference 
 
 - 참조(참조를 가능케 하는 주소값)를 인자로 전달하는  형태의 함수호출

 

예제)=============================================================  

 

#include <stdio.h>

 

void P_add(int* p)      // main함수의 number의 주소값을 인자로 받는다
{
 (*p)++;                     // p는 main함수의 number을 가리키므로 number값이 1증가한다.
}

int main()
{
 int number = 100; 

 P_add(&number);      // number의 주소값을 넘긴다.

 printf("number = %d \n", number);

 return 0;
}

 

================================================================  

 

 

scanf 함수 호출시 &를 붙이는 이유?

 

 - scanf("%d", &val);
   // scanf함수가 val이라는 변수에 접근하기 위해서
   // 주소값을 찾아서 실행된다.(call by reference)

 - scanf("%s", str);
   // 배열이름이 주소값이며, 포인터이름 자체가 주소값 str 이기때문에
   // &를 붙일 필요가 없다.

 

 


포인터가 가리키는 변수의 상수화

 - int a = 20;
   const int* p = &a;
   *p = 10; // Error
   a = 30;  // ok!;
 // p가 a를 봤을때만! a는 상수다
 // p라는 포인터로 a값을 변경 불가능하다!

 

 

 

포인터 상수화

 - int a = 20;
   int b = 100;
   int* const  p = &a;
   p = &b;   // Error
   *p = 30;  // ok!;
// p라는 포인터가 가리키는 값 자체를 상수화
// p는 무조건! 항상 a만 가리킬수 있음.

 - const int* const p = &a 이경우는
   위의 두가지 특징을 다 가진다.
  > p는 무조건 a만 가리키고 p를 통해서 a값을 변강할수 없다.

 

 


const 키워드를 사용하는 이유

 

 - 컴파일시 잘못된 연산에 대한 에러메시지
 
 - 프로그램을 안정적으로 구성

 

 

 

Posted by 토실토실천재
2010. 7. 10. 02:12
제 23장 포인터와 함수에 대한 이해 - 1


call by Reference
call by Value 

이번장은 저 위에 두가지 개념을 확실히 이해합시다!


함수의 인자로 전달하기

 - 값의 복사에 의한 전달 예)

void Fuction(int a) // val의 값을 변수 a에 복사
{
a++;
return a;
}

int main(void)
{
int val = 10; 
val = Function(val); // val이 지니고 있는 값을 전달하는것이다.
return 0;
}                                  // 변수 val, a는 다름(별개의 것)



배열의 인자로 전달하기
 // 배열전체 복사할수 없다(불가능)

 - 배열의 주소값을 전달한다!!

 - 값의 복사에 의한 전달 예제)

예제)=============================================================   


#include <stdio.h>

void Function(int* New_Array);

int main()
{
int Array[5] = {0, 1, 2, 3, 4};        // index값이 5인 배열 Array 선언
int i;

printf("Array배열의 요소 : ");

for(i=0; i<5; i++)
printf("%d ", *(Array + i)); // Array배열을 순서대로 출력

Function(Array);          // Function 함수호출(인자값은 Array의 주소로)
printf("\n배열요소값을 변경후 : ");// Array의 이름자체가 주소라고 인식을 하고 넘어가요

for(i=0; i<5; i++)         // 다시 Array배열 순서대로 출력
printf("%d ", *(Array + i));

printf("\n");

return 0;
}

void Function(int* New_Array) // main함수에서의 Array의 주소값을 받는다.
{           // 배열의 형태도 가리키는 포인터 형태이므로 
int j;          // int* 형식으로 주소값을 받는다!
int temp;

for(j=0; j<3; j++)
{
temp = *(New_Array+j); // 임시변수로 값자체를 바꾼다.
*(New_Array+j) = *(New_Array+4-j);// tip) : *(A+i) == A[i]
*(New_Array+4-j) = temp;
}
}

// Array값의 변경을 Function 함수에서 변경한셈이다.

// 즉, Function 함수가 int*형(int Array[])을 받기 때문에 똑같이 int*형을 선언한뒤
// Array의 주소값을 받는 셈 
// 배열전체자체를 받는건 불가능하다

=================================================================   

배열이름, 포인터 sizeof 연산 

 - 배열이름 : 배열 전체크기를 바이트 단위로 넘김

 - 포인터 : 포인터의 크기(4)를 바이트 단위로 넘김

예제)=============================================================   


#include <stdio.h>

int Sum_Array(int* N_Array, int index);

int main()
{
int Array[8] = {1, 2, 3, 4, 5, 6, 7 , 8};
int Serve_Sum;
printf("index of Array = %d \n", sizeof(Array)/sizeof(int));
Serve_Sum = Sum_Array(Array, sizeof(Array)/sizeof(int));
printf("Sum of Array's factors : %d \n", Serve_Sum);

return 0;
}
// sizeof연산을 이용한 논리적인 인자전달을 한다면
// 코드의 변화시 수정해줄 요소가 적어진다.
// 어떠한 환경에 변화에 따라서 프로그램이 유연하게 동작하도록
// 코딩을 하는것이 최선이다
// int대신 4를 넣어도 되지만, 시스템에 따라서 int는 2, 4, 8 이 인식되기때문에
// sizeof(int)라고 인자전달을 하게 코딩한것임

int Sum_Array(int* N_Array, int index)
{
int i, sum=0;

for(i=0; i<index; i++) // i<index ==> i< sizeof(N_Array) (4가 리턴될뿐)
sum += *(N_Array+i); // sum += N_Array[i]

return sum;
}

=================================================================   


"int * Array" vs "int Array[]"

 - 둘다 같은 의미를 지닌다.

 - int Array[]은 배열보다는 포인터에 가깝다.

 - 매개변수 안에서는 저렇게 사용이 가능 : Array[];(하지만 자제하시오)
 
 - 배열과 포인터 혼돈을 피하기위해서는 int* Array 형태가 더 좋다


Posted by 토실토실천재