Category (Click)
개발보드 덕질하기
🪱

[배열] 문자열

정렬 아니고요, 변수 다발입니다.
배열이라는 명칭은 다양한 의미를 가지고 있어 햇갈리기가 쉽습니다. C언어에서의 배열은 동일한 자료형을 연속적으로 메모리에 저장하는 자료 구조입니다. 1, 2, 3, 4와 같이 숫자를 저장하면 수열(숫자 배열)이, a, b, c, d와 같이 문자를 저장하면 문자열(문자 배열)이 되는 것이죠. 아래 내용을 통해 문자열에 대해 알아보도록 하겠습니다.
이미 여러분들은 하나의 문자를 표현하기 위해서는 char형 변수를 사용하고, 이 변수에 ASCII 코드에 대응되는 숫자를 넣는다는 것을 알고 있을텐데요, 이를 코드로 표현하자면 위와 같습니다.
그런데, a가 아니라 abcd를 변수로 저장하고 싶다면 어떻게 해야할까요? chat형이 1 byte이니 4 byte짜리 자료형(int)에다가 저장하는걸까요?
물론… 시프트 연산자를 활용하면 할 수는 있지만, 비트연산을 생각하자니 상당히 고통스럽고 귀찮습니다. 그런데, 만약 abcd보다 더 긴 것을 저장한다면 어떻게 될까요? 가장 큰 자료형인 long long을 넘기면 이런 방식으로는 해결할 수가 없죠.
바로 이럴 때 배열(Array)을 사용합니다. 위의 소스코드에서 6번 줄을 실행한 후에는 위 사진 중 왼쪽과 같이 메모리에 데이터가 저장되는데요, 이걸 약간 변형해 오른쪽 사진과 같이 저장되도록 하는것이 배열입니다.
배열을 적용하면 이렇게 코드로 구현할 수 있습니다. 위의 코드를 이해하려 하지는 마시고, 아래 내용을 통해 배열에 대해 자세히 알아보도록 하겠습니다.

배열 선언

배열을 선언할 때에는 변수 선언과 마찬가지로 (자료형) (변수 명) 순으로 작성하면 되는데요, 이때 변수 명 뒤에 대괄호([])를 쓰고 대괄호 속에 배열의 길이를 입력합니다. 이렇게 코드를 작성하면 char 자료형의 변수가 메모리 상에 연속적(일렬)으로 4개 생성됩니다.

배열의 구조

이때 변수 명(여기에서는 array)은 배열의 첫 번째 메모리 주소번지를 가르키는 포인터 변수가 됩니다. 따라서 위 코드와 같이 변수 명을 출력하면 a를 저장하고 있는 메모리의 주소가 나옵니다.
위 코드에서 1번 줄을 실행하면 메모리에는 위 사진과 같이 데이터가 저장됩니다. 만약 첫 번째 데이터인 a를 출력하고 싶다면,
역참조 연산자(*)를 앞에 붙이면 됩니다.
두 번째 데이터를 출력한다면 포인터에 1을 더한 후 역참조 연산자를 사용하면 됩니다. 이런 방식으로 나머지도 전부 출력하면 위 사진처럼 됩니다.
물론 배열의 각 방에 데이터를 넣을때도 이렇게 하면 됩니다. 아래 코드를 참고하세요.
연산자 우선순위에 주의해야합니다. 역참조 연산자(*)는 덧셈 연산자(+)보다 우선순위가 높아 괄호로 덧셈부터 하도록 해야합니다.
만약 괄호가 없다면 a에 1을 더해 b가 출력됩니다. 결론적으로는 정상적으로 작동하는것처럼 보이겠지만 의도된 동작이 아닙니다.
위 코드는 구조체 포인터의 배열의 포인터(구조체 2중 포인터)인 subscribe_list_의 데이터(포인터)에서 첫 번째 배열의 topic 멤버 변수의 포인터를 가져오는 구문입니다. 이처럼 프로젝트가 복잡해질 수록 연산자 우선순위가 중요해집니다.
그런데, 이렇게 매번 역참조 연산자를 사용하면 너무 귀찮겠죠? 그렇기 때문에 배열에서 데이터를 가져올 때에는 역참조 연산자 대신 아래 첨자 연산자([])를 사용합니다. 배열의 이름 뒤에 대괄호를 작성하고, 대괄호 안에는 더할 메모리를 작성하면 됩니다. 만약 첫 번째 데이터인 a를 출력하고 싶다면 0을, b를 출력한다면 1을 입력하면 되겠죠. 위의 역참조 연산자로 작성한 예시를 아래 첨자 연산자로 변환하면 아래와 같습니다.
훨씬 단순해졌죠? 대괄호 안의 숫자가 0부터 시작하는 이유는 이러한 이유입니다.
입력 역시 동일합니다.
여기서 아래 첨자 연산자이진 연산자로 간주됩니다. 즉 AND(&&), OR(||)과 같이 데이터의 연산자에 대한 전위 후위 순서는 아무런 의미가 없습니다. 참고로 대괄호의 시작점을 기준으로 전위[후위] 입니다.
코드로 설명하자면, 위 두 코드의 출력은 동일합니다. 세상에..

배열의 데이터 입력

배열에 데이터를 입력하는 방법은 배열 선언 시배열 선언 후, 2가지 방법으로 나뉩니다.
배열 선언 시 배열의 항목을 차례대로 입력
예제에서 사용한 방법입니다. 배열의 각 항목을 중괄호({}) 속에 콤마(,)로 구분해 순서대로 입력합니다. 저희는 문자를 배열에 넣기 때문에 a, b, c, d를 각각 따옴표()로 감싸 입력했습니다.
배열 선언 시 쌍따옴표로 문자열 입력
위의 방법은 간단한 대신 문자열 생성에만 사용할 수 있습니다. 쌍따옴표() 사이에 입력할 문자를 입력하면 자동으로 문자열(문자 배열)을 만들어 배열에 넣어줍니다. 그런데, 이 방법에서는 마지막 문자에 문자열의 끝을 알리는 NULL 문자(ASCII에서 0, \0으로 표현)를 자동으로 추가하기 때문에 입력하려는 문자열보다 하나 더 큰 배열을 생성해야 합니다. 만약 위의 코드에서 대괄호 사이의 숫자(5)를 지우면 뒷쪽의 문자열에 알맞은 공간을 자동으로 생성합니다.
이 내용을 조금 더 깊게 들어가자면 abcd 자체는 리터럴에 해당합니다. 위와 같이 코드를 작성하면 메모리의 수정 불가능한 영역에 abcd\0라는 문자열이 생성되게 되고, 이 데이터가 array라는 변수에 복사되는 것입니다. 문자열의 내용을 나중에 수정할 일이 있다면 이대로 두어도 되겠지만, 문자열을 수정할 필요가 없다면 이렇게 사용하는것은 낭비겠죠? 이럴때는 아래와 같이 문자열을 생성합니다.
리터럴 문자열 생성 및 포인터 변수에 저장
이렇게 문자열을 생성하면 메모리의 읽기 전용 공간에 리터럴 데이터인 abcd\0이 생성되고, a의 메모리 주소가 array에 저장됩니다.
이때 리터럴 데이터는 수정이 불가능하기 때문에 수정하려 하면 위와 같은 에러가 발생합니다.
배열 선언 후 문자열 입력
배열을 선언한 후에는 배열 하나하나에 따로 문자를 넣어주어야 합니다.