변수를 열심히 써 먹다 보면 한 가지 의문점이 생깁니다.

나는 여러 값들을 동시에 처리하고 싶은데, 변수로는 어떻게 못하나?

 

그래서 존재하는 것이 바로 배열과 문자열입니다.

배열을 통해 여러 값들을 동시에 다룰 수 있고, 문자열을 통해 여러 문자도 하나의 문장처럼 만들 수 있습니다!

 

목차

     


    0. 배열

    0.0. 배열의 선언

    5개의 값을 동시에 컨트롤하려면 5개의 변수를 만들어야 합니다. 굉장히 귀찮죠?

    이렇게 같은 데이터형의 변수를 동시에 처리해야 할 때 사용하는 것이 바로 배열입니다.

    배열같은 데이터형의 변수를 메모리에 연속적으로 할당하고 같은 이름으로 사용하는 방법을 제공합니다.

     

    배열을 선언하기 위해서는 배열의 데이터형배열의 이름, 배열의 크기가 필요합니다.

    [ ] 대괄호 안에 크기를 적어주는 것이 핵심이죠. 사용하기 전에 사용을 위한 메모리를 미리 잡아놓는 작업입니다!

     

    만약 배열의 크기가 없거나, 변수가 들어가게 되면 컴파일을 할 때 에러가 발생하게 됩니다.

    처음에 C언어를 접근할 때 가장 쉽게 마주치게 되는 에러가 바로 배열에 변수설정하는 부분이니, 꼭 기억하고 계셨다가 오류가 발생했을 때 쉽게 찾아낼 수 있도록 합시다! (이것때문에 제가 C++ 처음 배울 때 많이 고생했습니다 ㅠㅠ)

     

    배열의 크기는 리터럴, 혹은 매크로 상수로도 지정할 수 있습니다. (변수가 아니니까요!!)

    또한 배열은 모두 같은 데이터형이기 때문에, 배열 전체의 바이트 크기를 배열 원소 하나의 바이트 크기로 나누면 배열 원소의 개수(실질적인 배열의 크기)를 구할 수 있습니다.

     

    0.1. 배열의 사용

    배열의 각 원소에 접근하기 위해서는 인덱스를 사용합니다.

    인덱스는 항상 0부터 시작하고, 배열 크기보다 1 작은 값까지 사용할 수 있습니다. (본 블로그의 순서 체계가 0부터 시작하는 이유입니다 ㅋㅋㅋㅋㅋㅋ)

     

    만약 인덱스에 유효 범위(0 ~ 배열 크기-1)에서 벗어난 수를 넣게 된다면 실행시 에러가 발생할 수 있습니다. 할당하지 않는 곳을 참조하려고 하면 당연히 못찾겠죠?

     

    배열을 사용할 때 초기화를 하지 않았다면 쓰레기값을 가지게 됩니다.

    그렇기 때문에 만들 때 초기화를 사용하는 것이 좋습니다.

     

    초기화를 하는 방법은 선언하고 나서 { } 안에 초기값들을 넣어주는 방식으로 할 수 있습니다.

     

    이 과정에서 배열을 초기화할 때 초기값을 원소의 개수보다 부족하게 지정하면 나머지 원소를 0으로 초기화합니다.

     

    또한 배열을 초기화하기 위해서 { }를 사용할 때는 반드시 초기값을 하나 이상 지정해야 합니다.

     

    배열의 초기값을 지정할 때 배열의 크기를 생략하면, { } 안에 있는 값으로만 배열을 생성합니다. 만약 { } 안에 값이 3개가 들어있다면 배열의 크기가 3인 배열이 만들어지는 것이죠.

     

    아래는 정수형 배열의 합계와 평균을 구한 코드입니다.

    복습하는 셈 치고 하나하나 뜯어보시면 이해에 도움이 되실 겁니다.

    scanf_s를 사용한 이유는 Visual Studio 2005버전부터 scanf를 사용하게 되면 입력된 값을 저장할 때 메모리를 초과해버리는 버퍼 오버플로우때문에 데이터 손실이 있을 수 있기 때문에 scanf 대신 안전한 scanf_s를 사용하라는 경고가 뜨기 때문입니다.

     

    문자열 파트에서 _s가 붙는 안전 함수에 대해서 추가적으로 말씀 드리겠지만, 만약 이 문제에 대해 좀 더 깊은 관심이 있으신 분은 아래 블로그에 자세하게 설명이 되어 있어서 링크를 참고하시면 될 것 같습니다!

    (혹시나 머리가 지끈지끈하시는 분은 이 부분은 그냥 넘어가셔도 됩니다!)

     

    [C/C++]scanf와 scanf_s 함수의 차이점. #버퍼 오버플로우, C4996 오류

    표준입력함수 scanf / scanf_s자바의 Scanner, 자바스크립트의 prompt C언어의 scanf 그리고 scanf_s 이...

    blog.naver.com

    /* Ex07_04.c */
    #include <stdio.h>
    
    #define MAX 5
    
    int main(void)
    {
    	int arr[MAX] = { 0 };
    	int i;
    	int sum;
    	double average;
    
    	printf("%d개의 정수를 입력하세요: ", MAX);
    	for (i = 0; i < MAX; i++)
    		scanf_s("%d", &arr[i]);
    
    	for (i = 0, sum = 0; i < MAX; i++)
    		sum += arr[i];
    
    	average = (double)sum / (double)MAX;
    	printf("합계: %d, 평균: %5.2f\n", sum, average);
    
    	return 0;
    }

     


    1. 다차원 배열

    만약 더 많은 요소들을 한번에 컨트롤 하고 싶다면 어떨까요?

    배열 안에 배열을 나눠서 2단으로 나누면 좀 더 깔끔하게 정리가 될 수 있지 않을까요?

    이래서 등장한 것이 바로 다차원 배열입니다.

    배열의 원소에 접근하기 위해서 인덱스를 둘 이상 사용하는 경우가 바로 다차원 배열입니다.

    다차원 배열 역시 일차원 배열처럼 연속된 메모리에 할당합니다.

     

    만약 이차원 배열의 원소에 접근하고 싶다면 인덱스를 두 개 사용하면 됩니다.

    인덱스의 개수가 바로 배열의 차수가 됩니다. 2개면 2차, 3개면 3차 이런 식으로 말이죠.

     

    이차원 배열을 초기화할 때 역시 { } 안에 { }가 들어가 있는 방식으로 해 주면 됩니다.

    배열의 초기값 나열 방식, 생략시 0으로 초기화되는 규칙 역시 동일하게 적용됩니다.

    따라서 일반적인 일차원 배열을 생각하면서 다차원 배열을 만들면 쉽게 적용하실 수 있습니다.

    추가적으로 일차원 배열처럼 { } 안에 초기값만 나열할 수도 있습니다.

     

    한 가지 다른 점이 있다면, 이차원 배열을 만들 때, 배열의 크기를 생략할 때 앞은 생략이 가능하지만 뒤는 생략이 불가능합니다.

    이는 마지막에 몇 개로 묶을 지 알 수 없기 때문입니다.

     


    2. 문자열

    2.0. 문자열의 기본 사용

    문자열은 말 그대로 연속된 문자들의 모임입니다.

    문자열은 큰 따옴표(" ")로 표현하고, 문자열의 끝에는 NULL 문자('\0')를 함께 저장합니다.

    문자열의 끝을 컴퓨터에게 알리기 위해서입니다. 만약 NULL 문자가 없다면 컴퓨터는 이 문자열이 언제 끝나는 지 알 수 없겠죠?

     

    변수에서 배웠던 내용과 동일하게, 문자열 역시 상수와 변수가 있습니다. 프로그램 수행 중에 값이 변하지 않는 문자열이 문자열 상수, 값이 변경될 수 있는 문자열이 문자열 변수입니다.

     

    문자열의 크기는 저장할 문자열의 길이 + 1로 할당해야 합니다. NULL 문자의 자리도 만들어 주는 것이죠.

     

    문자열도 인덱스를 이용해서 문자열의 원소에 접근할 수 있습니다.

     

    문자열을 초기화 할 때는 문자열 상수를 이용합니다.

    만약 문자열의 크기보다 큰 문자열로 초기화하면 컴파일 경고가 발생합니다.

    문자열의 크기보다 작은 문자열로 초기화하면 빈 부분은 NULL 문자가 들어갑니다.

     

    초기값을 지정할 때는 문자열의 크기를 생략할 수 있습니다.

     

    문자열을 바꾸고 싶을 때 문자열 변수에 새로운 문자열을 할당할 수는 없습니다.

    이럴 때는 문자열에 저장된 각 문자를 하나씩 변경하거나, 문자열 처리 함수를 이용합니다.

    컴퓨터는 문자열을 읽을 때 NULL 문자가 등장하는 순간 문자열이 끝났다고 인식하기 때문에 NULL 문자 뒤에 값이 존재하더라도 신경쓰지 않습니다.

     

    2.1. 문자열 처리 함수

    문자열 처리 함수는 문자열의 복사, 비교시, 혹은 문자열의 길이를 구할 때 이용합니다.

    이 문자열 처리 함수를 사용하기 위해서는 전처리문 위치에 #include<string.h>를 포함해야 합니다.

     

    문자열의 복사strcpy 함수를 이용합니다.

    매개변수로 첫 번째에는 복사될 문자열명, 두 번째에는 복사할 값을 넣습니다.

     

    만약 strcpy 함수에서 복사할 값의 길이가 복사될 문자열의 크기보다 크면 실행 에러가 발생할 수 있습니다.

     

    문자열의 길이strlen 함수를 이용해서 구할 수 있습니다.

    strlen(문자열명) 형식으로 사용할 수 있습니다.

     

    문자열의 내용을 비교할 때는 strcmp 함수를 이용합니다.

    strcmp(문자열1, 문자열2) 형식으로 사용합니다.

    만약 ==를 사용하면 문자열의 주소만 비교하게 됩니다.

     

    문자열끼리 연결할 때는 strcat 함수를 이용합니다.

    strcat(주 문자열, 추가할 문자열) 형식으로 사용합니다.

     

    문자열을 입력받아서 보관하려면 %s 형식으로 받아서 사용합니다. 출력할 때도 %s를 사용합니다.

    이 때 주의해야 할 점은 scanf 함수는 공백문자가 나오면 입력을 종료합니다.

    만약 빈칸을 포함한 문자열을 입력받기 위해서는 scanf가 아닌 gets 함수를 사용해야 합니다.

     

    get 함수는 빈칸을 포함한 한 줄의 문자열을 입력받는 데 사용되고 put 함수는 한 줄의 문자열을 출력하는데 사용됩니다.

    아래 예시에서 sprintf는 문자열 값을 출력하는 동시에 문자열을 저장하는 함수입니다.

     

    위에서 scanf_s에 대한 이야기를 잠깐 했는데, 이와 비슷하게 문자열 관련 함수를 사용하다 보면 할당 받은 배열 크기를 넘어서 메모리를 사용하게 되는 오버플로우(오버런) 문제가 발생할 수 있습니다. (위에서 잠깐 언급했죠?)

     

    그래서 문자열 관련 함수를 사용할 때 _s를 붙여 안전 문자열 처리 함수를 사용하기도 합니다.

    VS에서는 컴파일할 때 미리 경고를 날려줍니다. 이런거 두고 못 보는듯 ㅋㅋㅋㅋ

     

    문자열 역시 배열로 저장할 수 있습니다. 실제로 문자열이 들어가는 맨 마지막 배열부분은 저장할 문자열의 길이+1로 지정하고, 그 앞은 필요한 문자열의 개수를 지정합니다. NULL 문자가 들어갈 공간을 확보하기 위해서입니다!!

     

    접근할 때는 문자열 하나를 가져오려면 인덱스를 하나만 사용하고, 문자열 안의 특정 문자를 가져올 때는 인덱스를 2개 사용합니다.

     

    문자열을 초기화 하는 것도 { }를 이용할 수 있고, 똑같이 배열의 제 1크기를 생략할 수 있습니다.

    아래 예시는 어짜피 요소가 총 5개 있으니까 컴퓨터가 알아서 fruits[5][20]으로 설정해서 배열을 만들겠죠!


    오늘 내용은 꽤 길어보이지만, 공통점을 가지고 있는 배열과 문자열에 대한 내용이었기에 계속 반복되는 내용의 연속이라 빠르게 넘어오실 수 있었을 겁니다.

    다음 주제인 포인터부터는 갑자기 난이도가 급상승할 수 있으니 단단히 마음먹고 오시는 것이 좋습니다..! (대부분 포인터에서 포기하시는 분들이 속출하더라구요 ㅠㅠ)

    그래도 여기까지 왔으면.. 마지막까지 포기할 수 없겠죠?

    그렇다면 다음 포스팅에서 뵙겠습니다 :)

    반응형
    • 네이버 블로그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기