[TIL/크래프톤 정글] DAY 33

배재준·2025년 4월 11일

크래프톤 정글 - TIL

목록 보기
26/93
post-thumbnail

2025.04.11

TIL(TODAY I LEARN)


  • WEEK05: C Pointer(&, * 연산자), 동적 메모리 할당, Linked List, Stack, Queue, Binary Tree, Binary Search Tree, 동적 프로그래밍, 그리디 알고리즘
  • 오랜만의 C언어를 공부해보자
  • 위 개념들을 공부했어야 했는데 좀 다른거도 했다.

입력 함수들의 입력 과정

[ 키보드 입력 ][ 입력 버퍼 (stdin) ][ scanf / fgets 등 ][ 변수에 저장 ]

1. 입력 함수 정리 (Input)

함수명용도특징공백 포함줄바꿈 처리보안
scanf()형식 기반 입력타입 명시 (%d, %s 등)❌ (공백 전까지만 %s)줄바꿈 안먹음 (남음)중간
fgets()한 줄 입력공백 포함 가능, 버퍼 사이즈 지정줄바꿈 \n 포함됨
gets()한 줄 입력과거에 쓰이던 함수, 위험함❌ (버퍼 오버플로우 위험)
getchar()한 문자 입력문자 1개 읽음-엔터 입력도 문자로 처리
getch() / getche()콘솔에서 입력 (키 눌림)즉시 입력 받음 (에코 차이 있음)--플랫폼 종속 (Windows)

문자열 입력 함수: fgets()scanf()의 차이점

  • fgets()

    #include <stdio.h>
    char *fgets(char *s, int size, FILE *stream);
    
    > char *s : 문자열을 저장할 버퍼(저장할 곳)
    > int size : 입력 받을 최대크기(size -1+\0)
    > FILE *stream 
    				: stdin 사용가능
    				:	입출력 대상과 연결된 추상화된 "스트림 객체"
    
    EX) 
    char str[100];
    fgets(str, sizeof(str), stdin);// 공백 포함, 개행 포함
    • 공백 입력을 허용
      • ‘Hello World’ 입력시 → ‘Hello World\n\0’ 저장
      • 입력 버퍼에서 다 가져옴!
    • 마지막 Enter 입력
      • 줄바꿈 문자(’\n’) + NULL(’\0’)를 문자열에 추가함
  • scanf()

    #includ <stdin.h>
    int scanf(const char *format, ...);
    
    EX)
    char str[100];
    scanf("%s", str);  // 공백 전까지만 입력됨
    • 공백을 기준으로 입력이 분리됨
      • ‘Hello World’ 입력시 → ‘Hello\0’ 만 저장
      • 입력 버퍼에 ‘\n’ 이 존재함
        • 정수형(%d, %f, %u, ...)은 입력 후 엔터를 쳐도 scanf()\n을 무시하고 처리
        • 문자형(%c)은 \n도 문자로 취급하기 때문에 문제가 생기는 것
        • 다음 입력에 영향이 갈 수 있음!
          • getchar() 이용해 버퍼에서 빼주거나
          • 야매로 fflush(stdin) 사용해 입력 버퍼 다 비워줌
    • 마지막 Enter 입력
      • 줄 바꿈 문자를 문자열에 포함시키지 않고 NULL문자(’\0’)만 문자열에 추가
  • strlen(”입력받은 문자열”) 하면 ‘\0’을 제외한 길이 리턴

    • scanf, fgets 는 ‘hello’ 를 입력받으면
    • strlen 5, 6을 리턴함

출력 함수들의 출력 과정

[ printf("Hello") ][ 출력 버퍼 (stdout) ](줄바꿈 or fflush or 버퍼 가득 참)
[ 실제 화면에 출력됨 ]

2. 출력 함수 정리 (Output)

함수명용도특징줄바꿈 자동
printf()형식 기반 출력%d, %s, %f 등 사용
puts()문자열 출력문자열 출력 + \n 자동
putchar()문자 1개 출력char 하나 출력
  • 입력 함수와 비슷하다!
    • printf() 출력버퍼 그대로 출력
    • puts() ‘\n’을 추가하여 출력

Call by Value vs Call by Reference

🔹 C는 "call by value" → 복사!


void func(int x) {
    x = x + 1;
}

int main() {
    int a = 10;
    func(a);
    printf("%d\n", a);  // 결과: 10
}
  • func(a)를 호출하면 a값이 복사돼서 x에 들어감
  • 즉, 함수 안에서 x를 바꿔도 원본 a는 변하지 않음

✔️ C는 항상 값을 복사해서 넘긴다 → call by value


🔹 "call by reference" → 원본 참조!

void func(int *x) {
    *x = *x + 1;
}

int main() {
    int a = 10;
    func(&a);
    printf("%d\n", a);  // 결과: 11
}
  • 포인터를 이용해서 주소를 넘김
  • 주소는 값이니까 여전히 call by value지만, 넘긴 주소를 통해 원본을 바꿀 수 있음
  • C에는 call by reference는 없지만, "포인터를 통한 call by reference처럼 흉내"낼 수 있음

그럼 왜 "call by reference"가 더 빠른가?

예를 들어 이런 함수:

void process(struct BigData data);
  • struct BigData가 크기가 수십~수백 바이트일 경우,
  • call by value면 모든 필드가 복사됨 → 느림 + 메모리 낭비

반면 이렇게 하면?

void process(struct BigData *data);
  • 포인터 하나만 넘김 → 복사 비용 거의 없음 (4~8바이트)
  • 원본도 직접 수정 가능
  • 성능상 더 효율적임

성능 차이 정리

방식설명복사량성능
call by value (값 복사)값 전체를 복사해서 전달많을 수 있음느릴 수 있음
call by reference (주소 복사)주소(포인터)만 복사4~8바이트보통 더 빠름

실제 사용 예

  • 큰 구조체 넘길 때 → 보통 포인터 사용
  • 정수나 문자처럼 작고 간단한 건 → 그냥 값으로 넘김

포인터

  • int a = 13; → 그냥 정수
  • int* p = &a; → 정수를 가리키는 포인터
  • int** pp = &p; → 포인터를 가리키는 포인터 (이중 포인터)
  • 아래 그림을 보고 이해를 해보자!


문제를 풀면서 궁금했던 점들

Linked List

(1) insertSortedLL() 만들기

typedef struct _listnode{
	int item;
	struct _listnode *next;
} ListNode;			// You should not change the definition of ListNode

typedef struct _linkedlist{
	int size;
	ListNode *head;
} LinkedList;			// You should not change the definition of LinkedList
  • 함수내에서 linked list node를 만들때는 동적할당을 해야함
  • 지역변수(스택에 저장)로 선언하게 되면 함수가 끝나게 되면 쓰레기 값이 될 수 있음.
  • 힙 메모리에 저장되면 함수가 끝나고도 사용이 된다.

연결 리스트는 왜 malloc 써야 할까?

연결 리스트는 노드를 동적으로 생성해서 언제든 붙이거나 빼는 구조.

ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));
newNode->item = 10;
newNode->next = NULL;
  • 이렇게 하면 힙 메모리에 저장되므로,
  • 프로그램이 원할 때까지 계속 유지되고 자유롭게 조작 가능

malloc 앞에 형변환은 왜 해주는가?

  • malloc 함수의 반환값은 void → 모든 자료형에 대응될 수 있게
  • C의 경우는 형변환 안해도 된다.
  • C++은 형변환 필수

free 잘 해주자

  • 안 쓰면 할당 해제 필수!
  • ex) 노드 중복 값이 존재해서 연결 리스트에 안 붙일 때
선언 방식메모리 위치free() 필요 여부
ListNode maxL;스택(stack)❌ 아니요 (자동 해제)
ListNode* maxL = malloc(...);힙(heap)✅ 꼭 필요함

(2) alternateMErgeLinkedList()

  • Segmentation Fault : 허용되지 않은 메모리(주소)를 접근하려고 할 때 발생하는 에러

오랜만에 C언어 공부를 하니 재밌었다.
예전 기억이 새록새록 나면서 새로운 사실들 배우니까 깨달음을 얻는 것 같다.
교수님이 분명히 알려줬더라. 내 뇌가 일을 잘 못하나 보다.

0개의 댓글