포인터
int a = 10;
int* ptr_a;
ptr_a = &a;
*ptr_a = 20;
printf("a = %d\\\\n", a);
printf("*ptr_a = %d\\\\n", *ptr_a);
- 포인터 변수의 메모리는빌드하는 크기에 따라 고정된다.
- 32비트로 빌드하면 32비트, 64비트 빌드면 64비트(8바이트)로 고정이다.
- 포인터 변수 : 데이터가 저장되는 변수의 ‘메모리 주소’를 가리키는 변수다.
- 저장된 메모리의 주인이 사라져도 포인터 변수에 저장된 주소는 계속 남아있는다.
- 메모리 주소는 프로그래머가 지정할 수 없다.
- 주소 연산자 (&)
- 단항 연산자
- 피연산자의 물리적인 메모리 주소를 반환한다.
- %p로 출력한다.
- 포인터 연산자 (*)
- 단항 연산자
- 해석하는 법 : 선언한 변수에 붙은 *을 지운 데이터형을 확인한다.
- int* → *를 쓰면 int 값을 확인하는 것이다.
- int** → 를 쓰면 int* 값을 확인하는 것이다.
- 피 연산자는 ‘포인터 변수(주소값)’만 올 수 있다.
주소 연산
int a = 10;
int* ptr_a = &a;
printf("&a = %d\\\\n", &a);
printf("(&a) + 1 = %d\\\\n", (&a) + 1);
printf("(&a) + 2 = %d\\\\n", (&a) + 2);
printf("ptr_a = %d\\\\n", ptr_a);
printf("ptr_a + 1 = %d\\\\n", ptr_a + 1);
printf("ptr_a + 2 = %d\\\\n", ptr_a + 2);
- 주소에 1을 더하면 다음 변수 크기만큼 주소 증가
- 산술 연산(+, -)은 좌항의 데이터 형의 메모리 크기만큼 증감하는 것이다.
- int형의 경우 4바이트씩 증가
- 이것은 ‘배열’에서 사용한다.
배열과 포인터의 관계
- 같은 자료형의 메모리가 연속된 주소로 이어진 구조
- 장점
- 단점
- 찾는 값을 검사하려면 비교를 나올때까지 반복해야한다..
int arr[10];
printf("%d\\\\n", &arr);
printf("%d\\\\n", arr);
printf("%d\\\\n", &arr[0]);
- 세 값이 모두 동일한 주소로 출력된다.
- 배열명은 첫 번째 요소의 주소를 나타냄
- arr == &arr[0]
- 배열명은 포인터 상수로 동작
배열과 포인터 주소연산 - 코드 추가
- &arr[3], arr + 3, ptr + 3, &ptr[3] ⇒ 모두 값이 같다.
- arr[3], *(arr + 3), *(ptr + 3), ptr[3] ⇒ 모두 값이 같다.
- ptr[n] ⇒ *(ptr + n)
- *ptr = arr ⇒ ptr이 arr과 같은 주소를 가리키게 되어 ptr[i] == arr[i]가 같은 의미가 된다.
배열 포인터
int arr[3] = { 1, 2, 3 };
//&를 빼도 같은 결과가 나온다. / 같은 값이니까
//컴파일이 안되는 이유 : [3]으로 제약을 두었기 때문이다.
//int* ptr = arr; => 제약이 없어서 더 넓은 범위의 선언이다.
int(*p_arr)[3] = &arr;
for (int i = 0; i < 3; i++) {
printf("%d\\\\n", (*p_arr)[i]);
}
- int(*p_arr)[3]: 크기가 3인 정수 배열을 가리키는 포인터
- &arr: 배열 전체의 주소
- (*p_arr)[i]: 배열 포인터를 통한 요소 접근
- 필요한 이유 : int*로 전환해서 넘겨도 되지만 ‘이차원’배열같은 경우에 사용된다고 한다.
- 즉, 배열 특정 인덱스의 ‘주소’를 넘기는 것이다.
이차원 배열과 배열 포인터 - 코드 추가
- &arr[0] == arr / &arr[1] == arr + 1 == &arr[0] + 1
int arr[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
/*
//단순한 포인트 변수와 이차원 배열 이름만 사용할 경우
//일차원 배열 형식으로 작성이 가능하지만 [] 요소를 잘 확인해야한다.
int* ptr = (int*)arr;
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 4; ++j
{
printf("%4d", arr[i * 4 + j]);
}
}
*/
int(*p_row)[4] = &arr[1];
for (int i = 0; i < 4; i++) {
printf("%d ", (*p_row)[i]);
}
- int(*p_row)[4]: 크기가 4인 정수 배열을 가리키는 포인터
- &arr[1]: 두 번째 행의 주소
- &arr[i] + n ⇒ 다음 인덱스의 주소를 가리키게 된다.
- 특정 행을 가리키는 포인터로 활용
포인터 배열과 문자열
char str[4][10] = { "hello", "world", "doodle", "google" };
char* ptr[4];
for (int i = 0; i < 4; i++) {
ptr[i] = str[i];
}
for (int i = 0; i < 4; i++) {
printf("%s\\\\n", ptr[i]);
}
- char* ptr[4]: 문자열 포인터 4개로 구성된 배열
- 각 포인터는 문자열의 시작 주소를 저장
- 문자열 배열의 효율적인 관리 방법
함수
반환타입 함수이름(매개변수)
{
// 함수 본문
return 반환값; // 반환타입이 void가 아닌 경우
}
- 특정 작업을 수행하는 코드의 집합
- 반복되는 코드를 줄이고 프로그램을 모듈화
- 코드의 재사용성과 가독성 향상
- 프로그램의 구조화와 유지보수성 개선
- 반환타입 : 데이터 형
- 함수 이름 : 변수 이름 규칙과 동일하다
- 매개 변수 : 데이터형과 변수 이름으로 선언된다. , n개의 변수가 들어간다. , ‘,’콤마로 구분한다.
- return : 함수의 종료를 의미한다.
- 함수의 데이터형을 확인하여 함수의 결과를 반환한다.
함수화
void buyItem(int* itemCnt, int* money) {
(*itemCnt)++;
(*money) -= 10;
printf("아이템을 구매했습니다.\\\\n");
printf(" 아이템 개수: %d\\\\n", *itemCnt);
printf(" 잔액: %d\\\\n", *money);
}
int itemCnt = 0;
int money = 100;
buyItem(&itemCnt, &money);
스코프 (=영역, 범위)
- 변수가 유효한 범위
- 변수에 접근할 수 있는 코드 영역
- 프로그램의 메모리 관리와 직결
- 반복문, if문, switch문 등이 있다.
블록 스코프
int a = 10; // main 함수의 지역 변수
{
int b = 20; // 블록 내부의 지역 변수
printf("a = %d, b = %d\\\\n", a, b); // 둘 다 접근 가능
}
// printf("b = %d\\\\n", b); // 오류! b는 블록을 벗어나면 접근 불가
printf("a = %d\\\\n", a); // a는 여전히 접근 가능
- 블록 : 중괄호 {}로 구분되는 영역
- 블록 내부에서 선언된 변수는 블록 종료 시 소멸
- 내부 블록에서 외부 블록의 변수 접근 가능
- 외부 블록에서 내부 블록의 변수 접근 불가
- 같은 이름을 중첩해서 사용할 경우 가장 가깝게 선언한 변수를 확인한다.
함수 스코프
- 각 함수는 독립적인 스코프 영역
- 함수 간 지역 변수는 서로 영향 없음
- 전역 변수는 모든 함수에서 접근 가능
- 같은 이름의 변수라도 스코프가 다르면 다른 변수
변수의 종류
- 지역 변수(Local Variable)
- 함수나 블록 내부에서 선언
- 해당 영역에서만 접근 가능
- 포함되어있는 영역에서 만들어지고, 함수 종료 시 메모리에서 해제
- 전역 변수(Global Variable)
- 함수 외부에서 선언
- 프로그램 전체에서 접근 가능
- 프로그램 종료 시까지 메모리에 유지
함수의 반환
- 반환값
- 함수가 작업을 완료한 후 호출한 곳으로 돌려주는 값
- return 키워드를 사용하여 반환
- 함수의 반환 타입과 일치해야 함
- return 문 실행 시 함수 즉시 종료
- 하나의 함수에서 여러 개의 return 문 가능
- void 함수는 반환값 없음
- 반환 타입과 실제 반환값의 타입 일치 필요
문자열 매개변수
void welcomePlayer(char playerName[])
{
printf("환영합니다, %s님!", playerName);
}
int main()
{
//연습문제 3_2 - 매개변수가 있는 함수
char name[10];
printf("플레이어 이름을 입력하세요: ");
scanf("%s", name);
welcomePlayer(name);
return 0;
}
- 문자열의 매개변수는 char playerName[]으로 받는다.
- 매개변수에서만 쓸 수 있는 형식이다.
- char* playerName도 같은 결과가 나온다.