Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 스프링 db1 - 스프링과 문제 해결
- @Aspect
- 자바의 정석 기초편 ch9
- 코드로 시작하는 자바 첫걸음
- 타임리프 - 기본기능
- 자바의 정석 기초편 ch6
- 자바의 정석 기초편 ch2
- 2024 정보처리기사 시나공 필기
- 자바의 정석 기초편 ch12
- 자바의 정석 기초편 ch14
- 자바의 정석 기초편 ch4
- 스프링 mvc2 - 로그인 처리
- 스프링 mvc2 - 타임리프
- 스프링 mvc2 - 검증
- 스프링 db2 - 데이터 접근 기술
- 자바의 정석 기초편 ch7
- 스프링 mvc1 - 서블릿
- 게시글 목록 api
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch5
- 스프링 mvc1 - 스프링 mvc
- 자바의 정석 기초편 ch3
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch1
- 스프링 입문(무료)
- 자바의 정석 기초편 ch8
- jpa 활용2 - api 개발 고급
- 2024 정보처리기사 수제비 실기
- jpa - 객체지향 쿼리 언어
- 자바의 정석 기초편 ch13
Archives
- Today
- Total
나구리의 개발공부기록
Chapter 02 - C언어(포인터) 본문
2024정보처리기사 준비 정리(필기 - 시나공, 실기 - 수제비)/실기 6강 - 프로그래밍 언어 활용
Chapter 02 - C언어(포인터)
소소한나구리 2024. 5. 27. 12:562024년도 수제비 실기책(6판) 내용 정리
13. 포인터
1) 포인터(pointer)개념
- 변수의 주소값을 저장하는 공간
2) 포인터 선언
자료형* 포인터_변수명 = &변수명;
// 주소에 해당하는 값을 가리키는 * 연산과,
// 주솟값을 나타내는 & 연산은 반대 기능
//*(&)처럼 두 연산을 같이쓰면 서로 상쇄됨
- 자료형 뒤에 *를 붙이면 주소를 저장하는 포인터 변수라는 의미이고, 일반 변수명에 &를 붙이면 해당 변수명의 주솟값임
- 각 타입의 변수를 가리키는 포인터 변수 선언시 int*, char*, float* 처럼선언해서 사용
- 주소에 해당하는 값을 가리킬때는 *를 사용
#include <stdio.h>
int main() {
int a = 10; // int 타입 변수 a에 10을 저장
int* b = &a; // 변수 a의 주소를 포인터 변수 b에 저장
// a의 값 10 출력
// 포인터 변수 b가 가르키는 주소값에 저장된 값(a의 주소값) 10 출력
// a의 주소값이 가르키는 값 == a의 값 이므로 10 출력
printf("%d %d %d", a, *b, *(&a));
return 0;
}
3) 배열과 포인터
- 배열이 '자료형 배열명[요소];'의 형태일 때
구분 | 코드 |
배열의 i번지 주소 | 배열+i == &배열[i]; |
배열의 i번지의 값 | *(배열+i) == 배열[i]; |
(1) 1차원 배열과 1차원 포인터
- 1차원 배열에서 배열명만 단독으로 사용할 경우 1차원 포인터와 동일함
- 1차원 배열일 때는 배열명[요소] 형태, *(배열명+요소)일 경우 값을 가르킴
- 1차원 포인터일 때는 포인터[요소] 형태, *(포인터+요소)일 경우 값을 가르킴
#include <stdio.h>
int main() {
// 길이가 3인 int타입 배열 변수a에 1, 2를 저장, 남은 자리는 0이 저장됨
// a의 0번째에는 1, 1번째에는 2, 2번째에는 0이 저장됨
// &a[0] == a(a의 주소값), &a[1] == (a+1)(a+1의 주소값)
// a[0] == *a(a의 값), a[1] == *(a+1)(a+1의 값)
// *a가 a[0]을 가르키게 되는 이유는 *a는 *(&a[0])가 되어서 서로가 상쇄됨
int a[3] = {1, 2};
int *p = a; // 포인터 변수 p에 a의 주소값을 저장
// 각 배열a의 0,1,2번째 위치의 값을 출력 -> 1, 2, 0
printf("%d %d %d\n", a[0], a[1], a[2]);
// *은 값을 뜻하므로 a의 주소가 가르키는 값, a+1의 주소가 가르키는값, a+2의 주소가 가르키는 값을 출력
printf("%d %d %d\n", *a, *(a+1), *(a+2)); // 1, 2, 0
// 포인터 변수p의 값은 a의 주소이므로, 위와 동일한 값이 꺼내짐
printf("%d %d %d\n", *p, *(p+1), *(p+2)); // 1, 2, 0
// 위와 동일한 값을 뜻함
printf("%d %d %d\n", p[0], p[1], p[2]); // 1, 2, 0
return 0;
}
(2) 2차원 배열과 1차원 포인터
- 2차원 배열에서 배열명만 단독으로 사용할 경우 2차원 포인터와 동일함
- 배열명[요소]형태, *(배열명+요소)는 1차원 포인터와 동일하고, 1차원 포인터에 대해 *과 [ ]을 이용해야 값을 가르킬 수 있음
#include <stdio.h>
int main() {
// int타입 배열 변수 a에 행길이가 3, 열길이가 2인 2차원 배열을 아래 처럼 값을 넣고 초기화
// a[0][0] == 1, a[0][1] == 2,
// a[1][0] == 3, a[1][1] == 4,
// a[2][0] == 5, a[2][1] == 6,
// a[0] == &a[0][0], a[0][1] == &a[0][1]
// a[1] == &a[1][0], a[1][1] == *a[1][1]
// a[2] == &a[2][0], a[2][1] == *a[2][1]
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
// 포인터 변수 p에 a[1](&[1][0])의 주소값을 저장
// p = a[1]이므로 p대신에 a[1]을 넣어도 결과가 같음
int *p = a[1];
// a[0] == &a[0][0], *a[0] == *(&a[0][0]) 이지만 &과 *가 상쇄되어 a[0][0]값을 출력
// 결과적으로 *a[0][0] == a[0], *a[1] == a[1][0], *a[2] == a[2][0]의 값을 출력
printf("%d %d %d\n", *a[0], *a[1], *a[2]); // 1, 3, 5
// **a == *(&a[0][0]) 이므로 서로 상돼되어 a[0][0]값이 출력됨
// **(a+1) == *(&a[1][0]) a[1][0]값이 출력
// **(a+2) == *(&a[2][0]) a[2][0]값이 출력
printf("%d %d %d\n", **a, **(a+1), **(a+2)); // 1, 3, 5
// 포인터 변수 p의값은 a[1]의 주소값을 가지고 있으므로 a[1][0]의 값을 출력
// *(p+1) == *(a[1]+1)이 되므로 a[1][1]의 값을 출력
printf("%d %d\n", *p, *(p+1)); //3, 4
// p == p[0] == a[1]이므로 a[1][0]의 값을 출력
// p[1] == a[1][1], 해당 값을 출력
printf("%d %d\n", p[0], p[1]); //3, 4
return 0;
}
(3) 2차원 배열과 포인터 배열
#include <stdio.h>
int main() {
// 2차원 배열 선언
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
// 길이가 3인 int타입 포인터배열 p에 각각 a[2], a[0], a[1]의 주소값을 저장함
int *p[3] = {a[2], a[0], a[1]};
printf("%d %d %d\n", a[0][0], a[1][0], a[2][0]); // 1, 3, 5
// *(&a[0][0]) == a[0][0]의 값을 출력, 이하 동일
printf("%d %d %d\n", *a[0], *a[1], *a[2]); // 1, 3, 5
// p[1][0] == (a[0])[0] == a[0][0]의 값을 출력
// p[2][0] == (a[1])[0] == a[1][0]의 값을 출력
// p[0][0] == (a[2])[0] == a[2][0]의 값을 출력
printf("%d %d %d\n", p[1][0], p[2][0], ;p[0][0]); // 1, 3, 5
// *p[1] == *(&p[1][0]) == p[1][0] == a[0][0]의 값을 출력, 이하 동일
// *과&이 상쇄되는 것에 주의
printf("%d %d %d\n", *p[1], *p[2], *p[0]); // 1, 3, 5
return 0;
}
(4) 2차원 배열과 2차원 포인터
- 배열명[요소][요소], *배열명[요소], **(배열명+요소)일 경우 값을 가르킴
- 2차원 포인터는 int **p, **q; 형태로 선언할 수 있으나 2차원 배열에서 한덩어리의 크기를 알 수 없기 때문에 열의 개수를 명시하는 형태로 포인터 변수를 선언함
- 포인터 변수 선언 시 괄호가 없으면 2차원 배열에 대한 포인터가 아닌 포인터 배열이 됨 ex) 자료형 (*변수명)[크기];
#include <stdio.h>
int main() {
int a[3][2] = {{1, 2}, {3, 4}, {5, 6}}; // 2차원 배열 선언
int (*p)[2] = a; // 2차원 포인터 배열 변수 p에 a의 주소값을 저장, (a[0][0]의 값을 가르킴)
int (*q)[2] = a+1; // 2차원 포인터 배열 변수 q에 a+1의 주소값을 저장 (a[1][0]의 값을 가르킴)
printf("%d %d %d\n, a[0][0], a[0][1], a[1][0]"); // 1, 2, 3
// p[0][0] == a[0][0]의 값을 출력, 이하 동일함
printf("%d %d %d\n, p[0][0], p[0][1], p[1][0]"); // 1, 2, 3
// q[0][0] == (a+1)[0] == a[1][0]의 값을 출력
// q[0][1] == (a+1)[1] == a[1][1]의 값을 출력
// q[1][0] == (a+2)[0] == a[2][0]의 값을 출력
printf("%d %d %d\n, q[0][0], q[0][1], q[1][0]"); // 3, 4, 5
return 0;
}
4) 구조체와 포인터
(1) 구조체 변수와 구조체 포인터
- 일반 구조체 변수로 접근할 때는 .으로 접근하고, 구조체 포인터로 접근할 때는 ->로 접근
#include <stdio.h>
struct Student { // 구조체 틀 생성
char gender; // Student 구조체에 char 타입 변수 gender 생성
int age; // int 타입 변수 age 생성
};
int main() {
struct Student s = {'F', 21}; // 구조체타입 변수 s에 구조체의 순서에맞게 'F'와 21을 저장
// gender에 'F'가 age에 21이 저장됨
struct Student *p = &s; // 포인터 변수 p에 변수s의 주소가 저장됨
// 변수 s에 포함된 gender, age의 값을 출력
printf("%c %d\n", s.gender, s.age); // F 21
// s의 주소값에 저장된 gender, age의 값을 출력
printf("%c %d\n", (&s)->gender, (&s)->age); // F 21
// 포인터 변수 p가 가르키는 주소의 gender, age의 값을 출력
printf("%c %d\n", p->gender, p->age); // F 21
// p의값(s의 주소값)에 포함된 gender, age의 값을 출력
printf("%c %d\n", (*p).gender, (*p).age); // F 21
// 1차원 포인터이므로 p[0]으로도 접근이가능
printf("%c %d\n", p[0].gender, p[0].age); // F 21
return 0;
}
(2) 1차원 구조체 배열과 1차원 구조체 포인터
- 1차원 구조체 배열에서 배열명만 단독으로 사용할 경우 1차원 구조체 포인터와 동일함
- 1차원 구조체 배열일 때 배열명[요소].변수명 형태, (*(배열명+요소)).변수명, 배열명 -> 변수명 형태, (배열명+요소) -> 변수형 형태로 값을 가르킴
- 1차원 포인터일 때 포인터[요소].변수형 형태, (*(포인터+요소)).변수명, 포인터->변수명 형태, (포인터+요소)->변수명 형태로 값을 가르킴
#include <stdio.h>
struct Student {
char gender;
int age;
};
int main() {
// 길이가 3인 구조체 배열변수 s에 값들을 저장
struct Student s[3] = {'F', 21, 'M', 20, 'M', 24};
struct Student *p = s; // 포인터 변수 p에 변수s의 주소를 저장
// 구조체 변수s의 [0]에 저장된 gender, age의 값을 출력
printf("%c %d\n", s[0].gender, s[0].age); // F 21
// *s(*s의 값은 배열s가 가르키는 첫번째의 값) == s[0]이므로 위와 같음
printf("%c %d\n", (*s).gender, (*s).age); // F 21
// 구조체 배열 변수명을 단독으로 사용하면 1차원 구조체 포인터와 동일
// s -> == p ->, p는 s[0]의 값들을 가르키므로 위와 동일한 값이 출력됨
printf("%c %d\n", s->gender, s->age); // F 21
// (s+1) == s[1], s[1]이 가르키는 변수의 값을 출력
printf("%c %d\n", (s+1).gender, (s+1).age); // M 20
// 1차원 포인터 p에 첫번째에 저장된 값(s의 주소값)의 값들을 출력
printf("%c %d\n", p[0].gender, p[0].age); // F 21
// 포인터 변수 p에 포함된 값(s의 주소값)의 값들을 출력
printf("%c %d\n", (*p).gender, (*p).age); // F 21
// 포인터 변수 p가 가르키는 값(s의 주소값)의 값들을 출력
printf("%c %d\n", p->gender, p->age); // F 21
// (p+1) == p[1], 포인터 변수 p의 두번째 값이 가르키는 값(s+1 == s[1])의 값들을 출력
printf("%c %d\n", (p+1).gender, (p+1).age); // M 20
return 0;
}
5) 함수 포인터
- 함수의 주소를 저장하고 해당 주소의 함수를 호출하는데 사용하는 포인터
- 리턴타입 (*함수_포인터)(함수 파라미터);
#include <stdio.h>
void fn1() { // 반환 타입이 없는 fn1함수 정의
printf("fn1 함수\n"); // fn1함수 호출시 출력
}
int fn2(int a) { // 반환타입이 int이고 파라미터 타입이 int인 fn2 함수 정의
printf("fn2 함수: %d\n", a); // fn2함수 호출시 파라미터의 값 a의 값을 출력
return 0;
}
int main() {
void (*pf1)(); // 리턴 타입이 없는 함수형 포인터 *pf1() 선언
int (*pf2)(int); // 리탄 타입이 int인 함수형 포인터 *pf2에 파라미터 타입을 int로 선언
fn1(); // fn1 함수 호출
// fn1 함수라는 문구 출력
fn2(5); // fn2 함수에 아규먼트 값으로 5를 지정하여 호출
// fn2 함수: 5 문구 출력
pf1 = fn1; // 함수 fn1의 주소를 포인터 변수 pf1에 저장
pf2 = fn2; // 함수 fn2의 주소를 포인터 변수 pf2에 저장
pf1(); // 포인터 변수 pf1(); 호출
// pf1의 값은 함수 fn1의 주소이므로 fn1함수가 호출되어 실행됨
// fn1 함수라는 문구 출력
pf2(2); // 포인터 변수 pf2에 아규먼트 값을 2를 넣어서 호출
// pf2의 값을 함수 fn2의 주소이므로 fn2함수가 호출됨
// 아규먼트의 값을 2가 되었으므로 fn2함수 호출시 전달인자는 2가 되어 연산이 됨
// fn2 함수: 2 문구 출력
return 0;
}
6) 사용자 정의 함수 포인터 반환
- 사용자 정의 함수의 반환 값으로 포인터를 전달 받을 수 있음
#include <stdio.h>
#include <string.h>
char n[6]; // 길이가 6인 문자타입 변수 n선언
char *soojebi() { // soojebi 함수가 char타입 포인터를 반환, n의 주소를 반환
strcpy(n, "Hello"); // Hello의 문자열을 문자 배열n에 복사 후 n을 반환
return n;
}
int main() {
char *p = soojebi(); // soojebi 함수의 연산결과를 포인터 변수 p에 저장
// 반환 결과가 n의 주소 == &n[0] 이므로 해당 주소를 포인터 변수에 저장
printf("%s\n", p); // 포인터 변수 p의값 == n의 주소 == &n[0] 의값을 문자열로 출력, Hello
return 0;
}
'2024정보처리기사 준비 정리(필기 - 시나공, 실기 - 수제비) > 실기 6강 - 프로그래밍 언어 활용' 카테고리의 다른 글
Chapter 02 - C언어(기출 문제_2) (1) | 2024.06.13 |
---|---|
Chapter 02 - C언어(기출 문제_1) (1) | 2024.06.03 |
Chapter 02 - C언어(함수) (0) | 2024.05.24 |
Chapter 02 - C언어(배열, 문자열, 구조체) (0) | 2024.05.21 |
Chapter 02 - C언어(조건문, 반복문) (0) | 2024.05.21 |