본문 바로가기
IT & AI/AI 지식

C 언어 배열, 포인터, 문자열 활용 심화

by 빛나는해커 2024. 11. 19.

1. 배열과 포인터

 

배열과 포인터의 관계

  • 배열명은 배열의 첫 번째 요소의 주소를 의미한다.
  • 배열명을 사용해 배열 요소에 접근할 수 있으며, 배열명은 포인터와 유사하게 동작하지만 변경이 불가능하다.
int numbers[5] = {1, 2, 3, 4, 5};
int *p = numbers;  // numbers는 배열의 첫 번째 요소의 주소
printf("첫 번째 요소: %d\n", *p);  // 출력: 1
  • 배열명은 배열의 첫 번째 요소의 주소로 취급되며, 포인터로 동작할 수 있다.
  • 따라서 포인터 연산을 통해 배열의 각 요소에 접근할 수 있다.
for (int i = 0; i < 5; i++) {
    printf("numbers[%d] = %d\n", i, *(numbers + i));  // 배열 요소 출력
}
  • 배열명은 배열의 시작 주소를 나타내며, 포인터처럼 사용될 수 있지만 변경할 수 없는 상수이다.
  • 반면에 포인터 변수는 다른 주소를 저장할 수 있는 변수이다.
int numbers[5] = {1, 2, 3, 4, 5};
int *p = numbers;
p = &numbers[2];  // 포인터는 다른 요소를 가리킬 수 있음
// numbers = &numbers[2];  // 오류: 배열명은 상수이므로 변경할 수 없음
  • 포인터 사이의 뺄셈은 두 주소 간의 거리를 반환하며, 관계 연산을 통해 두 포인터가 가리키는 주소를 비교할 수 있다.
int numbers[5] = {1, 2, 3, 4, 5};
int *p1 = &numbers[1];
int *p2 = &numbers[4];
int distance = p2 - p1;  // 두 포인터 간의 거리 (배열 요소 간의 차이)
printf("거리: %d\n", distance);  // 출력: 3

 

배열을 처리하는 함수

  • 배열을 함수로 전달하여 값을 출력할 수 있다.
  • 함수의 매개변수로 배열을 전달할 때는 배열명이 사용된다.
void print_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int numbers[5] = {1, 2, 3, 4, 5};
print_array(numbers, 5);  // 출력: 1 2 3 4 5
  • 배열 크기를 매개변수로 전달하여 크기가 다른 배열도 출력할 수 있도록 한다.
int numbers2[3] = {10, 20, 30};
print_array(numbers2, 3);  // 출력: 10 20 30
  • 배열에 값을 입력받아 저장하는 함수도 작성할 수 있다.
void input_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("값을 입력하세요: ");
        scanf("%d", &arr[i]);
    }
}

int numbers[5];
input_array(numbers, 5);
  • 함수의 매개변수 자리에 배열을 선언하면 실제로는 배열의 주소가 전달된다.
  • 이는 배열의 첫 번째 요소의 주소를 받는 포인터와 동일한 방식으로 동작한다.
void modify_array(int arr[], int size) {
    arr[0] = 100;  // 첫 번째 요소를 100으로 변경
}

int numbers[5] = {1, 2, 3, 4, 5};
modify_array(numbers, 5);
printf("첫 번째 요소: %d\n", numbers[0]);  // 출력: 100

2. 문자

 

아스키코드 값과 문자 입출력 함수

  • 아스키코드는 문자와 숫자 간의 매핑 규칙을 정의한 것으로, 컴퓨터에서 문자를 숫자로 표현할 때 사용된다.
  • 예를 들어, 'A'의 아스키 값은 65이다.
char c = 'A';
printf("%c의 아스키 값: %d\n", c, c);  // 출력: A의 아스키 값: 65
  • scanf 함수를 사용하여 문자를 입력받을 수 있다.
  • %c 형식 지정자를 사용한다.
char c;
printf("문자를 입력하세요: ");
scanf(" %c", &c);  // 공백을 넣어야 이전 입력의 줄바꿈을 무시함
printf("입력한 문자: %c\n", c);
  • getchar 함수는 한 문자를 입력받고, putchar 함수는 한 문자를 출력한다.
char c;
c = getchar();
putchar(c);  // 입력한 문자 출력

 

버퍼를 사용하는 입력 함수

  • scanf 함수는 입력 버퍼를 사용하여 데이터를 처리한다.
  • 문자 입력 시 이전의 줄 바꿈이 버퍼에 남아 있다면 다음 입력에 영향을 줄 수 있다.
  • scanf 함수는 입력받은 항목의 개수를 반환한다.
  • 이를 활용하여 입력이 제대로 이루어졌는지 확인할 수 있다.
int result = scanf("%d", &num);
if (result == 1) {
    printf("입력이 정상적으로 이루어졌습니다.\n");
}
  • getchar 함수를 반복 사용하여 문자열을 입력받을 수 있다.
char str[100];
int i = 0;
char c;
while ((c = getchar()) != '\n') {
    str[i++] = c;
}
str[i] = '\0';
printf("입력한 문자열: %s\n", str);
  • 입력 버퍼에 남아 있는 불필요한 데이터를 제거하기 위해 fflush(stdin)이나 반복적으로 getchar()를 호출할 수 있다.
while (getchar() != '\n');  // 입력 버퍼 지우기

3. 문자열

 

문자열과 포인터

  • 문자열 상수는 큰따옴표(")로 묶어서 선언하며, 문자열은 자동으로 널 문자(\0)로 끝난다.
char *str = "Hello, World!";
  • char 포인터를 사용하여 문자열을 가리킬 수 있다.
  • 이는 문자열 리터럴의 주소를 가리키는 포인터로 동작한다.
char *str = "Hello";
printf("%s\n", str);  // 출력: Hello
  • scanf 함수는 문자열을 입력받을 때 %s 형식 지정자를 사용하며, 공백이 포함되면 그 이전까지만 입력받는다.
char name[20];
scanf("%s", name);
printf("이름: %s\n", name);
  • gets 함수는 한 줄 전체를 입력받으며, 공백도 포함한다.
  • 하지만 안전하지 않기 때문에 권장되지 않는다.
char str[50];
gets(str);
printf("입력한 문자열: %s\n", str);
  • fgets 함수는 입력의 길이를 제한할 수 있어 더 안전한 방법으로 문자열을 입력받는다.
fgets(str, sizeof(str), stdin);
printf("입력한 문자열: %s\n", str);
  • scanf, gets, fgets 등은 표준 입력 버퍼를 공유하므로, 입력 순서에 따라 버퍼에 남은 줄 바꿈이 다음 입력에 영향을 줄 수 있다.

 

문자열 연산 함수

  • strcpy 함수는 문자열을 다른 문자열에 복사한다.
char dest[20];
strcpy(dest, "Hello");
printf("복사된 문자열: %s\n", dest);
  • strncpy 함수는 지정된 개수만큼 문자를 복사하며, 복사되는 문자의 길이를 제한함으로써 보다 안전하게 문자열을 처리할 수 있다.
char dest[20];
strncpy(dest, "Hello, World!", 5);
dest[5] = '\0';  // 널 문자 추가
printf("복사된 문자열: %s\n", dest);  // 출력: Hello
  • strcat 함수는 두 개의 문자열을 이어 붙이고, strncat 함수는 지정된 개수만큼만 문자열을 이어 붙인다.
char str1[20] = "Hello";
char str2[] = " World";
strcat(str1, str2);
printf("붙인 문자열: %s\n", str1);  // 출력: Hello World

strncat(str1, "!!!", 2);
printf("부분적으로 붙인 문자열: %s\n", str1);  // 출력: Hello World!!
  • strlen 함수는 문자열의 길이를 반환하며, 널 문자는 포함하지 않는다.
char str[] = "Hello";
int length = strlen(str);
printf("문자열의 길이: %d\n", length);  // 출력: 5
  • strcmp 함수는 두 문자열을 비교하여 같으면 0을 반환하고, 다르면 양수 또는 음수를 반환한다.
  • strncmp 함수는 지정된 개수만큼만 비교한다.
char str1[] = "Hello";
char str2[] = "Hello, World!";
int result = strcmp(str1, str2);
printf("비교 결과: %d\n", result);  // 출력: 음수 (str1 < str2)

result = strncmp(str1, str2, 5);
printf("부분 비교 결과: %d\n", result);  // 출력: 0 (처음 5문자는 동일)
  • 기본적인 문자열 함수들을 직접 구현해 보며 문자열의 구조와 연산 원리를 이해할 수 있다.
// 문자열 복사 함수 구현
void my_strcpy(char *dest, const char *src) {
    while (*src) {
        *dest++ = *src++;
    }
    *dest = '\0';
}

char dest[20];
my_strcpy(dest, "Hello");
printf("복사된 문자열: %s\n", dest);  // 출력: Hello

C 언어 기본 배열, 포인터, 문자열 활용 소개 이미지