다른 명령
편집 요약 없음 |
편집 요약 없음 |
||
| 67번째 줄: | 67번째 줄: | ||
T A[N][M]; | T A[N][M]; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
이는 N행 M열의 2차원 배열을 선언하고, 선언된 배열의 메모리 크기는 <code>N * M * sizeof(T)</code>이다. 이때 이차원 배열의 각 | 이는 N행 M열의 2차원 배열을 선언하고, 선언된 배열의 메모리 크기는 <code>N * M * sizeof(T)</code>이다. 이때 C언어는 row-major order를 사용하여 이차원 배열의 각 원소들을 저장한다. Row-major order란 같은 행의 원소들이 메모리 상에서 연속적으로 저장되는 것을 의미한다. 예를 들어, 아래와 같이 배열이 주어져있다고 가정하자. | ||
[[파일:2D Array- Array of Array.png|대체글=Figure 3. 2D Array: Array of Array|섬네일|500x500픽셀|'''Figure 3. 2D Array: Array of Array''' ]] | |||
<syntaxhighlight lang="c"> | |||
int val[4][5] = { | |||
{9, 8, 1, 9, 5}, | |||
{9, 8, 1, 0, 5}, | |||
{9, 8, 1, 0, 3}, | |||
{9, 8, 1, 1, 5} | |||
}; | |||
</syntaxhighlight> | |||
위의 배열은 row-major order 기준으로 각 행에 연속적으로 20바이트를 할당한다. 배열이 메모리에 할당된 모습은 figure 3에 잘 나타나있다. | |||
i | |||
2차원 배열은 배열의 배열이라고 할 수 있다. 이에 따라, A[i]는 i번째 행(배열)의 시작 주소를 의미한다. 따라서 A[i]가 가리키는 주소는 <code>A[i] = A + i * (M * sizeof(T))</code>와 같이 계산된다. | |||
==각주== | ==각주== | ||
[[분류:컴퓨터 시스템]] | [[분류:컴퓨터 시스템]] | ||
2025년 5월 13일 (화) 04:07 판
상위 문서: Assembly
개요
해당 문서에서는 1차원 배열(array)와, 다차원 배열, 그리고 포인터 배열의 특성에 대해 다룬다. 또한 구조체(struct)를 선언할 때, 구조체가 메모리에 어떻게 배치되는지와 정렬 및 패딩(padding) 규칙이 구조체에 어떤 영향을 미치는지에 대해 다룬다.
Array
C에서는 기본적으로 아래와 같이 배열을 선언한다:
T A[N];
T는 배열의 원소(element)의 자료형, N는 배열에 최대로 저장될 수 있는 원소의 수에 해당한다. 위 명령어를 통해 총 N * sizeof(T) 바이트의 연속적인 메모리 할당이 이뤄진다. 예를 들어, char *p[3];와 같은 명령어는 포인터 자료형의 크기가 8바이트이므로, 총 24바이트의 공간이 할당된다. 이는 figure 1이 잘 보여준다.
Array Access
기본적으로 배열 이름 A는 배열의 첫 원소의 시작 주소를 지정하는 포인터처럼 작동한다. 예를 들어, 배열 val이 figure 2와 같이 선언되었을 때, 배열 이름 val에 대한 산술 연산은 아래와 같이 작동한다.
| Expression | Type | Value |
|---|---|---|
| val | int* | x |
&val[1] or val + 1
|
int* | x + 1 * 4 |
val[1] or *(val + 1)
|
int | 5 |
&val[i] or val + i
|
int* | x + i * 4 |
아래는 배열의 원소에 접근하는 C언어 기반의 함수와, 동일한 작업을 수행하는 어셈블리 코드이다.
int get_elem(int* arr, long idx) {
return arr[idx];
}
get_elem:
mov (%rdi,%rsi,4), %eax
ret
위 어셈블리 코드에서 %rdi는 배열의 시작 주소를 의미하며, %rsi는 인덱스를 의미한다. 따라서, arr[idx]는 %rdi + 4 * %rsi에 위치한 원소이다.
Array vs. Pointer in C
배열과 포인터는 밀접한 관계가 있지만, 동일하지 않다. char str1[32];과 같이 배열 이름은 포인터처럼 사용될 수 있지만, 진짜 포인터 변수는 아니다. 이는 아래의 예시 코드를 통해서 알아볼 수 있다.
char str1[32];
char str2[64];
char *p = str1;
printf("%p vs. %p\n", str1, p);
printf("sizeof(str1) = %ld\n", sizeof(str1)); // 배열의 크기 = 32
printf("sizeof(p) = %ld\n", sizeof(p)); //포인터 크기 = 8
p = str2; //char* 포인터에 배열 이름 할당은 괜찮음
str2 = p; //이는 컴파일 오류를 야기
위의 코드에서는 마지막 줄이 컴파일 오류를 야기한다. 이는 배열 이름은 사실상 상수와 같이 동작하므로, 재할당이 불가하기 때문이다. 하지만 그 외에는 사실상 포인터와 같이 동작하므로, 서로 호환되어 사용되는 것을 보여준다.
Multi-dimensional (2D) Array
C에서는 다음과 같이 2차원 배열을 선언한다:
T A[N][M];
이는 N행 M열의 2차원 배열을 선언하고, 선언된 배열의 메모리 크기는 N * M * sizeof(T)이다. 이때 C언어는 row-major order를 사용하여 이차원 배열의 각 원소들을 저장한다. Row-major order란 같은 행의 원소들이 메모리 상에서 연속적으로 저장되는 것을 의미한다. 예를 들어, 아래와 같이 배열이 주어져있다고 가정하자.
int val[4][5] = {
{9, 8, 1, 9, 5},
{9, 8, 1, 0, 5},
{9, 8, 1, 0, 3},
{9, 8, 1, 1, 5}
};
위의 배열은 row-major order 기준으로 각 행에 연속적으로 20바이트를 할당한다. 배열이 메모리에 할당된 모습은 figure 3에 잘 나타나있다.
i
2차원 배열은 배열의 배열이라고 할 수 있다. 이에 따라, A[i]는 i번째 행(배열)의 시작 주소를 의미한다. 따라서 A[i]가 가리키는 주소는 A[i] = A + i * (M * sizeof(T))와 같이 계산된다.