C 언어 프로그래밍 핵심 정리
1. 연산자
- 산술:
+,-,*,/,%(정수 나눗셈은 소수부 버림) - 대입:
=,+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|= - 증감:
++x,x++(전위/후위 평가 시점 차이) - 비교:
==,!=,<,<=,>,>=(결과는 정수 0/1) - 논리:
&&,||,!(단락 평가) - 비트:
&,|,^,~,<<,>> - 조건(삼항):
cond ? a : b - 주소/간접:
&(주소),*(역참조) - 크기:
sizeof(표현식|타입)(컴파일 타임) - 우선순위(높음→낮음) 개요:
- 단항(증감, 부호,
!,~, 캐스트,sizeof,&,*) */%→+-→ 시프트 → 비교 → 등가 → 비트 AND → 비트 XOR → 비트 OR → 논리 AND → 논리 OR → 삼항 → 대입 → 콤마
- 단항(증감, 부호,
2. 분기문
- if
- 형태:
if (조건) 문장;
- 형태:
- if–else
- 형태:
if (조건) 문장1; else 문장2;
- 형태:
- if–else if–else
- 위에서부터 첫 참인 분기만 실행
if (x > 0) {
puts("pos");
} else if (x == 0) {
puts("zero");
} else {
puts("neg");
}
3. 반복문
while
- 형태:
while (조건) { 본문 } - 조건이 처음부터 거짓이면 0회 실행
이중 while(중첩)
int i = 0;
while (i < 3) {
int j = 0;
while (j < 2) {
printf("%d,%d\n", i, j);
j++;
}
i++;
}
무한 루프
while (1) { ... }또는for (;;) { ... }- 종료 경로(조건,
break,return)를 반드시 설계
for (;;) {
int c = getchar();
if (c == EOF) break;
}
for문
- 형태:
for (초기식; 조건; 증감식) { 본문 } - 초기식/증감식 생략 가능. 조건 생략 시 참으로 간주.
for (int i = 0; i < n; i++) {
// ...
}
break & continue
break: 가장 안쪽 반복문 또는switch를 즉시 탈출continue: 현재 반복의 나머지를 건너뛰고 다음 반복으로- for: 증감식 실행 후 조건 검사
- while/do-while: 조건 검사로 이동
4. 함수
- 선언/정의/호출
int add(int a, int b); // 선언(프로토타입) int add(int a, int b) { // 정의 return a + b; }
int r = add(2, 3); // 호출
- 반환값이 없으면 `void`
- 인자 전달은 값에 의한 복사만 존재
- 지역 변수 수명: 블록 종료 시 소멸
- 필요 시 헤더로 프로토타입 분리
---
## 5. 변수의 범위와 static
- 범위(scope)
- 블록 범위: `{}` 내부에서만 유효
- 파일 범위: 함수 밖에서 선언 → 해당 번역 단위에서 유효
- 수명(storage duration)
- 자동(auto): 블록 진입 시 생성, 종료 시 소멸
- 정적(static): 프로그램 시작~종료까지 존속
- 링크(linkage)
- 외부 링크: 파일 간 참조 가능(전역 변수/함수 기본)
- 내부 링크: `static` 전역 → 해당 소스 파일 내에서만 참조
- static의 용도
- static 지역 변수: 호출 간 값 유지
- static 전역: 심볼 가시성을 파일로 제한
```c
void counter(void) {
static int c = 0; // 최초 1회 초기화
printf("%d\n", ++c);
}6. 배열
배열을 사용해야 하는 이유
- 동일 타입의 연속 메모리를 인덱스로 관리
- 캐시 지역성 확보로 효율적 접근
- 고정 크기 데이터 집합에 적합
선언, 초기화
int a[5]; // 자동 영역: 초기화 안 하면 indeterminate
static int b[5]; // 정적 영역: 0으로 초기화
int c[5] = {1, 2, 3}; // 나머지는 0
char s1[] = "abc"; // {'a','b','c','\0'}
char s2[5] = {'h','i','\0'}; // 문자열로 사용 가능
문자열과 null 문자('\0')의 필요성
- C의 문자열은 null-종단 방식
- 문자열 함수(
strlen,printf("%s"),strcpy등)는'\0'까지 처리 - 누락 시 버퍼 경계 초과 접근(UB) 발생
다차원 배열
int m[2][3] = { {1,2,3}, {4,5,6} }; // 행 우선(row-major)
제약
- 배열 간 대입 불가:
a = b;(불가) - 함수 인자로 전달 시 첫 원소 주소로 decay
7. 포인터
- 정의: 특정 타입 객체의 주소를 저장하는 변수
```c
int x = 10;
int *p = &x; // 주소 보관 - p = 20; // 역참조로 x 변경
``` - 포인터 산술:
p+1은 다음 요소 주소(요소 크기만큼 이동) void*: 임의 포인터. 역참조 전 적절한 타입으로 변환 필요NULL: 유효하지 않은 주소 표현- 주의: 경계 밖 접근, 해제 후 사용(dangling), 이중 해제, 잘못된 캐스팅 등은 정의되지 않은 동작
8. JavaScript에서의 “포인터”
- 포인터 언어 기능 없음
- 원시 타입(Number, String, Boolean 등): 값 복사
- 객체/배열/함수: 변수에는 “참조 값”이 저장되며, 대입 시 참조 값이 복사됨
- 함수 인자도 값 복사. 객체의 “참조 값”이 복사되므로, 매개변수를 통해 객체 내부를 바꾸면 원본이 변함. 단, 매개변수에 새 객체를 대입해도 바깥 변수는 변하지 않음
function f(o) { o.x = 1; o = { x: 2 }; }
const a = { x: 0 };
f(a);
// a.x === 1, a가 새 객체로 바뀌지는 않음
9. 배열과 포인터(C)
- 배열 이름의 decay: 대부분의 식에서 배열명 → 첫 요소에 대한 포인터
- 예외:
sizeof(배열),&배열, 문자열 리터럴 초기화 등
- 예외:
- 인덱싱:
a[i] == *(a + i) - 차이점
- 배열: 고정 크기, 메모리를 자체 소유,
sizeof(a)는 전체 바이트 - 포인터: 주소만 보유,
sizeof(p)는 포인터 크기
- 배열: 고정 크기, 메모리를 자체 소유,
int a[10];
int *p = a; // &a[0]와 동일
sizeof(a); // 예: 40 (int가 4바이트일 때)
sizeof(p); // 예: 8 (64비트 포인터)
10. 값에 의한 복사와 “참조 효과”
- C는 값에 의한 복사만 제공
- 원본 수정 필요 시 포인터 인자를 사용하여 간접 변경
void swap_by_value(int a, int b) { int t=a; a=b; b=t; } // 실패
void swap_by_ptr(int *a, int *b) { int t=*a; *a=*b; *b=t; } // 성공
int x=1, y=2;
swap_by_value(x, y); // x,y 변화 없음
swap_by_ptr(&x, &y); // x=2, y=1
함수 포인터(필요 시)
int add(int a, int b) { return a + b; }
int (*fp)(int, int) = add;
int r = fp(2, 3);
11. 실수 방지 요점
- 입력 처리 시 버퍼 크기 엄수(
fgets권장) - 동적 메모리
malloc/free쌍 관리, 소유권 명확화 - 논리 연산의 단락 평가 고려(부작용 함수 호출 배치 주의)
- 비교와 대입 혼동 금지(
==vs=)
중요포인트





'STUDY' 카테고리의 다른 글
| C 언어 핵심 개념 요약 + 예시 (0) | 2025.11.10 |
|---|---|
| 객체지향 언어의 특징 (0) | 2025.11.07 |
| 변수와 상수 (0) | 2025.11.05 |
| 블로그 포스팅하면서 (0) | 2025.10.15 |
| CRUD 알아두면 정말 조케따~ (0) | 2025.10.02 |