C 배열 기본 - sonkoni/Koni-Wiki GitHub Wiki

배열 기본

배열은 그 주소가 첫 인자(0번 인덱스)의 주소이다. 그래서 포인터 연산과 상호 호환된다.

하지만 엄밀히 말해 배열은 포인터와 다르다. 배열은 스토리지를 갖고 있는데 반해, 포인터는 단지 주소를 저장하고 있는 변수일 뿐이다. 따라서 배열이 포인터로 퇴화(decay)하여 포인터처럼 쓰일 수는 있지만 포인터가 배열이 되지는 못한다. 이는 sizeof 연산자를 통해 크기를 구해보면 딱 안다.

== 선언 ==
자료형 배열이름[가로갯수];                // 선언.
자료형 배열이름[가로갯수] = {값, 값, 값};   // 선언하며 할당
자료형 배열이름[가로갯수] = {0,};         // 선언하며 0으로 초기화

== 자료형배열: 배열 선언하며 동시 할당 ==
자료형 배열이름[] = {값, 값, 값};

== 접근 ==
배열이름[인덱스]

== 할당 ==
배열이름[인덱스] = 값;   // 특정 인덱스에 값 할당.   numArr[3] = 16;
자료형 * 포인터 = 배열;  // 포인터에 배열 할당      int *numPtr = numArr;

인덱스는 0부터 시작한다. 선언 시 들어가는 크기와 헷갈리지 말아야 한다. 배열의 인덱스가 0부터 시작하는 이유는 메모리 주소가 0부터 시작하기 때문이다. 배열의 이름도 포인터이므로 인덱스가 0으로 시작하면 요소 접근과 포인터 연산이 일치하게 된다.

C에서 만약 인덱스를 벗어나거나, 인덱스에 음수를 입력하면 쓰레기값이 출력된다. 강제로 다른 메모리 공간에 접근한 것이다. 만약 이곳에 값을 할당해버리면 엉뚱한 일이 벌어지니 조심해야 함.

    int numArr[5];   (11)(12)(13)(14)(15) :: 총 5개
                       |               |
            index:    [0]             [4]
#include <stdio.h>
int main(int argc, char *argv[]) {
    // 초기화
    int numArr[5] = {0,};
    printf("=> %d\n", numArr[4]);
    // => 0

    // 할당
    numArr[3] = 13;
    printf("=> %d\n", numArr[3]);
    // => 13

    // 선언 후 바로 할당
    int nArr[5] = {11, 12, 13, 14, 15};
    printf("=> %d\n", nArr[0]);
    printf("=> %d\n", nArr[4]);
    // => 11
    // => 15

    // 인덱스를 벗어나면 쓰레기값이 반환된다.
    printf("=> %d\n", nArr[100]);
    // => -1113282265

    return 0;
}

선언 길이보다 초기 할당이 적을 때

선언 길이보다 초기 할당이 적을 경우 자동으로 나머지 공간이 0으로 채워진다.

#include <stdio.h>
int main(int argc, char *argv[]) {
    int scArr[5] = {11, 22};  // 초기 할당이 선언 길이보다 짧은 경우
    for (int i = 0; i < 5; i++) {
        printf("%2d ", scArr[i]);
    }
    return 0;
}
// 11 22  0  0  0 

선언만 하고 아무 값도 할당하지 않은 경우라면 쓰레기값으로 채워진다.

#include <stdio.h>
int main(int argc, char *argv[]) {
    int scArr[5];  // 선언만 하고 한 번도 초기화하지 않음
    for (int i = 0; i < 5; i++) {
        printf("%2d ", scArr[i]);
    }
    return 0;
}
// -1300699696 32759 288102531  1  7 

이러한 특성으로 인해 배열 초기화 = {0, };가 아니라 그냥 = {0}; 만 넣어도 초기화 된다는 걸 알 수 있다.

#include <stdio.h>
int main(int argc, char *argv[]) {
    int scArr[5] = {0};  // 그냥 0 하나만 넣을 경우
    for (int i = 0; i < 5; i++) {
        printf("%2d ", scArr[i]);
    }
    return 0;
}
// 0  0  0  0  0 

자료형 배열

#include <stdio.h>
int main(int argc, char *argv[]) {
    // 자료형 배열: 선언하며 동시 할당 시에는 갯수를 생략할 수 있음.
    //           후행으로 오는 초기화 배열 리터럴의 갯수가 배열갯수가 된다.
    int scArr[] = {11, 22, 33, 44, 55};
    for (int i = 0; i < 5; i++) {
        printf("%2d ", scArr[i]);
    }
    return 0;
}
// 11 22 33 44 55 

배열 요소의 갯수

배열에 sizeof 연산자를 사용하면 배열 전체 크기가 나온다. 여기에 하나의 인덱스가 차지하는 공간을 나누면 배열 요소의 갯수를 구할 수 있다.

#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5]; // 배열 요소의 갯수는 5이다.
    int count = sizeof(numArr) / sizeof(int); // 이렇게 배열요소의 갯수를 역으로 구할 수 있다.
    printf("size => %d", count);
    return 0;
}
// size => 5

배열 요소를 모두 출력하기

#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5] = {11, 12, 13, 14, 15};
    int count = sizeof(numArr) / sizeof(int);

    // 순방향 출력
    for (int i = 0; i < count; i++) {
        printf("idx[%d]: %d\n", i, numArr[i]);
    }
    printf("------\n");

    // 역방향 출력
    for (int i = count - 1; i >= 0; i--) {
        printf("idx[%d]: %d\n", i, numArr[i]);
    }

    return 0;
}
// idx[0]: 11
// idx[1]: 12
// idx[2]: 13
// idx[3]: 14
// idx[4]: 15
// ------
// idx[4]: 15
// idx[3]: 14
// idx[2]: 13
// idx[1]: 12
// idx[0]: 11

배열 요소의 합계 구하기

#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5] = {11, 12, 13, 14, 15};
    int count = sizeof(numArr) / sizeof(int);
    int sum = 0;
    for (int i = 0; i < count; i++) {
        sum += numArr[i];
    }
    printf("sum: %d", sum);
    return 0;
}
// sum: 65

배열 요소마다 2배수로 저장하기

#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5] = {11, 12, 13, 14, 15};
    int count = sizeof(numArr) / sizeof(int);
    for (int i = 0; i < count; i++) {
        numArr[i] *= 2;
        printf("idx[%d]: %d\n", i, numArr[i]);
    }
    return 0;
}
// idx[0]: 22
// idx[1]: 24
// idx[2]: 26
// idx[3]: 28
// idx[4]: 30

배열과 포인터

배열은 사실 첫 번째 요소의 주소값이다.

#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5] = {11, 12, 13, 14, 15};
    printf("%p\n", numArr);
    printf("%p\n", &numArr[0]);
    return 0;
}
// 0x7ff7b2d905b0
// 0x7ff7b2d905b0
#include <stdio.h>
int main(int argc, char *argv[]) {
    int numArr[5] = {11, 12, 13, 14, 15};

    // 배열이 첫 번째 요소의 `주소값`이기 때문에 포인터에 할당 가능
    int *numPtr = numArr;
    
    // 배열이든 배열포인터든 역참조하면 동일하게 첫 번째 요소가 출력됨
    printf("=> %d, %d\n", *numArr, *numPtr);
    
    // 배열이든 배열포인터든 인덱스를 통해 동일하게 접근 가능
    printf("=> %d, %d\n", numArr[2], numPtr[2]);
    
    // sizeof(배열)  : 배열의 전체 크기(4바이트 * 5요소 = 20)가 출력됨
    // sizeof(포인터) : 포인터 크기(8바이트. LP64)가 출력됨
    printf("=> %zu, %zu\n", sizeof(numArr), sizeof(numPtr));
    return 0;
}
// => 11, 11
// => 13, 13
// => 20, 8

배열을 활용하여 10진수를 2진수로 변환

#include <stdio.h>
int main(int argc, char *argv[]) {
    int decimal = 13;
    int binary[20] = {0,};
    int position = 0;
    while (1) {
        binary[position] = decimal % 2;  // 나머지 저장
        decimal /= 2;                    // 몫 저장
        position++;        // 자릿수 변경
        if (!decimal) {    // 몫이 0이 되면 반복 종료
            break;
        }
    }
    
    // 배열 요소 역으로 출력
    for (int idx = position - 1; idx >= 0; idx--) {
        printf("%d", binary[idx]);
    }
    printf("\n");
    
    return 0;
}
// 1101
⚠️ **GitHub.com Fallback** ⚠️