ex250602 공부노트 - Hwanghyewon06/c- GitHub Wiki
#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
- Visual Studio 컴파일러 전용 지시문.
-
gets()
,strcpy()
같은 보안 위험 함수 사용 시 발생하는 경고 C4996을 무시합니다. - 실제 프로덕션에서는 사용 권장 ❌ →
fgets()
,strncpy()
사용 권장.
- 표준 입출력 함수 (
printf()
,scanf()
등) 사용을 위한 헤더.
- 문자열 관련 함수 (
strcmp()
,strcpy()
,strlen()
등) 사용 가능.
- 메모리 동적 할당 함수 (
malloc()
,free()
등) 사용 가능.
모든 코드의 핵심은 다음 흐름을 따릅니다:
- 문자열 입력 받기 →
- 조건 검사 (종료 여부 등) →
- 메모리 복사 or 주소 저장 →
- 문자열 출력 →
- 동적 메모리 할당 해제 (해당하는 경우)
char* sarr[1000] = { 0 }; // 문자열 포인터 배열
-
sarr
는char*
타입을 1000개 저장하는 배열 → 문자열 1000개 저장 가능. - 각 요소는
char*
→ 문자열 시작 주소(포인터)를 저장하는 변수.
char buf[1000];
gets_s(buf, 1000);
-
buf
는 지역 배열: 문자열을 입력 받는 임시 저장소. -
gets_s()
는 입력을 받아buf
에 저장.
char* s = (char*)malloc(strlen(buf) + 1);
strcpy(s, buf);
sarr[count++] = s;
-
malloc(strlen(buf) + 1)
: 문자열 길이 + 널 문자 공간만큼 동적 메모리 할당. -
strcpy()
: 입력 받은 문자열을 새로 할당한 메모리에 복사. -
sarr[]
: 복사된 문자열의 주소를 저장함. - 따라서
buf
가 사라져도 문자열은 유지됨.
if (strcmp("exit", buf) == 0)
break; // 또는 run = 0;
- 문자열 비교 (
strcmp
): 리터럴"exit"
과 사용자가 입력한buf
내용이 동일하면 종료.
for (int i = 0; i < count; ++i)
free(sarr[0]); // ❌ 버그
- 항상
sarr[0]
만 해제 → 메모리 누수 발생 - 정답은:
for (int i = 0; i < count; ++i)
free(sarr[i]); // ✅ 각 문자열에 대해 메모리 해제
sarr[count++] = buf;
-
문제점:
buf
는 지역변수로 매번 새로 선언됨 → 반복 시 덮어씌워짐. - 따라서 모든
sarr[i]
가 마지막 입력 문자열만 가리킴. - 이건 포인터 주소를 공유하는 문제로, 문자열 복사를 생략했기 때문.
char buf[1000];
gets_s(buf, 1000);
printf("string : %s\n", buf);
- 단순한 입력-출력 구조.
- 포인터 없음, 메모리 할당 없음, 문자열 저장 없음.
- 반복 구조 속에서 매 입력마다 바로 출력 후 버림.
if (buf[0] == 'e' &&
buf[1] == 'x' &&
buf[2] == 'i' &&
buf[3] == 't' &&
buf[4] == '\0') // null 문자 포함 필수
break;
-
"exit"
을 문자열이 아닌 문자 배열 비교로 처리함. - 문자열 라이브러리 없이 직접 비교하는 방식.
-
'\0'
체크는 문자열 종료 확인의 핵심 (없으면"exit123"
도 통과함)
개념 | 설명 |
---|---|
char* sarr[1000] |
문자열 포인터 배열. 각 요소는 문자열의 시작 주소를 저장 |
buf[1000] |
입력을 임시 저장하는 지역 배열 |
malloc() |
문자열을 위한 동적 메모리 할당. +1 은 \0 포함 때문 |
strcpy() |
문자열 내용을 새로운 메모리로 복사 |
free() |
malloc() 으로 할당한 메모리를 해제. 반드시 반복문 사용 필요 |
gets_s() |
보안 강화된 문자열 입력 함수. 크기 제한 필수 |
strcmp() |
문자열 내용 비교. 동일하면 0 반환 |
포인터 주소 저장 문제 |
sarr[i] = buf; 는 같은 주소 복사 → 내용 덮어쓰기 발생 |
-
free(sarr[0])
만 호출 → 나머지 메모리 누수 -
sarr[i] = buf;
→ 모든 포인터가 같은 주소 가리킴 (복사 안됨) -
buf[4] == 't'
까지만 비교 → 문자열 종료 문자 체크 누락 시 오류
항목 | 필수 개념 |
---|---|
문자열은 배열 or 포인터로 처리된다 | 둘은 메모리 관리 방식이 다름 |
포인터 배열은 주소만 저장 | 내용을 복사하려면 malloc 과 strcpy 필요 |
동적 메모리는 해제 필수 | 반복문으로 free() 처리해야 메모리 누수 방지 |
지역 배열은 반복 시 덮어써짐 | 주소만 저장하면 마지막 내용만 남게 됨 |
문자열 비교는 strcmp() 또는 문자 직접 비교 가능 |
단, 정확한 길이와 \0 체크 필요 |
#include <stdio.h>
struct Person
{
char name[20]; // 포인터와 배열
int age;
};
void PrintPerson(Person* p)
{
printf("name: %s, age: %d\n", p ->name, p-> age);
}
int main()
{
Person p1 = { "홍길동", 30 };
Person p2 = { "Hong Gil- Dong", 30 };
PrintPerson(&p1);
PrintPerson(&p2);
}
#include <stdio.h>
//struct Person
//{
// char name[20]; // 포인터와 배열
// int age;
//
//};
//int main()
//{
// Person p1 = { "홍길동", 30 };
// Person p2 = { "Hong Gil- Dong", 30 };
//
// printf("name: %s, age: %d\n", p1.name, p1.age);
// printf("name: %s, age: %d\n", p2.name, p2.age);
// printf("%c\n", p2.name[3]);
//}
//#include <stdio.h>
//struct Person
//{
// char name[20]; // 포인터와 배열
// int age;
//
//};
//int main()
//{
// Person p1 = { "홍길동", 30 };
//
// printf("name: %s, age: %d\n", p1.name, p1.age);
//} 야 제대로 해 이 코드 설명을 작성하라는 거야
#include <stdio.h>
-
stdio.h
는 Standard Input Output Header입니다. - 이 파일을 포함시켜야
printf()
함수 같은 표준 입출력 함수들을 사용할 수 있습니다. - 만약 이 줄이 없으면
printf()
를 사용할 수 없고, 컴파일 에러가 발생합니다.
struct Person
{
char name[20]; // 포인터와 배열
int age;
};
-
struct
는 관련된 변수들을 하나의 사용자 정의 자료형으로 묶는 키워드입니다. - 여기서는 사람(
Person
)이라는 구조체를 정의하고 있음.
- 문자형 배열이며, 최대 19글자의 문자열을 저장할 수 있음 (
+1
은 문자열 끝에 붙는 널 문자'\0'
때문). - 즉,
"홍길동"
또는"Hong Gil- Dong"
같은 문자열을 저장하는 공간입니다. - 포인터가 아님: 이 배열은 실제 문자열 데이터를 구조체 내부에 저장함.
- 사람의 나이를 저장하는 정수형 변수입니다.
void PrintPerson(Person* p)
{
printf("name: %s, age: %d\n", p->name, p->age);
}
- 이 함수는 아무 값도 반환하지 않음을 의미합니다.
- 단지 구조체 정보를 출력만 하고 끝남.
-
PrintPerson
은 함수 이름. -
매개변수로
Person
구조체의 **포인터(주소)**를 받습니다.-
Person* p
는 구조체Person
의 포인터형. - 즉,
p
는 구조체 변수를 가리키는 주소를 저장함.
-
-
p->name
: 구조체 포인터p
가 가리키는 구조체의name
멤버를 의미. -
p->age
: 마찬가지로 구조체 포인터의age
멤버. -
->
연산자는 구조체 포인터에서 멤버에 접근할 때 사용합니다.
int main()
{
Person p1 = { "홍길동", 30 };
Person p2 = { "Hong Gil- Dong", 30 };
PrintPerson(&p1);
PrintPerson(&p2);
}
- 프로그램의 시작 지점.
- 운영체제가 처음으로 실행하는 함수이며, 반드시 있어야 합니다.
- 구조체
Person
의 변수p1
을 선언하고 초기화합니다. -
"홍길동"
은name
배열에 저장,30
은age
에 저장됩니다. - 문자 배열에 한글을 넣을 수 있지만, 인코딩(UTF-8, EUC-KR 등)에 따라 배열 크기 초과 가능성 있음.
- 두 번째 구조체 변수 선언.
-
name
에 영문 이름이 들어가고,age
는 30.
-
&p1
은 구조체 변수p1
의 주소를 함수에 전달함. - 함수는 포인터를 통해
p1
의 데이터를 참조하여 출력.
- 위와 동일하게
p2
의 주소를 전달하여 출력.
//Person p1 = { "홍길동", 30 };
//Person p2 = { "Hong Gil- Dong", 30 };
//
//printf("name: %s, age: %d\n", p1.name, p1.age);
//printf("name: %s, age: %d\n", p2.name, p2.age);
//printf("%c\n", p2.name[3]);
-
.
연산자는 일반 구조체 변수에서 멤버에 접근할 때 사용합니다. - 포인터가 아닐 때는
->
가 아닌.
사용.
-
p2
의 이름 문자열에서 4번째 문자를 출력. - 인덱스는 0부터 시작하기 때문에
"Hong Gil- Dong"
에서name[3]
는'g'
.
//Person p1 = { "홍길동", 30 };
//printf("name: %s, age: %d\n", p1.name, p1.age);
- 구조체 하나만 생성하고 출력하는 코드.
- 포인터, 함수 없이 구조체를 직접 다루는 가장 단순한 형태입니다.
문법 요소 | 역할 및 설명 |
---|---|
#include <stdio.h> |
표준 입출력 함수 사용 (printf 등) |
struct Person |
사용자 정의 자료형: 사람 정보 묶기 |
char name[20] |
이름 저장용 배열 (고정 크기 문자열 저장) |
int age |
나이 저장용 변수 |
void PrintPerson(Person* p) |
구조체 포인터로 받은 데이터를 출력하는 함수 |
-> |
구조체 포인터에서 멤버 접근할 때 사용 |
. |
일반 구조체 변수에서 멤버 접근 시 사용 |
&p1 , &p2
|
구조체의 주소를 전달 (포인터 매개변수 전달용) |
문자열 입력 함수 (Visual Studio 전용 안전 함수)
┌────────────┐
│ 사용자 입력 │
└─────┬──────┘
↓
┌──────────────┐
│ gets_s(buf, size) │
└─────┬────────────┘
↓
┌────────────────────────┐
│ buf 배열에 문자열 저장 │
└────────────────────────┘
-
기능: 사용자로부터 문자열을 한 줄 입력받아
buf
에 저장. -
보호 기능: 두 번째 인자
size
로 버퍼 오버플로우 방지. -
종료 조건: 사용자가
[Enter]
누르면 입력 종료됨.
문자열 비교 함수
┌────────────┐ ┌────────────┐
│ str1 ("abc")│ │ str2 ("abc")│
└────┬────────┘ └────┬────────┘
↓ ↓
비교 (문자열 내용 순서대로)
↓
┌────────────────────┐
│ return 0 → 같음 │
│ return <0 or >0 → 다름 │
└────────────────────┘
-
기능: 두 문자열을 내용 기준으로 비교.
-
리턴값:
-
0
→ 완전히 같음 -
<0
→ str1 < str2 -
>0
→ str1 > str2
-
-
종료 조건: 널 문자
'\0'
까지 비교함.
문자열 길이 계산 함수
┌───────────────┐
│ 문자열: "hello"│
└─────┬─────────┘
↓
계산: h-e-l-l-o (5글자)
↓
┌────────────────────┐
│ 리턴: 5 (널 문자는 제외) │
└────────────────────┘
-
기능: 문자열에서
'\0'
이전까지의 문자 개수 반환. - 주의: 배열 크기 아님, 문자열 실제 글자 수임.
문자열 복사 함수
┌────────────┐ ┌────────────┐
│ src: "dog" │ ──▶ │ dest │
└────────────┘ └────────────┘
↓
dest: "dog"
-
기능:
src
문자열을dest
에 복사 (\0
포함). -
조건:
dest
는src
보다 큰 공간이어야 함.
동적 메모리 할당 함수
┌─────────────┐
│ malloc(20) │
└────┬────────┘
↓
┌───────────────────┐
│ 힙 메모리에 20바이트 │
│ 공간을 할당 후 주소 반환 │
└───────────────────┘
- 기능: 요청한 크기만큼 힙 영역에 메모리 블록 할당.
-
리턴값: 메모리 시작 주소 (
void*
→ 타입 캐스팅 필요) -
주의:
NULL
체크 필수 (할당 실패 시)
동적 메모리 해제 함수
┌─────────────┐
│ free(ptr) │
└────┬────────┘
↓
┌────────────────────┐
│ ptr가 가리키는 메모리 해제 │
└────────────────────┘
-
기능:
malloc()
으로 할당한 메모리 반환. -
주의사항:
- 해제 후 포인터를 NULL로 초기화하는 것이 좋음.
- 같은 포인터를 두 번 해제하면 오류 발생.
출력 함수
┌──────────────┐
│ printf("%s", str) │
└───────┬──────────┘
↓
┌───────────────────┐
│ str의 문자열을 화면에 출력 │
└───────────────────┘
-
기능: 서식 지정자(
%d
,%s
,%c
,%f
)를 사용하여 다양한 데이터 형식 출력 가능. - 출력 장치: 콘솔(표준 출력)
[사용자 입력]
↓
gets_s(buf)
↓
strcmp(buf, "exit")로 종료 검사
↓
┌──────────────────────────────┐
│ 동적 메모리 할당 (malloc) │
│ 문자열 복사 (strcpy) │
│ 포인터 배열에 저장 (sarr[]) │
└──────────────────────────────┘
↓
[모든 문자열 출력 후]
↓
free(sarr[i])로 메모리 해제
함수 | 기능 | 반환값 / 특징 |
---|---|---|
gets_s() |
사용자 문자열 입력 (보안 강화 버전) | 입력된 문자열 (buf 에 저장) |
strcmp() |
문자열 비교 | 0: 같음, 양수/음수: 다름 |
strlen() |
문자열 길이 측정 |
\0 제외한 문자 수 |
strcpy() |
문자열 복사 |
dest 에 src 복사 |
malloc() |
동적 메모리 할당 | 메모리 주소 (void* ) |
free() |
동적 메모리 해제 | 없음 |
printf() |
출력 함수 | 화면에 출력. 반환값은 출력한 문자 수 |