본문 바로가기

Miscellaneous

C언어 간단 정리...!!


포인터와 배열

"배열의 이름도 포인터다. 단 그 값을 바꿀 수 없는 상수라는 점이 일반적인 포인터와의 유사한 차이점이다."

-배열의 이름은 첫 번째 요소의 주소값을 나타낸다.

-포인터와 배열
둘 다 이름이 존재한다.
둘 다 메모리의 주소 값을 나타낸다.
포인터는 변수이다. 하지만 배열의 이름은 상수이다.

#배열의 이름을 가리켜 "상수 포인터"라 한다.
-포인터를 배열의 이름 처럼 사용할 수 있다.
또한, 포인터를 배열 이름 처럼 사용할 수 있다.

int main(void)
{
 int arr[3] = {0, 1, 2,}; // 배열 선언, arr은 배열의 첫 번째 요소를 가리키므로 포인터
 int *ptr;                    // arr이라는 배열 이름과 타입이 같다.
 ptr = arr;                  // arr이 지니는 주소값을 변수 ptr에 대입하고 있다. 배열이 상수 이므로 ptr변수에 저장.
printf("%d %d %d", ptr[0], ptr[1], ptr[2]);  //ptr이라는 포인터를 마치 배열 이름 처럼 사용.
 return 0;
}

실행결과
0, 1, 2

-포인터 연산

포인터는 제한된 형태의 연산이 가능하다.
포인터 연산이란 포인터 값을 증가 혹은 감소 시키는 연산을 말하는 것이다.
포인터를 가지고 나누거나 곱하는 연산은 수행되지 않는다.

int *ptr=0; // ptr1= NULL 과 같은 문장
char *ptr2 = 0 // 값이 0이라는 것이 아니라 아무것도 가리키지 않음
double *ptr3 = 0;

---------------다른 예제----------------

#include<stdio.h>
int main(void)
{
 int i;
 char ch;
 char str[6] = "Hello"; //문자열 변수 뒤에 null문자가 들어가므로, 길이는 6
 printf("변경 전 문자열\n");
 printf('%s \n", str);
 for(i=0; i < 6; i++)
  printf("%c | ", str[i]);
for(i = 0; i<3; i++)
{
 ch=str[4-i];
 str[4-i] = str[i];
 str[i] = ch;
}
printf("\n변경 후 문자열\n");
printf("%s\n", str);
return 0;
}

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

int main(void)
{
 int arr[2] = {1, 2};
 int *pArr = arr;
 printf("%d %d", arr[0], *(arr+1)); // 배열 이름을 통한 출력(배열이름을 포인터 처럼 사용)
 printf("%d %d", pArr[0], *(pArr+1)); // 포인터 변수를 통한 출력(포인터를 배열 처럼 사용)
 return 0;
}

실행결과
1, 2
1, 2

-문자열 표현방법
#변수로 표현하는 방법
#상수로 표현하는 방법

char str1[5] = "abcd"; // char형인 str1이라는 이름의 배열 을 선언하여 저장
char *str2 = "ABCD"; // 포인터를 이용하여 문자열 상수 ABCD를 가리키겠다는 의미
                             // str2는 문자열의 첫 문자 A를 가르키게 된다.

-문자열 상수에 대한 조금 더 깊은 이해

#문자열 상수는 메모리 공간에 저장이 되면, 그 순간에 문자열 상수의 주소 값이 반환된다.
#똑같은 문자열을 선언하면 한번만 메모리 공간에 할당된다.

char *arr[3] = {
"I",
"love",
"you"
};

문자열 배열이라는 것을 선언한 것이다. charr형 포인터 배열인데, 이를 가리켜 문자열 배열이라고 표현 하는 것이다.
여러 개의 문자열을 저장할 수 있는 특징!!


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


포인터와 함수에 대한 이해

함수에서 인자를 전달하는 것은 복사이다.
함수 호출 시 배열을 통재로 넘겨주는 방법은 존재하지 않는다.
그러므로
배열의 주소값을 인자로 전달해서 이를 통해서 접근하도록 유도하는 방법을 생각해 볼 수 있다.

포인터 이용!!


#include<stdio.h>
void fct(int *arr2);

int main(void)
{
 int arr1[2] = {1, 2};
 fct(arr1); // 배열의 이름을 인자로 전달. 배열을 전달한 것이 아니라 주소를 전달한것
              // 배열 이름은 첫번째 요소의 주소 값을 의미하는 상수 포인터
printf("%d", arr1[0]);
return 0;
}
void fct(int *arr2)
{ // arr1이 지니고 있는 주소 값을 포인터 변수 arr2가 받아 주고 있으므로 서로 같은 값
  // 배열은 하나인데 가리키는 포인터가 두개 이므로 두개가 배열 하나를 가리킴
 printf("%d", arr2[0]);
 arr2[0]=3 // arr2를 통해서 첫번째 요소의 값을 3으로 변경
}

fct함수 내에서는 배열의 복사본을 가지고 연산을 하는 것이 아니라, 배열을 가리키는 포인터를 이용해서 8번째 줄에서 선언한 배열 arr1에 직접 접근하고 있기 때문에 변경이 가능하다.

sizeof(arr)/sizeof(int)

sizeof 연산자를 배열의 이름에 사용하게 되면, 배열의 크기가 반환된다. 따라서 여기서 얻어진 결과를 배열 요소의 자료형 크기 sizeof(int)로 나누게 되면 배열의 전체 길이를 얻게 되는 것이다.

int main(void){
 int arr[5];
 int *parr=arr;

 printf("%d", sizeof(arr)); // 20출력
 printf("%d", sizeof(parr)); // 4출력
}

배열의 이름을 sizeof의 피연산자로 놓으면 배열의 전체 크기가 바이트 단위로 반환된다.
그러나 포인터 변수를 sizeof 의 피연산자로 놓으면 포인터 변수의 크기, 4가 반환된다.

따라서 함수에 배열의 주소만 전달할 경우, 함수 내에서는 배열의 길이를 알 방법이 없다.
그래서 반드시 배열의 길이를 두번째 인자로 전달해야 한다. 
이렇듯 일반적으로 배열을 인자로 전달받는 함수의 경우, 대부분 배열의 길오 함께 전달받도록 구현해야 한다. 


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


포인터의 포인터

더블 포인터

int **ptr;

-더블 포인터가 가리키는 것은 싱글 포인터
더블 포인터건 싱글 포인터건 간에 포인터는 무조건 메모리 공간의 주소 값을 저장하는 변수이다.
따라서 모든 변수는 4바이트 메모리 공간을 요구한다. 다만 차이가 나는 것은 포인터가 가리키는 대상이다.

double vla = 3.14;
double *ptr = &val; // 싱글 포인터
double **ptr2 =  &ptrf; //더블 포인터 , 싱글 포인터의 주소 값을 저장하는 용도로 사용함.
싱글 포인터는 기본 자료형 변수의 주소 값을 저장하기 위한 것이다.

반면 더블 포인터는 싱글 포인터의 주소값을 저장하기 위한 용도로 사용되는 포인터이다.

-더블 포인터에 의한 call-by-reference

#include <stdio.h>

void swap(int *p1, int *p2);

int main(void){
 int a=10, b=20;
 int *pa, *pb;

pa=&a, pb=&b;

printf("pa가 가리키는 변수  : %d", *pa);
printf("pb가 가리키는 변수  : %d", *pb);

swap(pa,pb);

//변수 a의 입장에서는 pa에 의해 값이 호출되므로 참조호출이 가능하다.
   그러나, pa의 입장에서는 예를 들어, 주소값 0110의 값이 호출되므로, 주소가 단순이 복사된다.

printf("pa가 가리키는 변수  : %d", *pa);
printf("pb가 가리키는 변수  : %d", *pb);

}

void swap(int **p1, **p2){
 int *temp;
 temp = *p1;
 *p1 = *p2;
 *p2 = temp;
}

단순히 주소값만을 복사해서 인자를 받으므로 변수 값이 변경되지 않고, 그대로 남는다.
따라서 인자가 포인터의 값을 넘겨주게 만들지 말고, 포인터의 주소 값을 넘겨주게 해주면
변수를 변경할 수 있다.

pa와 pb를 더블포인터인 p1과 p2를 통해서 주소값을 넘겨준다.

주소값을 알고 있다 == 해당 주소의 변수에 접근이 가능하다.
반응형

'Miscellaneous' 카테고리의 다른 글

JSON을 이용해 보자!  (0) 2012.01.12
FlatForm 三 國 時 代.....  (0) 2012.01.10
ARM 아키텍처와 RISC  (0) 2012.01.03
KGC2010에서 앵그리버드 개발자의 강연 내용  (0) 2012.01.03
Basic Computer Information  (0) 2011.12.23