C언어_10
포인터
문자열 상수와 포인터
#include <stdio.h>
int main(void)
{
char str[] = "love";
const char *pStr = "you";
printf("str출력 : %s\n", str);
printf("pStr출력 : %s\n", pStr);
}
str출력 : love
pStr출력 : you
#include <stdio.h>
int main(void)
{
char str[] = "love";
const char *pStr = "you";
printf("str출력 : %s\n", str);
printf("pStr출력 : %s\n", pStr);
}
str출력 : love
pStr출력 : you
포인터 변수 pStr
에는 실제 문자열 상수인 "you"가 저장되는 것이 아니다. 문자열 상수는 문자열을 메모리 공간에 저장하고, 메모리 주소값을 리턴한다. 변수 pStr
은 실질적으로 문자열 상수의 주소값을 가지고 있는 것이다.
포인터 배열
포인터 배열은 포인터 변수를 여러개 사용하기 위해 사용한다.
#include <stdio.h>
int main(void)
{
char *pArr[] = {"C언어", "자바", "베이직"};
int i;
for(i = 0; i < 3; i++)
{
printf("%s\n", pArr[i]);
}
return 0;
}
C언어
자바
베이직
2차원 배열
int arr[i][j];
i
행과 j
열로 이루어진 행렬로 메모리 구조를 생각하자.
#include <stdio.h>
int main(void)
{
int i, j;
int arr[2][3];
arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;
printf("2차원 배열 값의 출력 결과 \n");
printf("=======================\n");
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++ )
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("=======================");
return 0;
}
2차원 배열 값의 출력 결과
=======================
1 2 3
4 5 6
=======================
함수와 포인터
기본적인 함수의 인자 전달 형태는 복사형태이다. A에서 B로 복사 시 A, B 모두 값이 존재한다.
int main(void)
{
int a = 10;
temp(a);
}
void temp(b)
{
{
a
: 실인수
b
: 형식인수, 매개변수, 인자, 인수
배열형
배열형의 인자는 포인터형으로 받는다.
#include <stdio.h>
void func(int *pArr);
int main(void)
{
int arr[] = {1, 2, 3, 4, 5};
int i;
func(arr);
for(i = 0; i < 5; i++)
{
printf("배열의 요소 출력 : %d\n",arr[i]);
}
return 0;
}
void func(int *pArr)
{
int i;
for(i = 0; i < 5; i++)
{
printf("배열의 요소 출력 : %d\n",*(pArr + i));
}
printf("\n");
}
배열의 요소 출력 : 1
배열의 요소 출력 : 2
배열의 요소 출력 : 3
배열의 요소 출력 : 4
배열의 요소 출력 : 5
배열의 요소 출력 : 1
배열의 요소 출력 : 2
배열의 요소 출력 : 3
배열의 요소 출력 : 4
배열의 요소 출력 : 5
배열을 포인터로 받아와 사용할 경우, 배열의 크기를 알 수 없기 때문에 사이즈를 인자로 전달해주어야 한다.
#include <stdio.h>
int func(int *pArr, int size);
int main(void)
{
int arr[] = {1, 2, 3, 4, 5};
int sumArr, sizeArr;
sizeArr = sizeof(arr) / sizeof(int);
sumArr = func(arr, sizeArr);
printf("배열의 총 합 : %d\n", sumArr);
return 0;
}
int func(int *pArr, int size)
{
int i, sum = 0;
for(i = 0; i < size; i++)
{
sum += *(pArr + i);
}
return sum;
}
배열의 총 합은 : 15
값 호출 방식과 참조호출 방식
값 호출 방식(call by value)
실인수의 값이 형식 인수로 전달되는 방식으로, 실인수의 메모리가 형식 인수로 복사되어 메모리가 별도로 관리된다.
#include <stdio.h>
void callValue(int b);
int main(void)
{
int a = 1;
int *pa = &a;
callValue(a);
printf("실인수 a의 출력 : %d\n", a);
return 0;
}
void callValue(int b)
{
int *pb = &b;
b = b + 3;
printf("형식인수 b의 출력 : %d\n", b);
}
형식인수 b의 출력 : 4
실인수 a의 출력 : 1
#include <stdio.h>
void Swap(int a, int b);
int main(void)
{
int x = 10, y = 20;
printf("초기값 x = %d, y = %d\n", x, y);
Swap(x, y);
printf("함수 밖에서 변경 후 x = %d, y = %d\n", x, y);
return 0;
}
void Swap(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
printf("함수 안에서 변경 후 a = %d, b = %d\n", a, b);
}
초기값 x = 10, y = 20
함수 안에서 변경 후 a = 20, b = 10
함수 밖에서 변경 후 x = 10, y = 20
참조 호출 방식(call by reference)
함수 호출 시 전달인자로 메모리 접근에 사용되는 주소값을 전달한다. 원본 메모리의 주소값을 통해 사용하므로, 다른 함수 안에서 값을 변경 했을 때 실인수의 값도 변경된다.
#include <stdio.h>
void callReference(int *b);
int main(void)
{
int a = 1;
printf("a 초기값 : %d\n", a);
callReference(&a);
printf("실인수 a 출력 : %d\n", a);
return 0;
}
void callReference(int *b)
{
*b = *b + 3;
printf("실인수 b 출력 : %d\n", *b);
}
a 초기값 : 1
실인수 b 출력 : 4
실인수 a 출력 : 4
#include <stdio.h>
void Swap(int *a, int *b);
int main(void)
{
int x = 10, y = 20;
printf("초기값 x = %d, y = %d\n", x, y);
Swap(&x, &y);
printf("함수 밖에서 변경 후 x = %d, y = %d\n", x, y);
return 0;
}
void Swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
printf("함수 안에서 변경 후 a = %d, b = %d\n", *a, *b);
}
기값 x = 10, y = 20
함수 안에서 변경 후 a = 20, b = 10
함수 밖에서 변경 후 x = 20, y = 10
사용자로부터 두 수를 입력받아 합과 곱을 출력하는 예제(참조호출 활용)
#include <stdio.h>
void sum_mul(int i, int j, int *hap, int *mul);
int main(void)
{
int a,b;
int x, y;
printf("두개의 정수 입력 : ");
scanf("%d%d", &a, &b);
sum_mul(a, b, &x, &y);
printf("두 수의 합 : %d\n", x);
printf("두 수의 곱 : %d\n", y);
}
void sum_mul(int i, int j, int *hap, int *mul)
{
*hap = i + j;
*mul = i * j;
}
개의 정수 입력 : 10 20
두 수의 합 : 30
두 수의 곱 : 200
함수 포인터
함수도 메모리 어딘가에 정의되어 있고, 필요할 때 그 위치를 참조(호출)하여 사용한다. 함수도 엄밀히 포인터임을 알 수 있다.
선언 방법
int (*func)(int a);
자료형(*함수 포인터 이름)(인자 목록);
#include <stdio.h>
int Add(int a, int b);
int Min(int a, int b);
int main(void)
{
int a, b, sel, result;
int (*fPtr)(int a, int b);
while(1)
{
printf("다음 중 선택하시오 (1. 덧셈 2. 뺄셈. 3. 종료) : ");
scanf("%d", &sel);
switch (sel)
{
case 1:
fPtr = Add;
break;
case 2:
fPtr = Min;
break;
case 3:
return 0;
default:
break;
}
printf("두 정수를 입력하시오 : ");
scanf("%d %d", &a, &b);
result = fPtr(a, b);
printf("결과 : %d\n", result);
}
return 0;
}
int Add(int a, int b)
{
return a + b;
}
int Min(int a, int b)
{
return a - b;
}
다음 중 선택하시오 (1. 덧셈 2. 뺄셈. 3. 종료) : 1
두 정수를 입력하시오 : 3 5
결과 : 8
다음 중 선택하시오 (1. 덧셈 2. 뺄셈. 3. 종료) : 2
두 정수를 입력하시오 : 1 5
결과 : -4
다음 중 선택하시오 (1. 덧셈 2. 뺄셈. 3. 종료) : 3
정적 바인딩
변수와 함수들이 컴파일 타임에 메모리의 크기와 위치가 결정되는 경우
동적 바인딩
변수와 함수들이 런타임(프로그램이 실행되는 시간) 에 메모리의 크기와 위치가 결정되는 경우
함수 포인터를 사용하는 이유
예를 들어 vscode
나 이클립스
에서 플러그인에 새로운 함수가 추가될 때마다 매번 다시 컴파일해야하는 비효율적인 상황이 생기는데, 호출하는 함수를 함수 포인터를 이용하여 동적 바인딩을 하면 매번 컴파일 할 필요가 없게 된다.
이런 예시처럼 함수포인터는 프로그램의 확장성과 유용함을 위해 사용한다.
NULL 포인터
null
포인터란 아무것도 가르키지 않는 포인터이다. 국룰
주로 함수의 동작 에러 체크 용도로 자주 사용된다.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "Love";
char *p;
int a;
p = strchr(str, 'v');
if (p != NULL)
{
*p = 'b';
printf("변경 결과 : %s\n", str);
}
else
{
printf("NULL을 리턴하였습니다.\n");
}
return 0;
}
변경 결과 : Lobe
Author And Source
이 문제에 관하여(C언어_10), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gimmicks_/c10저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)