C Programming Study_3

김현우·2025년 4월 2일
0

멘토링

목록 보기
4/7

C Programming Study_3

배열 & 문자열

1. 1차원 배열

1.1 배열 선언

  • 배열은 같은 데이터 타입의 여러 값을 하나의 변수에 저장할 수 있는 자료형입니다.
  • 배열을 선언할 때, 배열의 크기는 고정되어야 하며, 선언된 크기만큼 메모리를 할당합니다.

예시코드:

int arr[5];  // 5개의 정수를 저장할 수 있는 배열

1.2 배열 초기화

  • 배열을 선언하면서 초기값을 지정할 수 있습니다. 초기값이 없으면 배열에는 쓰레기 값이 저장됩니다.

예시코드

int arr[5] = {1, 2, 3, 4, 5};  // 배열을 선언하고 초기화
  • 배열의 일부만 초기화하면, 나머지 요소는 0으로 초기화됩니다.

1.3 배열 순회

배열에 저장된 모든 값을 반복문을 사용하여 순차적으로 접근할 수 있습니다.

예시코드

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    // char str[6] = "Hello";
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);  // 배열의 값을 출력
    }

    return 0;
}

2. 다차원 배열

2.1 2차원 배열

2차원 배열은 행과 열을 가지며, 행렬처럼 데이터를 저장할 수 있습니다.

예시코드

#include <stdio.h>

int main() {
    int arr[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", arr[i][j]);  // 2차원 배열 순회
        }
        printf("\n");
    }

    return 0;
}

2.2 다차원 배열의 메모리

  • 다차원 배열은 연속적인 메모리 블록에 저장됩니다. 즉, 2D 배열의 요소들은 메모리 상에서 연속적으로 저장됩니다.

3. 배열과 포인터

  • 3.1 배열 이름과 포인터
    배열의 이름은 배열의 첫 번째 요소의 주소를 가리키는 포인터와 같습니다

예시코드

#include <stdio.h>

int main() {
    int arr[3] = {1, 2, 3};
    
    // 배열 이름은 첫 번째 요소의 주소를 가리킴
    printf("배열의 첫 번째 요소 주소: %p\n", arr);
    printf("배열의 첫 번째 요소: %d\n", *arr);  // 포인터를 사용한 접근

    return 0;
}

3.2 포인터로 배열 순회

포인터를 이용해 배열을 순회할 수도 있습니다.

예시코드

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int *ptr = arr;  // 배열의 첫 번째 요소를 가리키는 포인터

    for (int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));  // 포인터를 이용한 배열 접근
    }

    return 0;
}

4. 동적 배열

4.1 동적 메모리 할당

  • 동적 메모리 할당은 malloc() 또는 calloc() 함수를 사용하여 실행 시간에 배열의 크기를 동적으로 할당할 수 있습니다.
  • 동적 할당은 프로그램 실행 중에 메모리를 효율적으로 사용할 수 있도록 해줍니다.

예시코드(malloc)

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int n;

    printf("배열의 크기를 입력하세요: ");
    scanf("%d", &n);

    // 동적으로 메모리 할당
    arr = (int *)malloc(n * sizeof(int));

    if (arr == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }

    // 배열 값 입력받기
    for (int i = 0; i < n; i++) {
        printf("arr[%d] = ", i);
        scanf("%d", &arr[i]);
    }

    // 배열 출력
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }

    // 동적으로 할당된 메모리 해제
    free(arr);

    return 0;
}

4.2 동적 배열과 포인터

  • 동적 메모리 할당을 사용할 때, 메모리는 포인터 변수를 사용하여 관리합니다.
  • malloc() 함수는 지정된 크기만큼 메모리를 할당하고, 그 메모리의 첫 번째 주소를 반환합니다.
  • 메모리 할당이 성공하면 그 주소를 포인터에 저장하고, 작업이 끝나면 free() 함수를 사용해 할당된 메모리를 해제합니다.

4.3 calloc() 함수

  • malloc()과 비슷하지만, calloc()은 메모리를 초기화하며 할당합니다. 즉, 모든 값이 0으로 설정됩니다.

예시코드

arr = (int *)calloc(n, sizeof(int));  // 메모리 할당과 동시에 0으로 초기화

4.4 realloc() 함수

  • realloc() 함수는 동적으로 할당된 메모리 크기를 변경할 때 사용됩니다. malloc() 또는 calloc()으로 할당된 메모리 블록의 크기를 변경할 수 있습니다.
  • realloc()은 현재 할당된 메모리 크기를 변경하고, 그 결과로 새로 할당된 메모리 블록의 주소를 반환합니다.
  • 만약 메모리 크기를 줄이는 경우, 반환된 주소는 원래 주소와 동일할 수 있습니다.
  • realloc()은 메모리 재할당이 실패할 경우 NULL을 반환하므로, 반환값을 체크하는 것이 중요합니다.

예시코드(realloc)

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int n;

    printf("배열의 크기를 입력하세요: ");
    scanf("%d", &n);

    // 동적 메모리 할당
    arr = (int *)malloc(n * sizeof(int));

    if (arr == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }

    // 배열 값 입력 받기
    for (int i = 0; i < n; i++) {
        printf("arr[%d] = ", i);
        scanf("%d", &arr[i]);
    }

    // 배열 크기 확장 (크기를 2배로 증가)
    printf("배열 크기를 두 배로 확장합니다.\n");
    arr = (int *)realloc(arr, 2 * n * sizeof(int));  // 배열 크기 변경

    if (arr == NULL) {
        printf("메모리 재할당 실패\n");
        return 1;
    }

    // 새로운 배열의 값 입력 받기
    for (int i = n; i < 2 * n; i++) {
        printf("arr[%d] = ", i);
        scanf("%d", &arr[i]);
    }

    // 배열 값 출력
    for (int i = 0; i < 2 * n; i++) {
        printf("%d ", arr[i]);
    }

    // 동적 메모리 해제
    free(arr);

    return 0;
}

5. 추가내용

5.1 배열의 크기 계산 (sizeof)

  • 배열의 크기를 계산할 때는 sizeof 연산자를 사용하여 배열이 차지하는 메모리 크기를 구할 수 있습니다. 이를 통해 배열의 크기를 동적으로 처리할 수 있습니다.
int arr[5];
printf("배열의 크기: %zu\n", sizeof(arr));  // 배열의 전체 크기
printf("배열의 원소 개수: %zu\n", sizeof(arr) / sizeof(arr[0]));  // 배열 원소의 개수

5.2 배열을 함수로 전달하기

  • 배열을 함수에 전달할 때는 배열의 첫 번째 요소의 주소만 전달되므로, 배열의 크기를 함께 전달하거나 배열 크기 정보를 저장하는 방법을 사용해야 합니다.

예시코드

#include <stdio.h>

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    printArray(arr, 5);  // 배열과 크기를 함수로 전달
    return 0;
}

6.문자열

6. 문자열의 기본

6.1 문자열 선언

  • 문자열은 char 배열로 선언합니다.
  • 문자열은 마지막에 널 문자('\0')가 자동으로 추가되어 문자열의 끝을 나타냅니다.

예시코드

char str[6] = "Hello";  // 배열 크기 6, 마지막 '\0' 포함
  • 문자열의 크기는 널 문자 '\0'을 포함해야 합니다.

7. 문자열 함수

7.1 strlen() 함수

  • strlen() 함수는 문자열의 길이를 반환합니다.
  • 널 문자('\0')는 제외하고 길이를 계산합니다.

예시코드

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello";
    printf("문자열 길이: %zu\n", strlen(str));  // 5
    return 0;
}

7.2 strcmp() 함수

  • strcmp() 함수는 두 문자열을 비교하여 결과를 반환합니다.
    • 0: 두 문자열이 동일
    • 음수: 첫 번째 문자열이 작음
    • 양수: 첫 번째 문자열이 큼

예시코드

#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    
    int result = strcmp(str1, str2);
    if (result == 0) {
        printf("두 문자열은 같습니다.\n");
    } else if (result < 0) {
        printf("%s는 %s보다 작습니다.\n", str1, str2);
    } else {
        printf("%s는 %s보다 큽니다.\n", str1, str2);
    }

    return 0;
}

7.3 strcpy() 함수

  • strcpy() 함수는 하나의 문자열을 다른 문자열에 복사합니다.
  • 대상 문자열의 크기를 확인하고, 이를 초과하는 복사는 방지해야 합니다.
#include <stdio.h>
#include <string.h>

int main() {
    char str1[20], str2[] = "Hello, World!";
    
    strcpy(str1, str2);  // str2를 str1에 복사
    printf("str1: %s\n", str1);  // "Hello, World!"
    
    return 0;
}

7.4 strcat() 함수

  • strcat() 함수는 두 문자열을 이어붙이는 함수입니다.
  • 대상 문자열에 문자열을 추가합니다.
#include <stdio.h>
#include <string.h>

int main() {
    char str1[20] = "Hello, ";
    char str2[] = "World!";
    
    strcat(str1, str2);  // str2를 str1 뒤에 이어 붙임
    printf("str1: %s\n", str1);  // "Hello, World!"
    
    return 0;
}

8. 문자열 입력 및 출력

8.1 gets() vs fgets()

  • gets()는 버퍼 오버플로우 위험이 있어 사용하지 않도록 권장합니다.
  • 대신, fgets()를 사용하여 안전하게 문자열을 입력받습니다.

예시코드(fgets)

#include <stdio.h>

int main() {
    char str[100];
    
    printf("문자열을 입력하세요: ");
    fgets(str, sizeof(str), stdin);  // 안전하게 문자열 입력받기
    
    printf("입력한 문자열: %s\n", str);
    
    return 0;
}
  • fgets()는 버퍼 크기를 지정하여 입력을 제한하고, 입력의 끝에서 널 문자 \0을 자동으로 추가합니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char *str;
    int size = 50;

    str = (char *)malloc(size * sizeof(char));
    if (str == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }

    // 문자열 입력 받기
    printf("문자열을 입력하세요: ");
    fgets(str, size, stdin);

    // 문자열 크기 재할당
    size += 50;  // 새로운 크기
    str = (char *)realloc(str, size * sizeof(char));
    
    printf("입력한 문자열: %s\n", str);

    // 동적 메모리 해제
    free(str);
    
    return 0;
}

8.2 fgets()와 scanf()의 차이점

  • fgets() 함수
    • fgets()는 새로운 줄 문자(\n)도 포함하여 입력을 받습니다
    • 널 문자(\0)를 자동으로 추가하여, 문자열의 끝을 나타냅니다.
#include <stdio.h>

int main() {
    char str[100];
    
    // 사용자로부터 문자열을 입력받음
    printf("문자열을 입력하세요: ");
    fgets(str, sizeof(str), stdin);  // 문자열을 한 줄 입력받기

    printf("입력한 문자열: %s\n", str);
    
    return 0;
}
  • scanf() 함수
    • scanf()는 기본적으로 공백, 탭, 새 줄 문자를 구분자로 사용하여 입력을 받습니다.
    • 즉, scanf()는 공백 문자(' ', '\n', '\t')를 입력 구분자로 간주하기 때문에 공백이 포함된 문자열을 입력받을 수 없습니다.
    • 문자열을 입력받을 때 scanf()는 공백을 구분자로 처리하기 때문에, 공백이 포함된 문자열을 제대로 처리할 수 없습니다.
#include <stdio.h>

int main() {
    char str[100];
    
    // 사용자로부터 문자열을 입력받음
    printf("문자열을 입력하세요: ");
    scanf("%99[^\n]", str);  // 개행문자를 기준으로 입력받기

    printf("입력한 문자열: %s\n", str);
    
    return 0;
}

9. 과제

1. 배열과 문자열을 이용한 회문 판별

  • 문제 설명:
    • 사용자로부터 문자열을 입력받고, 해당 문자열이 회문(palindrome)인지 판별하는 프로그램을 작성하세요.
    • 회문이란, 앞에서 읽으나 뒤에서 읽으나 같은 문자열을 의미합니다.
    • 문자열은 공백을 제외하고 비교해야 하며, 대소문자는 구분하지 않습니다.
  • 예시 입력
 madam
  • 예시 출력
입력한 문자열은 회문입니다.

2. 문자열에서 중복 문자 제거

  • 문제 설명:
    • 사용자로부터 문자열을 입력받고, 해당 문자열에서 중복된 문자를 제거하는 프로그램을 작성하세요.
    • 중복 문자가 있을 경우 첫 번째로 나타나는 문자만 남기고 나머지는 제거합니다.
  • 예시 입력
 programming
  • 예시 출력
progamin

3. 두 문자열 합치기 (동적 메모리 사용)

  • 문제 설명:
    • 사용자로부터 두 문자열을 입력받고, 두 문자열을 합쳐서 새로운 문자열을 동적으로 할당한 메모리에 저장한 후 출력하는 프로그램을 작성하세요.
    • 동적 메모리 할당(malloc)을 사용하여 새로운 문자열을 저장하고, free()로 메모리를 해제합니다.
  • 예시 입력
Hello
World
  • 예시 출력
HelloWorld

4.

  • 문제 설명:
    • 사용자에게 두 개의 문자열을 입력받고, 두 문자열을 합친 후 알파벳 순서대로 정렬한 뒤, 중복된 문자를 제거하는 프로그램을 작성하세요. 이때, 동적 메모리 할당을 사용하여 입력받은 문자열을 처리합니다. 그리고 동적 메모리 할당을 해제해야 합니다.
  • 제약 조건:
    • 문자열의 길이는 최대 1000자입니다.
    • 입력 받은 두 문자열의 길이가 각각 1000자 이하입니다.
    • 입력 받은 문자열은 공백을 포함할 수 있으며, 공백도 문자로 취급합니다
  • 예시 입력
apple
banana
  • 예시 출력
알파벳 순서대로 정렬된 문자열: abelnop
profile
학생

0개의 댓글