본문 바로가기
학점은행제

[C언어 I] 학습복습 - 포인터, 포인터 연산 및 배열, 다중 포인터, 배열 포인터, 함수 포인터, 스트림, EOF, 문자열 입출력 함수 및 버퍼

by 코곰 2021. 5. 22.

학습 복습 내용은 아이티뱅크 C언어 I 강의와 교안을 바탕으로 합니다.

 

 

1. 포인터

* 정수 형태 메모리 주소 값을 저장하는 변수

int num = 7;
int *pnum; //포인터 변수 pnum의 선언
pnum = # //num의 주소값을 pnum에 저장
//num의 주소값은 0x12ff76등의 정수값으로 표현된다!

* 포인터 변수의 크기는 시스템의 주소 값 크기에 따라 다르다.

* 포인터 변수에 저장되는 값은 형태는 모두 동일하지만, 선언하는 방법엔 차이가 있다.

* int형 포인터 변수에는 int형 변수의 주소값만 저장이 된다.

 

* 포인터 연산을 통해 메모리 접근 기준을 세움

* 예제 - int형포인터 변수 통해 메모리(변수) 접근 시, 4바이트 메모리 공간에 부호 있는 정수 형태로 데이터를 읽고 쓴다.

int * pnum1;//int형 변수를 가리키는 포인터 변수 선언
int* pnum1;
int *pnum1; //이 세 가지는 모두 같은 표현

double *pnum2; //double형 변수를 가리키는 포인터 변수 선언
type *ptr; //type형 변수를 가리키는  포인터 변수 선언

(출처- https://www.geeksforgeeks.org/pointers-in-c-and-c-set-1-introduction-arithmetic-and-array/)

* null값으로 포인터 변수 값을 초기화하는 것은 괜찮다.

 

* 포인터의 필요성!!

(1) 함수 내에서 함수 외부에 선언된 변수의 접근을 위해

(2) 메모리 동적 할당 등을 위해

(3) 자료구조에 유용하게 쓰임

 

2. 포인터 연산

* 배열, 혹은 문자열의 이름은 이들의  시작 주소값을 가리키는 포인터이다.

# 배열의 이름은 배열 시작 주소값을 의미한다
int arr[3] = {1, 2, 3};

# 포인터 변수 선언
int *ptr = &arr[0];
int *ptr2 = arr; // ptr과 ptr2는 같은 주소를 가리킴

# 배열 이름과 포인터 관계
arr[0] += 5; //6
ptr[0] += 2 //8

printf("%d %d %d \n", *ptr, *(ptr+1), *(ptr+2)); //8 2 3

# 포인터 type 따라 포인터 연산 결과 다름
double ptr3 = 0x0010;
printf("%p %p\n", ptr2, ptr3); // 00000020, 00000010
printf("%p %p\n", ptr2+1, ptr3+1); // 00000024, 00000018

 

 

> arr[i] == *(arr+i) 의 의미.

 

char str1[] = 'Hello';
char *str2 = 'Hello';

 

3. 포인터 배열

int *arr1[20];//길이가 20인 int형 포인터 배열 arr1

int num1 = 1, num2 = 2, num3 = 3;
int *arr[3] = {&num1, &num2, &num3};

char *strArr[3] = {'Simple', 'String', 'Array'};

 

* 활용 - 배열을 함수의 매개변수로 전달해줄 때는, 값만 복사해준다. 따라서 원본 배열을 다루려면 배열의 포인터를 매개변수로 전달해야 한다!

 

void ParamPtr(int *param)
//void ParamPtr(int param[]) 으로도 가능
{
    printf("%d", param[0]);
}
int main(void)
{
    int arr[3] = {1};
    ParamPtr(arr);
    
    return 0;
} 

 

* 함수 호출 시,

(1) Call-by-value: 단순히 값을 전달

(2) Call-by-reference: 메모리에 접근할 수 있는 주소 값을 전달

 

4. 다차원 배열

* TYPE arr[세로길이][가로길이] 로 2차원 배열 선언

* 실제 메모리는 다차원 배열도 1차원 배열의 형태로 저장

 

* 2차원 배열 초기화 예제..

int arr[3][3] = {
	{1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

int arr[3][3] = {
	{1},
   	{4, 5},
    {7, 8, 9}
};

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

int arr[][4] = {1, 2, 3, 4, 5, 6, 7, 8};
int arr[][2] = {1, 2, 3, 4, 5, 6};
int arr[][] = {1, 2, 3, 4, 5, 6, 7, 8};//에러!!

 

 

5. 다중 포인터

int num = 5;
int *ptr = #
int **dptr = &ptr; //*(*dptr) = *(ptr) = &num!!

* 포인터 변수의 swap은 이중포인터를 이용해서 해야 한다.

void Swap(int **dp1,int **dp2)
{
    int *temporary = *dp1;
    *dp1 = *dp2;
    *dp2 = *temporary;
}
int main(void)
{
    int n1 = 1, n2 = 2;
    int *ptr1 = &n1;
    int *ptr2 = &n2;
    Swap(&ptr1, &ptr2); //주소값 전달
    printf("%d %d\n", *ptr1, *ptr2);//2   1
    
    return 0;
    
}

 

 

6. 배열 포인터 변수

int arr[3][4]; //int형 변수고, sizeof(int)x4만큼 증가 혹은 감소하는 포인터형이 필요함!

int (*ptr)[4];

* 2차원 배열에서도

arr[i] == *(arr+i)는 적용됨

int arr[2][2] = {{1, 0}, {3, 2}};

arr[1][0]; //2
(*(arr+1))[0]; //2
*(arr[1]+0); //2
*(*(arr+1)+0);//2

 

 

7. 함수 포인터

int (*fptr) (int); //int를 받아 int를 반환하는 함수에 대한 포인터 변수
int SampleFunc(int num) { ... }
fptr = SampleFunc;
fptr(10);

 

 

8. 스트림

* 데이터가 한 방향으로 흐르는 경로를 스트림이라 함

* stdin - 표준 입력 스트림

* stdout - 표준 출력 스트림

* stderr - 표준 에러 스트림

 

 

 

9. EOF, 문자열 출력, 문자열 입력!

* EOF (End Of File) - 파일의 끝을 표현하기 위해 정의된 상수

* fgetc 혹은 getchar 함수 호출이 EOF 반환할 때 - 파일의 끝에 도달함

 

* 문자열 출력 함수 - puts, fputs 

puts("hello");

fputs("hello",  stdout); //모니터

 

* 문자열 입력 함수 - gets, fgets 

fgets("hello!!", sizeof("hello!!"),  stdin);

 

10. 입출력 버퍼

* 버퍼: 특정 크기의 메모리 공간

* 호출된 출력 함수가 반환될 때는 출력 버퍼로 데이터가 완전히 전송된 상태

* 엔터를 입력할 때가 키보드로 입력된 데이터가 입력버퍼로 전달되는 상태

 

* 출력버퍼를 '비운다' - 출력버퍼에 저장된 데이터를 목적지로 다 전송

fflush(stdout);

* 입력버퍼를 '비운다' - 입력버퍼에 저장된 데이터를 없앤다!

void ClearReadBuffer(void) {
	while(getchar() !=  "\n");
}

댓글