[★C] 배열

방법이있지·2025년 6월 7일
post-thumbnail

배열을 사용하면 동일한 자료형의 값을 여러 개 저장할 수 있습니다. 문자열을 저장할 때는 보통 각 문자를 char형 배열에 저장합니다.

배열

배열의 선언 및 사용

  • 배열은 자료형 배열명[요소 개수] 형태로 선언한다.
    • e.g., int arr[5], char arr[10]
    • 초기화 후 값을 대입하기 전엔 쓰레기 값 (메모리 공간이 초기화되지 않았을 때 자동으로 들어있는 값)이 존재한다.
  • 배열명[인덱스]를 통해 배열 요소에 접근한다.
    • e.g., printf("%d\n", arr[1]);
int arr[3];     // int형 요소 5개의 배열 선언
arr[0] = 41;    // 각 배열 요소에 값 대입
arr[1] = 9;
arr[2] = 33;

for (int i = 0; i < 3; i++){
    printf("%d ", arr[i]);
}

// 실행결과: 41 9 33
  • 배열을 선언하면 메모리에 연속된 공간이 할당됨.
    • 위의 arr 배열은 int형이므로, 총 12바이트의 연속된 공간이 할당됨
  • 배열의 범위를 초과하는 인덱스를 사용하면, 배열이 아닌 메모리 영역에 접근할 수 있음
    • arr[4] -> 배열이 아닌 메모리 영역에 접근, 예기치 못한 동작을 유발

배열 초기화

  • 선언과 동시에 {}(중괄호)로 묶어 배열의 값을 초기화
    • int arr[4] = {3, 6, 9, 12}
    • int arr[5] = {10, 17, 14} (남은 두 요소는 0으로 채움)
    • int arr[5] = {0} (모든 요소를 0으로 초기화)
    • int arr[] = {3, 6, 9} (컴파일러가 자동으로 배열 개수를 3개로 정함)
  • 초기화 이후에는 중괄호 대입 연산이 불가능하므로, 각 요소에 값을 일일이 대입해야 함

sizeof 연산자

  • 배열 요소의 개수는 sizeof(배열명) / sizeof(배열 요소) 계산
int value[5];
// 배열 요소의 개수 계산
int count = sizeof(value) / sizeof(value[0]);

for (int i = 0; i < count; i++){
    scanf("%d", &value[i]);
}

int total = 0;

for (int i = 0; i < count; i++){
    total += value[i];
}

printf("%.1f", total / (double)count);

// 입력: 10 13 14 20 30
// 실행결과: 17.4
  • 위 예제에선 sizeof(value)20(바이트), sizeof(score[0])4(바이트)이므로 count는 5가 됨

문자열을 저장하는 배열

char형 배열

  • 문자열은 문자의 연속이므로 배열에 저장할 수 있음
  • 각 문자는 1바이트로 처리할 수 있으므로, char형 배열을 보통 사용
  • 배열 요소의 개수는 최소한 문자열 + 1이여야 함
    • 초기화 시, 문자열의 끝에 널 문자(\0)를 저장해야 하기 때문

// 문자열 초기화 및 출력
char str[80] = "ilovelgtwins";      // 문자열상수로 초기화
printf("%s\n", str);                // 실행결과: ilovelgtwins

// 위 코드에서 계속: 새로운 문자열 입력 및 출력
scanf("%s", str);           // 입력: lgfighting
printf("%s\n", str);        // 실행결과: lgfighting
  • char형 배열은 문자열 상수로 초기화할 수도 있음
  • 문자가 채워지지 않은 남는 배열 요소에는 0이 채워짐
    • 0널 문자 \0의 아스키코드 값
    • 문자열의 끝을 표시하는 용도로 사용
  • printfchar형 배열에서 널 문자가 나올 때까지만 출력
  • scanf는 사용자가 입력한 문자열 다음에 자동으로 널 문자를 추가

strcpy - 문자열 대입

  • char형 배열에 새로운 문자열을 저장하는 함수 (= 사용 불가)
  • strcpy(저장될 배열명, 저장할 문자열)
    • 저장할 문자열엔 문자열 상수 말고도, char형 배열 역시 선언 가능. 이 경우 배열에 저장된 문자열을 복사
  • #include <string.h> 선언 필요
#include <stdio.h>
#include <string.h> // 문자열 관련 함수 포함 헤더 파일

int main(void){
    char str1[30] = "twins";
    char str2[30];

    strcpy(str2, str1);     // str2 배열에 str1 배열의 문자열 복사
    strcpy(str1, "lg");     // str1 배열에 "lg" 복사
    printf("%s %s", str1, str2);
    // 실행결과: lg twins
    return 0;
}
  • 저장할 문자열이 배열 크기보다 큰 경우, 배열의 범위를 넘어 저장되어 메모리 오류가 발생할 수 있으니 주의할 것

문자열의 입출력: fgets, fputs

  • stdin, stdout은 키보드로 입출력을 한다는 뜻이라는 것만 알아두기
  • fgets(char형 배열명, 배열 크기, stdin)
    • fgets(str, sizeof(str), stdin)과 같이 사용
    • 입력받은 문자열 끝에 자동으로 줄바꿈 문자 + 널 문자를 붙임 ('hello\0\n')
    • scanf와 달리 공백을 포함해 문자열을 입력받을 수 있음
    • 배열의 크기를 지정 -> 입력 문자열이 메모리 영역을 침범하는 것을 방지
  • fputs(char형 배열명 or 문자열 상수, stdout)
    • 널 문자 이전까지 문자열을 출력
char str[80];
    fgets(str, sizeof(str), stdin);
    // [입력] c language is too hard :(
    fputs(str, stdout);
    // [출력] c language is too hard :(

널 문자가 없을 때

  • 배열을 문자열 상수로 초기화하면, 자동으로 마지막에 널 문자가 추가됨
  • 하지만 직접 문자를 각 요소에 대입하는 경우, 널 문자는 수동으로 대입해야 함
char str[5];
str[0] = 'S';
str[1] = 'O';
str[2] = 'S';
str[3] = '\0';          // 직접 널문자 대입
printf("%s\n", str);    // 실행결과: SOS
  • 널 문자가 없으면, printf로 출력하는 과정에서 배열에 할당되지 않은 이어지는 메모리 영역까지 출력할 수 있음
    • 쓰레기 값을 출력하거나, 메모리 접근 에러가 발생할 수 있음

연습문제

키보드로부터 문장을 입력받은 후, 대문자를 찾아 소문자로 바꾸는 프로그램을 작성합니다.
바뀐 문장과 바뀐 문자의 수도 출력합니다.

  • 띄어쓰기가 있는 문자열이 올 수도 있으니, scanf 대신 fgets 사용
  • 문자열 끝의 널 문자(\0)를 만나면 반복문을 종료해야 함
    • sentence[i] != 0로 확인하기
  • 문자는 내부적으로 정수(ASCII 코드)로 저장되므로, 대소 비교와 연산이 가능함
    • A <= sentence[i] && sentence[i] <= Z로 대문자 여부 확인
    • ('a' - 'A')는 같은 알파벳의 소문자와 대문자 간 정수 차이 -> 이만큼 더해주면 대문자에서 소문자로 변환
#include <stdio.h>
#include <string.h>

int main(void){
    int count = 0;
    char sentence[100];
    fputs("문장 입력: ", stdout);
    fgets(sentence, sizeof(sentence), stdin);

    // 널 문자를 마주치면 종료
    for (int i = 0; sentence[i] != 0; i++){

        // 문자가 대문자인 경우
        if ('A' <= sentence[i] && sentence[i] <= 'Z'){
            // 소문자로 변경
            // 대문자-소문자 간 아스키값 차이를 더함
            sentence[i] += ('a' - 'A');
            count += 1;
        }

    }
    // fgets로 입력받은 sentence는 끝에 줄바꿈 문자를 포함
    // 따라서 printf에선 줄바꿈 안 해줘도 됨
    printf("바뀐 문장: %s", sentence);
    printf("바뀐 문자 수: %d\n", count);
    return 0;
}

// [입력]
// 문장 입력: Hey bOy Imma getCha

// [출력]
// 바뀐 문장: hey boy imma getcha
// 바뀐 문자 수: 4
profile
뭔가 만드는 걸 좋아하는 개발자 지망생입니다. 프로야구단 LG 트윈스를 응원하고 있습니다.

0개의 댓글