C & C++

[C언어] 배열(Array) 구조 선언, 할당, 포인터 연산, 출력 예제

jimmy_AI 2021. 12. 7. 19:27
반응형

지난 번에 C언어 포인터에 관한 포스팅에 이어,

이번에는 포인터를 기반으로 한 배열 구조에 대한 예제를 몇 가지 다루어보고자 합니다.

 

C언어 배열 구조 선언(Array 선언)

배열 구조는 연속된 주소를 원하는 개수만큼 통째로 할당받아,

자료를 원하는 위치에 할당하여 순서로 접근 가능하게 만든 구조입니다.

 

다만, 파이썬의 리스트 등과는 다르게, 특정 자료형을 넣기로 선언했다면

해당 자료형만 넣어야하는 식의 구성으로 되어 있다는 점이 특징입니다.

 

예를 들어, 한 배열에 int, double 등 여러 자료가 섞여서 들어가는 것은 불가능합니다.

 

선언하는 문법 자체는 매우 간단합니다. 다음의 예시 코드를 살펴보겠습니다.

#include <stdio.h>

int main(){

// 배열 선언 (값 초기화 X)
int arr[5];

// 값 할당(4번 위치 미할당)
arr[0] = 1;
arr[1] = 3;
arr[2] = 5;
arr[3] = 7;
// arr[3] = 3.5; 불가능(int 자료형이 아님)

// 원소 출력해보기
for(int i = 0; i<5; i++){
  printf("%d\n", arr[i]);
}
}

원하는 사이즈를 미리 지정해서 몇 칸의 메모리를 할당 받을지를 먼저 선언해야합니다.

여기서는 5칸을 할당받기로 정했습니다.

 

인덱스는 파이썬 등 다른 언어와 마찬가지로 0번 부터 시작함에 유의해주세요.

위에서는 배열을 선언만하고, 값을 할당하는 일을 아래에서 따로 해주었습니다.

 

마지막 원소 자리인 4번 위치에는 값을 할당하지 않았는데요,

이 경우 랜덤하게 이상한 값이 삽입되므로 주의해야합니다.

for 문을 통하여 출력된 원소들의 상태를 살펴보겠습니다.

0~3번 위치에는 저희가 선언한 값이 잘 들어있고, 4번 위치에는 엉뚱한 값이

할당된 것을 확인해볼 수 있었습니다.

 

C언어 배열 구조 선언과 동시에 값 할당

위에서는 배열 구조 선언과 할당을 따로 진행했는데요.

이번에는 배열 구조를 선언과 동시에 값 할당을 진행해보겠습니다.

 

물론, 값 할당 이후에도 변경하는 것은 자유롭게 가능합니다.

#include <stdio.h>

int main(){

int arr_1[5] = {1, 3, 5, 7, 9};
int arr_2[5] = {}; // 모두 0으로 할당
double arr_3[5] = {1.0, }; // 0번 위치만 1.0, 나머지는 0.0 할당

// 원소 출력해보기
printf("arr_1 : \n\n");
for(int i = 0; i<5; i++){
  printf("%d ", arr_1[i]);
}

printf("\n\narr_2 : \n\n");
for(int i = 0; i<5; i++){
  printf("%d ", arr_2[i]);
}

printf("\n\narr_3 : \n\n");
for(int i = 0; i<5; i++){
  printf("%.1f ", arr_3[i]);
}
}

5개 크기의 배열을 선언한 뒤, arr_1은 5개의 값을 제가 원하는 값으로 선언한 예시이고,

arr_2는 빈 괄호로 선언하여 모든 숫자를 0으로 할당한 예시이며,

arr_3은 앞의 첫 원소만 1.0으로 할당하고, 나머지 숫자는 모두 0.0으로 할당한 예시입니다.

 

arr_3은 double 자료형을 넣은 배열임에 주의하며, 출력 결과도 살펴보겠습니다.

 

C언어 배열과 포인터의 관계

배열과 포인터의 관계를 할당된 주소를 출력해보며 이해해보도록 하겠습니다.

위에서 언급을 했었지만, 배열 내에 원소들은 연속된 칸에 저장되어 있다고 했었습니다.

 

int 자료값과 double 자료값이 저장된 배열들의 주소를 출력해보겠습니다.

#include <stdio.h>

int main(){

int arr_i[5] = {1, 3, 5, 7, 9};
double arr_d[5] = {1.0, 2.5, 4.0, 5.5, 7.0};

// 주소 출력해보기
printf("arr_i : \n\n");
for(int i = 0; i<5; i++){
  printf("%p\n", &arr_i[i]); // %p로 포맷팅
}

printf("\narr_d : \n\n");
for(int i = 0; i<5; i++){
  printf("%p\n", &arr_d[i]);
}
}
반응형

출력 결과를 살펴보시면, int 자료형 배열은 16진수의 숫자가 4씩 증가하고,

double 자료형 배열은 16진수 숫자가 8씩 증가하고 있음을 살펴볼 수 있습니다.

 

int 자료형은 4바이트, double 자료형은 8바이트의 자료형이라 나타나는 현상으로,

0번 ~ 4번 인덱스에 해당하는 자리가 연속으로 지정되어 있음을 알 수 있습니다.

 

위 원리를 기반으로 포인터 연산으로 배열 내 원소에 접근하는 것이 가능합니다.

 

C언어 포인터 연산으로 배열 원소 접근

#include <stdio.h>

int main(){

int arr_i[5] = {1, 3, 5, 7, 9};
double arr_d[5] = {1.0, 2.5, 4.0, 5.5, 7.0};

 // 첫 원소를 가리키는 주소에 대한 포인터 변수 선언
int* arr_i_ptr = &arr_i[0];
double* arr_d_ptr = &arr_d[0];

// 주소로 접근
printf("arr_i : \n\n");
for(int i = 0; i<5; i++){
  printf("%d ", *(arr_i_ptr + i)); // 포인터 연산 이용
}

printf("\n\narr_d : \n\n");
for(int i = 0; i<5; i++){
  printf("%.1f ", *(arr_d_ptr + i)); // 포인터 연산 이용
}
}

int, double 자료형에 대한 배열의 첫 원소의 주소에 해당하는 포인터를 선언하고,

해당 포인터를 기준으로 자료에 접근해보았습니다.

 

여기서 신기한 점은 ptr이 0번 인덱스의 주소이면, ptr + 1, ptr + 2, ... 는

1번, 2번, ... 인덱스의 주소를 나타내게 되는 연산을 수행할 수 있다는 점입니다.

 

또한, int, double 자료형은 size가 각각 4바이트, 8바이트로 다름에도,

포인터 연산에서는 이 점까지 자동으로 반영할 수 있다는 점도 주목해보시면 좋습니다.

 

출력 결과를 보시면, 각 배열의 원소가 제대로 출력된 점을 확인할 수 있습니다.

 

C언어 배열의 특수한 경우 : char 자료형 배열, 2차원 배열

마지막으로 C언어 배열의 특수한 경우만 살펴보고 이 글을 마무리해보도록 하겠습니다.

 

먼저, char 자료형에 대한 배열을 만든 경우는 파이썬을 공부해보신 분들은 알겠지만,

문자열(string) 자료형에 해당합니다.

이에 관한 자세한 내용이 궁금하시다면 아래 글을 참고해보세요.

 

[C언어] 문자열 선언 방법 정리(배열, 포인터)

C언어 string 배열 및 포인터 선언 예제 및 특징 비교 C언어에서 문자열(string) 자료를 char 배열로 선언하는 경우와 포인터를 이용하여 선언하는 경우의 예시 코드를 살펴보고, 이 두 문자열 선언 경

jimmy-ai.tistory.com

 

2차원 이상의 배열도 배열을 넣는 배열의 형태로 선언이 가능합니다.

다만, 역시나 자료형이 모두 일치해야한다는 제약 조건이 따라오기는 한다는 점에 유의해주세요.

2차원 배열에 대한 상세한 내용은 아래의 포스팅에서 확인하실 수 있습니다.

 

[C언어] 2차원 배열 선언, 값 접근/수정/출력 방법 및 문자열 배열

C언어 2차원 array 사용 방법 예제 이번 글에서는 C언어에서 2차원 배열을 선언하는 방법과 주요 특징을 먼저 살펴본 뒤, 값에 접근, 수정 및 출력하는 과정을 다루어보고 2차원 배열의 특수 케이스

jimmy-ai.tistory.com

이상으로 C언어 배열에 대한 전반적인 내용을 다룬 포스팅을 마무리하겠습니다. 감사합니다.