본문 바로가기

책 정리/윤성우의 열혈 C

배열과 포인터 정리 (포인터와 배열의 시작)

배열과 포인터 함수의 개념은 어렵지 않으나 이 셋을 연계해서 이해하다보면 혼란스러울수 있으므로 정리를 한다.

 

 

배열이란?

1차원배열, 2차원배열이 있고, '둘 이상의 변수를 모아 놓은 것', 데이터를 저장하고 처리하는 경우에 유용하게 사용할 수 있는 것이 배열이다. 그리고 다수의 변수로는 할 수 없는일을 배열로는 가능하다.(반복문을 이용해 순차적으로 접근가능)

 

 

1차원 배열을 선언할때는 '배열이름, 자료형, 길이정보' 가 필요하고 변수가 '나란히' 선언된다.

ex) int arr[7] (자료형, 배열이름, 길이정보) -> int형 변수 7개로 이뤄진 배열 arr 선언

 

 

배열의 접근방법

arr[0], arr[1], arr[2] ..........

*arr, *(arr+1), *(arr+2)......

 

 

배열의 이름은 주소 값이 저장되어 있고 포인터 상수 이므로 포인터 변수처럼 접근이 가능하다. 그러나 상수 이므로 배열이름에 저장된 주소 값을 변경할순 없다.

 

 

----------------------------------------------------------------------------------------------------------------------------------

문자열

char형 배열에 문자열을 저장하면 끝에 '\0' 문자(널) 가 자동으로 삽입 된다. 널 문자가 저장이 되어있으면 문자열 이라고 하고 널문자가 없으면 문자배열이다. (널 문자의 아스키코드 값은 0 이고, 공백은 32이 이다,문자열끝을 알리는 역할)

 

선언방법: char str[14] = "Good morning!";

 

scanf("%s", str); -> 이렇게 문자열을 저장이 가능하다.

 

문자열을 입력받는 배열의 이름은 시작 주소값을 가지고 있으므로 &을 사용하지 않아도 되나, 문자열을 입력받는 배열이 아닌경우에 를 저장할때에는 &arr[i] 이렇게 사용을 해야한다. "문자열"을 입력받을때만 &을 안붙힌다.

다른 함수에서 참조를해서 변경을 하려면 그곳의 주소 값을 알아야 가능하다. 그래서 &연산자를 붙힌다.

 

 

문자열도 str[1] = 'a'; 이런식으로 값의 변경이 가능하다.

 

 

C언어에서는 모든 문자열 끝에 널 문자{'\0') 가 자동으로 삽입이 되고 이 널 문자로 문자열의 끝을 판단한다.

널 문자가 없으면 문자열이 아닌 문자배열 이다.

-널 문자는 배열 또는 char형 포인터 변수에도 저장이 된다.  char str1[], char* str2

-배열 형태로 선언한 문자배열은 배열이름에 저장된 주소 값을 변경할순 없으나 그 내용은 변경이 가능하다.

(변수 형태의 문자열)

-포인터 변수형태로 선언한 문자열은 포인터 변수의 주소 값은 변경이 가능하나, 그 내용은 변경이 불가능 하다.

(상수 형태의 문자열)

 

 

printf("My home");  이 문장은 메모리의 어느 곳에 My home 이 저장이 되어 그 저장된 곳의 주소 값을 전달받아 printf 함수가 출력하는 형태이다. 즉, 문자열을 통째로 전달받는 함수가 아닌, 문자열의 주소 값을 전달받는 함수이다.

 

scanf함수는 공백을 기준으로 문자열을 입력받기 때문에 공백이 없는 한 문자만 입력이 가능하다.

 

 

------------------------------------------------------------------------------------------------------------------------

 

포인터의 이해

 

주소 값은 1바이트 단위로 메모리에 할당이 되고 포인터는 주소값의 저장을 목적을 선언하며 선언방식은 아래와 같다.

type* ptr;, type ptr[];

- 포인터 변수의 자료형과 가르키는 데이터의 자료형이 일치해야 한다.

- type들을 '포인터 형' 이라고 하며 이 포인터 형은 메모리 공간을 참조하는 기준이 된다.

- '포인터 형'의 크기는 일반 자료형의 크기가 아니라 컴퓨터 비트수랑 동일하다.

 

배열의 이름은 배열의 시작주소를 가지기 때문에 '포인터 상수'로 불린다.

- 포인터 상수 이므로 주소 값의 변경이 불가능하다.

 

포인터와 관련된 연산자

&(주소값 반환), *(포인터가 가르키는 메모리공간에 접근), []

 

 

포인터를 선언만 해 놓고, 이후에 유효한 주소 값을 채워 넣을 생각이라면 0(NULL)로 초기화를 하는 것이 좋다.

----------------------------------------------------------------------------------------------------------------------------------

 

포인터와 배열

 

포인터를 대상으로 하는 증감연산은 포인터 형에 따라 결정이 된다.

- int형 일경우 1 증감은        = +4, -8    = n x sizeof(int)

- double형 일경우 1 증감은  = +8, -8    = n x sizeof(double)

결국 n x sizeof(type) 이라는 것이다.

 

arr[i] == *(arr+i)   

 

 

포인터 배열: 포인터 배열로 이뤄져 주소 값의 저장이 가능한 배열을 가르켜 '포인터 배열' 이라 한다.

선언방법: int* arr1[20];,        double* arr2[30];

 

문자열을 저장하는 포인터 배열: char* arr[3]={"Simple", "String", "Array"};

-char형 포인터 배열이고, 이 세 문자열이 메모리에 저장이되고 그 주소 값을 포인터 배열에 저장을 하는 원리이다.

 

 

----------------------------------------------------------------------------------------------------------------------------------

포인터와 함수에 대한 이해

 

함수는 인자를 전달받도록 정의할 수 있고, 함수호출시 전달되는 인자의 값은 매개변수에 복사가 된다. 복사가 되기때문에 함수가 호출되고 나면, 전달되는 인자와 매개변수는 별개가 된다.

 

매개변수로 배열을 선언할 수 없다. 신에 배열의 주소 값을 전달하는 것은 가능하다.

- void ShowAray(int* param, int len); , void ShowAray(int param1 [], int len);  

         매개변수의 선언시에만 같은 선언으로 간주함.

- 값의 접근 뿐만 아니라 변경도 가능하다.

- 함수 내에서는 인자로 전달된 배열의 길이를 계산할 수 없으므로 길이도 같이 인자로 전달한다.

 

Call-by-value

- 값을 전달하는 형태의 함수호출

- 저장된 값의 변경이 불가 ( 값을 변경하더라도 실제 값이 변경되지 않고 복사본이 변경이 된다)

 

Call-by-reference

- 주소 값을 전달하는 형태의 함수호출

- 주소 값에 접근을 하여 값의 변경이 가능 (실제 값에 접근하여 변경을 하므로 실제 값이 변경이 된다)

 

scanf 함수에 & 를 붙히는 이유도 실제 값에 접근을 하여 값을 입력하려면 주소 값이 필요하기 때문이다.

 

 

포인터 대상의 const 선언

const 선언은 변수를 상수화 하는 목적으로 사용 했으나 포인터 변수에도 적용이 가능하다.

 

포인터 변수에선 const의 선언 위치에 따라 의미가 달라진다.

- const 가 앞에 붙은경우: const int* ptr = #            

     이 경우에는 ptr을 통한 num의 변경이 불가능하다. 즉, ptr 입장에선 num이 상수가 되어 있는 것 이다.

- const가 뒤에 붙은 경우: int* const ptr = #           

     이 경우에는 ptr이 상수가되어 ptr에 저장된 주소 값을 변경할 수 없는 것이다. 즉, 한번 가리키기 시작한 변수

     를 끝까지 가리켜야 한다.

- 두 가지 형태의 const를 선언한 경우: const int* const ptr = &num

     이 경우는 ptr을 통한 num의 값의 변경과 ptr의 저장된 주소 값의 변경 둘 다 불가능하게 되어서 ptr은 접근만 가능

     해진다.

 

const 선언은 특별한 기능을 제공하는 것이 아니나 코드의 안정성을 높이기 위해 사용하는 선언이다.