C언어에서 배열을 효율적으로 사용하는 베스트 프랙티스

배열은 C언어에서 데이터를 효율적으로 관리하고 처리할 수 있는 핵심적인 자료 구조입니다. 배열을 올바르게 활용하면 코드의 간결성과 성능을 크게 향상시킬 수 있습니다. 본 기사에서는 배열의 기본 개념부터 시작하여 성능 최적화를 위한 베스트 프랙티스와 실제 응용 예제를 다룹니다. 이를 통해 배열을 보다 효과적으로 사용할 수 있는 방법을 알아보겠습니다.

배열의 기본 개념과 선언 방법


배열은 동일한 데이터 타입의 여러 값을 하나의 변수로 관리할 수 있는 자료 구조입니다. C언어에서 배열은 고정된 크기를 가지며, 메모리에 연속적으로 할당됩니다.

배열 선언과 초기화


배열을 선언할 때는 데이터 타입과 배열 이름, 그리고 크기를 지정합니다. 초기화는 선언과 동시에 값을 설정하는 방식으로 이루어집니다.

// 배열 선언
int numbers[5]; // 크기가 5인 정수형 배열

// 선언과 동시에 초기화
int numbers[5] = {1, 2, 3, 4, 5}; 

// 일부 초기화 (나머지는 0으로 설정)
int numbers[5] = {1, 2}; // {1, 2, 0, 0, 0}

배열 크기 계산


배열의 크기는 sizeof 연산자를 사용해 계산할 수 있습니다.

int numbers[5] = {1, 2, 3, 4, 5};
size_t size = sizeof(numbers) / sizeof(numbers[0]); // 배열 요소 개수 계산

배열의 장점

  • 효율적인 데이터 관리: 반복적인 데이터 처리에 적합합니다.
  • 연속된 메모리 할당: 데이터 접근 속도가 빠릅니다.

배열 사용 시 주의사항

  • 배열 크기를 초과하여 접근하면 메모리 오류가 발생할 수 있습니다.
  • 크기를 명확히 정의하지 않으면 초기화된 값의 개수에 따라 크기가 결정됩니다.
int numbers[] = {1, 2, 3}; // 크기 자동 결정 (3)

배열의 기본 원리와 선언 방식을 정확히 이해하면, 다양한 문제를 효과적으로 해결할 수 있습니다.

배열 인덱싱 최적화


배열 인덱싱은 배열 요소에 접근하는 핵심 방법으로, 성능과 코드 가독성에 큰 영향을 미칩니다. 올바른 인덱싱과 최적화된 접근 방식을 통해 코드 효율을 높일 수 있습니다.

배열 인덱싱의 기본 원리


배열의 첫 번째 요소는 인덱스 0에서 시작하며, 배열 이름은 첫 요소의 메모리 주소를 가리킵니다. 따라서 array[i]는 내부적으로 *(array + i)로 처리됩니다.

int numbers[5] = {10, 20, 30, 40, 50};
printf("%d\n", numbers[2]); // 30 출력

인덱싱 최적화를 위한 팁

  1. 루프 변수 최적화
    배열을 반복 처리할 때, 루프 변수와 배열의 범위를 명확히 정의하여 불필요한 계산을 줄입니다.
   for (size_t i = 0; i < sizeof(numbers) / sizeof(numbers[0]); i++) {
       printf("%d\n", numbers[i]);
   }
  1. 캐시 효율성 고려
    배열은 메모리에 연속적으로 저장되므로, 순차적으로 접근하면 캐시 효율이 향상됩니다.
   // 비효율적인 접근
   for (size_t i = 0; i < N; i++) {
       for (size_t j = 0; j < M; j++) {
           process(array[j][i]); // 열 단위 접근 (캐시 비효율)
       }
   }

   // 효율적인 접근
   for (size_t i = 0; i < M; i++) {
       for (size_t j = 0; j < N; j++) {
           process(array[i][j]); // 행 단위 접근 (캐시 효율)
       }
   }
  1. 계산된 인덱스 사용 최소화
    중복되는 계산은 반복문 외부에서 수행하고 결과를 변수로 저장해 재사용합니다.
   for (size_t i = 0; i < N; i++) {
       size_t offset = i * M;
       for (size_t j = 0; j < M; j++) {
           process(array[offset + j]);
       }
   }

배열 인덱싱 오류 방지

  • 배열 크기를 초과하는 인덱스를 사용하지 않도록 범위를 확인합니다.
  • 배열을 함수로 전달할 때, 크기 정보를 함께 전달합니다.
void printArray(int *array, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%d\n", array[i]);
    }
}

배열 인덱싱의 최적화는 성능 향상뿐만 아니라 코드의 안정성과 유지보수성을 높이는 데에도 중요한 요소입니다.

다차원 배열의 효율적 사용


다차원 배열은 복잡한 데이터 구조를 관리하거나 행렬 연산과 같은 작업에 유용합니다. 다차원 배열을 효율적으로 사용하려면 메모리 접근 패턴과 초기화 방법을 이해하는 것이 중요합니다.

다차원 배열의 선언과 초기화


C언어에서 다차원 배열은 배열 안에 배열이 있는 구조로, 행과 열의 개수를 지정해 선언합니다.

// 2차원 배열 선언 및 초기화
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 일부 초기화 (나머지는 0으로 설정)
int matrix[3][3] = {
    {1, 2},
    {3, 4}
}; // 결과: {{1, 2, 0}, {3, 4, 0}, {0, 0, 0}}

효율적인 메모리 접근


다차원 배열은 메모리에 연속적으로 저장됩니다. 따라서 행 우선 방식(Row-major order)으로 접근하면 캐시 효율성을 높일 수 있습니다.

// 캐시 친화적인 행 우선 접근
for (size_t i = 0; i < 3; i++) {
    for (size_t j = 0; j < 3; j++) {
        process(matrix[i][j]);
    }
}

// 캐시 비효율적인 열 우선 접근
for (size_t j = 0; j < 3; j++) {
    for (size_t i = 0; i < 3; i++) {
        process(matrix[i][j]);
    }
}

다차원 배열을 함수에 전달


다차원 배열을 함수로 전달할 때는 배열 크기를 명시하거나 포인터를 활용해야 합니다.

// 배열 크기 명시
void printMatrix(int matrix[3][3], size_t rows, size_t cols) {
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
}

// 포인터를 사용한 전달
void printMatrixPtr(int *matrix, size_t rows, size_t cols) {
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            printf("%d ", *(matrix + i * cols + j));
        }
        printf("\n");
    }
}

동적 다차원 배열


정적 배열의 크기가 고정적인 단점은 동적 메모리 할당으로 해결할 수 있습니다.

// 동적 2차원 배열 생성
int **matrix = malloc(rows * sizeof(int *));
for (size_t i = 0; i < rows; i++) {
    matrix[i] = malloc(cols * sizeof(int));
}

// 배열 해제
for (size_t i = 0; i < rows; i++) {
    free(matrix[i]);
}
free(matrix);

활용 예: 행렬 덧셈


다차원 배열을 활용한 행렬 덧셈의 예제입니다.

void addMatrices(int a[3][3], int b[3][3], int result[3][3]) {
    for (size_t i = 0; i < 3; i++) {
        for (size_t j = 0; j < 3; j++) {
            result[i][j] = a[i][j] + b[i][j];
        }
    }
}

효율적인 다차원 배열 사용은 복잡한 데이터 구조와 알고리즘을 다룰 때 성능과 이해도를 크게 향상시킵니다.

배열 크기와 동적 할당


배열 크기의 관리와 동적 할당은 C언어 프로그래밍에서 유연성과 메모리 효율성을 극대화하는 데 중요한 역할을 합니다. 고정 크기 배열의 한계를 극복하기 위해 동적 메모리 할당을 활용할 수 있습니다.

배열 크기의 중요성


고정 크기 배열은 크기를 초과할 수 없으므로, 충분한 크기를 미리 설정하거나, 정확한 크기를 동적으로 계산해 사용하는 것이 중요합니다.

// 고정 크기 배열
#define SIZE 10
int fixedArray[SIZE];

동적 배열 선언


malloc과 같은 메모리 할당 함수를 사용해 런타임 시 배열 크기를 동적으로 결정할 수 있습니다.

// 동적 배열 생성
size_t size = 10;
int *dynamicArray = (int *)malloc(size * sizeof(int));

// 동적 배열 사용
for (size_t i = 0; i < size; i++) {
    dynamicArray[i] = i * 10;
}

// 메모리 해제
free(dynamicArray);

크기 재조정


동적 배열은 realloc 함수를 통해 크기를 변경할 수 있습니다.

// 배열 크기 증가
size_t newSize = 20;
dynamicArray = (int *)realloc(dynamicArray, newSize * sizeof(int));

// 추가 공간 초기화
for (size_t i = size; i < newSize; i++) {
    dynamicArray[i] = i * 10;
}

동적 배열 사용 시 주의사항

  1. 메모리 누수 방지
    동적으로 할당된 배열은 사용 후 반드시 free 함수를 사용해 메모리를 해제해야 합니다.
  2. 메모리 초과 방지
    배열 크기를 동적으로 조정할 때, 할당 실패에 대비해 NULL을 확인합니다.
   if (dynamicArray == NULL) {
       perror("Memory allocation failed");
       exit(EXIT_FAILURE);
   }

배열 크기 계산


배열 크기를 관리하는 함수는 프로그램의 가독성과 유지보수성을 높이는 데 유용합니다.

// 동적 배열 크기 설정 함수
int *createArray(size_t size, int initValue) {
    int *array = (int *)malloc(size * sizeof(int));
    if (array != NULL) {
        for (size_t i = 0; i < size; i++) {
            array[i] = initValue;
        }
    }
    return array;
}

활용 예: 평균 계산 프로그램


동적 배열을 활용해 평균을 계산하는 프로그램의 예제입니다.

#include <stdio.h>
#include <stdlib.h>

double calculateAverage(int *array, size_t size) {
    int sum = 0;
    for (size_t i = 0; i < size; i++) {
        sum += array[i];
    }
    return (double)sum / size;
}

int main() {
    size_t size = 5;
    int *array = (int *)malloc(size * sizeof(int));

    for (size_t i = 0; i < size; i++) {
        array[i] = (i + 1) * 10; // {10, 20, 30, 40, 50}
    }

    printf("Average: %.2f\n", calculateAverage(array, size));

    free(array); // 메모리 해제
    return 0;
}

동적 배열을 활용하면 프로그램이 입력 데이터나 환경 변화에 더 잘 적응할 수 있으며, 메모리 사용 효율을 크게 높일 수 있습니다.

포인터와 배열의 관계


C언어에서 배열과 포인터는 밀접하게 연결되어 있으며, 배열 이름은 포인터처럼 작동합니다. 이 관계를 이해하면 배열을 더 유연하고 효율적으로 사용할 수 있습니다.

배열과 포인터의 기본 관계


배열 이름은 배열의 첫 번째 요소를 가리키는 포인터로 취급됩니다.

int array[5] = {10, 20, 30, 40, 50};

// 배열 이름은 첫 번째 요소의 주소
printf("%p\n", array);       // 배열 시작 주소
printf("%p\n", &array[0]);   // 배열 첫 요소의 주소

// 포인터로 배열 접근
int *ptr = array;
printf("%d\n", *(ptr + 2));  // 30 출력

포인터 연산과 배열


포인터 연산을 통해 배열 요소에 접근할 수 있으며, 반복문을 사용해 배열을 처리할 때 자주 활용됩니다.

// 포인터로 배열 순회
int array[5] = {10, 20, 30, 40, 50};
int *ptr = array;

for (size_t i = 0; i < 5; i++) {
    printf("%d\n", *(ptr + i)); // 포인터 연산으로 배열 접근
}

포인터를 사용한 함수 전달


배열을 함수에 전달할 때 배열 이름은 포인터로 전달됩니다. 따라서 배열의 크기를 명시적으로 전달해야 합니다.

void printArray(int *array, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
}

int main() {
    int array[5] = {10, 20, 30, 40, 50};
    printArray(array, 5); // 배열 이름 전달
    return 0;
}

포인터와 다차원 배열


다차원 배열은 포인터의 배열처럼 작동하며, 각 차원에 대한 포인터를 통해 접근할 수 있습니다.

int matrix[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

// 첫 번째 행 접근
int *row = matrix[0];
printf("%d\n", *(row + 1)); // 2 출력

// 행과 열을 포인터로 접근
printf("%d\n", *(*(matrix + 1) + 2)); // 6 출력

배열과 포인터의 차이점

  1. 배열 이름은 상수 포인터
    배열 이름은 첫 요소의 주소를 가리키는 상수 포인터로 변경할 수 없습니다.
   int array[5];
   int *ptr = array;
   ptr++;      // 가능
   array++;    // 오류
  1. 메모리 크기 계산
    배열은 sizeof로 전체 크기를 계산할 수 있지만, 포인터는 포인터 변수 자체의 크기만 반환됩니다.
   int array[5] = {1, 2, 3, 4, 5};
   int *ptr = array;

   printf("%zu\n", sizeof(array)); // 배열 크기 (20 bytes)
   printf("%zu\n", sizeof(ptr));   // 포인터 크기 (8 bytes on 64-bit system)

활용 예: 동적 배열 처리


포인터를 활용해 동적 배열을 처리하는 프로그램입니다.

void reverseArray(int *array, size_t size) {
    for (size_t i = 0; i < size / 2; i++) {
        int temp = array[i];
        array[i] = array[size - 1 - i];
        array[size - 1 - i] = temp;
    }
}

int main() {
    size_t size = 5;
    int *array = (int *)malloc(size * sizeof(int));
    for (size_t i = 0; i < size; i++) {
        array[i] = (i + 1) * 10; // {10, 20, 30, 40, 50}
    }

    reverseArray(array, size);

    for (size_t i = 0; i < size; i++) {
        printf("%d ", array[i]); // {50, 40, 30, 20, 10}
    }

    free(array);
    return 0;
}

배열과 포인터의 관계를 잘 활용하면 더 유연하고 최적화된 코드를 작성할 수 있습니다. 이 관계를 이해하는 것은 C언어 프로그래밍에서 필수적인 기술입니다.

배열 관련 메모리 오류 해결


배열을 사용할 때 메모리 관리와 관련된 오류는 프로그램의 안정성과 성능에 큰 영향을 미칩니다. 이러한 오류를 예방하고 해결하는 방법을 익히는 것이 중요합니다.

배열 관련 주요 메모리 오류

  1. 배열 인덱스 초과 접근
    배열 크기를 초과하여 접근하면 예기치 않은 동작이나 프로그램 충돌이 발생할 수 있습니다.
   int array[5] = {1, 2, 3, 4, 5};
   printf("%d\n", array[6]); // 정의되지 않은 동작 발생
  1. 초기화되지 않은 배열 사용
    배열을 선언한 후 초기화하지 않고 사용하면 쓰레기 값이 저장되어 예상치 못한 결과를 초래할 수 있습니다.
   int array[5];
   printf("%d\n", array[0]); // 쓰레기 값 출력
  1. 메모리 누수
    동적 배열을 할당한 후 free 함수를 호출하지 않으면 메모리 누수가 발생합니다.
   int *array = (int *)malloc(5 * sizeof(int));
   // 배열 사용 후 free를 호출하지 않음
  1. 해제된 메모리 접근
    free된 메모리 주소에 접근하면 정의되지 않은 동작이 발생합니다.
   int *array = (int *)malloc(5 * sizeof(int));
   free(array);
   printf("%d\n", array[0]); // 정의되지 않은 동작

메모리 오류 해결 방법

  1. 배열 크기 확인
    배열 접근 전에 항상 크기를 확인하여 초과 접근을 방지합니다.
   for (size_t i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
       printf("%d\n", array[i]);
   }
  1. 초기화
    배열을 선언한 후 값을 명시적으로 초기화합니다.
   int array[5] = {0}; // 모든 요소를 0으로 초기화
  1. 동적 메모리 관리
    동적 배열을 사용한 후 메모리를 반드시 해제합니다.
   int *array = (int *)malloc(5 * sizeof(int));
   // 사용 후 메모리 해제
   free(array);
  1. 포인터 무효화
    메모리를 해제한 후 포인터를 NULL로 설정하여 재사용을 방지합니다.
   free(array);
   array = NULL; // 포인터 무효화

디버깅 메모리 오류

  1. 배열 크기 초과 탐지
    디버깅 도구(예: Valgrind, AddressSanitizer)를 사용해 메모리 접근 오류를 탐지합니다.
   valgrind --leak-check=full ./program
  1. 로그 출력
    배열 접근 시 로그를 추가해 접근 범위와 값의 유효성을 확인합니다.
   for (size_t i = 0; i < size; i++) {
       printf("Accessing index %zu: %d\n", i, array[i]);
   }
  1. 경계 확인 함수 사용
    안전한 배열 접근을 위해 사용자 정의 함수로 경계를 검사합니다.
   int safeAccess(int *array, size_t index, size_t size) {
       if (index >= size) {
           printf("Index out of bounds: %zu\n", index);
           return -1; // 오류 값 반환
       }
       return array[index];
   }

활용 예: 배열 범위 검사 함수


다음은 배열 범위를 검사하는 함수의 예제입니다.

#include <stdio.h>
#include <stdlib.h>

int safeAccess(int *array, size_t index, size_t size) {
    if (index >= size) {
        printf("Index out of bounds: %zu\n", index);
        return -1; // 오류 값 반환
    }
    return array[index];
}

int main() {
    int array[5] = {10, 20, 30, 40, 50};
    size_t size = sizeof(array) / sizeof(array[0]);

    printf("Element at index 3: %d\n", safeAccess(array, 3, size)); // 40
    printf("Element at index 6: %d\n", safeAccess(array, 6, size)); // 오류 메시지 출력

    return 0;
}

메모리 오류를 예방하고 디버깅 기법을 활용하면 배열을 안전하게 관리할 수 있으며, 안정적인 프로그램을 작성할 수 있습니다.

배열과 함수의 효율적 결합


배열은 함수와 결합하여 데이터 처리의 효율성을 극대화할 수 있습니다. 특히 배열을 함수로 전달하고 데이터를 효율적으로 처리하는 방법은 C언어 프로그래밍에서 중요한 기술입니다.

배열의 함수 전달


C언어에서는 배열을 함수로 전달할 때 배열 이름을 사용하며, 이는 배열의 첫 번째 요소에 대한 포인터로 동작합니다. 함수에 배열을 전달할 때는 크기를 명시적으로 전달해야 합니다.

void printArray(int *array, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
}

int main() {
    int array[5] = {10, 20, 30, 40, 50};
    printArray(array, 5);
    return 0;
}

다차원 배열 전달


다차원 배열은 함수로 전달할 때 배열의 차원 정보를 함께 제공해야 합니다.

void printMatrix(int matrix[2][3], size_t rows, size_t cols) {
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int matrix[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };
    printMatrix(matrix, 2, 3);
    return 0;
}

효율적인 데이터 처리

  1. 포인터를 사용한 배열 처리
    포인터를 사용해 배열을 처리하면 반복문에서 직접적인 메모리 접근이 가능해 효율성이 높아집니다.
   void multiplyByTwo(int *array, size_t size) {
       for (size_t i = 0; i < size; i++) {
           *(array + i) *= 2;
       }
   }
  1. 함수 반환으로 동적 배열 처리
    동적으로 할당된 배열을 함수 반환값으로 사용하면 데이터 처리가 유연해집니다.
   int *createArray(size_t size, int value) {
       int *array = (int *)malloc(size * sizeof(int));
       if (array != NULL) {
           for (size_t i = 0; i < size; i++) {
               array[i] = value;
           }
       }
       return array;
   }

   int main() {
       int *array = createArray(5, 10);
       for (size_t i = 0; i < 5; i++) {
           printf("%d ", array[i]); // 10 출력
       }
       free(array);
       return 0;
   }

매크로를 활용한 배열 처리


매크로를 활용하면 함수 호출 없이 간단히 배열을 처리할 수 있습니다.

#define PRINT_ARRAY(arr, size)          \
    for (size_t i = 0; i < size; i++) { \
        printf("%d ", arr[i]);          \
    }                                   \
    printf("\n");

int main() {
    int array[5] = {10, 20, 30, 40, 50};
    PRINT_ARRAY(array, 5);
    return 0;
}

응용 예: 배열 합계 및 평균 계산


다음은 배열의 합계와 평균을 계산하는 함수입니다.

void calculateSumAndAverage(int *array, size_t size, int *sum, double *average) {
    *sum = 0;
    for (size_t i = 0; i < size; i++) {
        *sum += array[i];
    }
    *average = (double)(*sum) / size;
}

int main() {
    int array[5] = {10, 20, 30, 40, 50};
    int sum = 0;
    double average = 0.0;

    calculateSumAndAverage(array, 5, &sum, &average);

    printf("Sum: %d, Average: %.2f\n", sum, average);
    return 0;
}

장점

  • 데이터 재사용성: 동일한 데이터 구조를 여러 함수에서 재사용 가능
  • 모듈화: 배열 관련 작업을 별도의 함수로 분리해 가독성과 유지보수성 향상
  • 효율적 처리: 포인터를 활용한 배열 접근으로 성능 최적화

배열과 함수를 효율적으로 결합하면 코드의 유연성과 성능이 크게 향상되며, 복잡한 데이터 처리 작업도 간결하게 구현할 수 있습니다.

배열 기반 응용 프로그램 예제


배열은 다양한 응용 프로그램에서 데이터를 저장하고 처리하는 데 핵심적인 역할을 합니다. 다음은 배열을 활용한 실제 응용 예제를 통해 배열 사용의 유용성을 보여줍니다.

예제 1: 학생 점수 통계 프로그램


학생들의 점수를 배열로 저장하고, 총점, 평균, 최고 점수를 계산합니다.

#include <stdio.h>

void calculateStatistics(int *scores, size_t size, int *total, double *average, int *max) {
    *total = 0;
    *max = scores[0];
    for (size_t i = 0; i < size; i++) {
        *total += scores[i];
        if (scores[i] > *max) {
            *max = scores[i];
        }
    }
    *average = (double)(*total) / size;
}

int main() {
    int scores[] = {85, 90, 78, 92, 88};
    size_t size = sizeof(scores) / sizeof(scores[0]);
    int total = 0, max = 0;
    double average = 0.0;

    calculateStatistics(scores, size, &total, &average, &max);

    printf("Total: %d, Average: %.2f, Max: %d\n", total, average, max);
    return 0;
}

출력 예시:

Total: 433, Average: 86.60, Max: 92

예제 2: 버블 정렬 구현


배열을 정렬하는 버블 정렬 알고리즘을 구현합니다.

#include <stdio.h>

void bubbleSort(int *array, size_t size) {
    for (size_t i = 0; i < size - 1; i++) {
        for (size_t j = 0; j < size - 1 - i; j++) {
            if (array[j] > array[j + 1]) {
                int temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
}

int main() {
    int numbers[] = {5, 3, 8, 6, 2};
    size_t size = sizeof(numbers) / sizeof(numbers[0]);

    printf("Before sorting: ");
    for (size_t i = 0; i < size; i++) {
        printf("%d ", numbers[i]);
    }

    bubbleSort(numbers, size);

    printf("\nAfter sorting: ");
    for (size_t i = 0; i < size; i++) {
        printf("%d ", numbers[i]);
    }

    return 0;
}

출력 예시:

Before sorting: 5 3 8 6 2  
After sorting: 2 3 5 6 8

예제 3: 문자열 회문 검사


문자열이 회문인지(앞뒤가 같은지) 검사하는 프로그램입니다.

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool isPalindrome(char *str, size_t size) {
    for (size_t i = 0; i < size / 2; i++) {
        if (str[i] != str[size - 1 - i]) {
            return false;
        }
    }
    return true;
}

int main() {
    char str[] = "madam";
    size_t size = strlen(str);

    if (isPalindrome(str, size)) {
        printf("\"%s\" is a palindrome.\n", str);
    } else {
        printf("\"%s\" is not a palindrome.\n", str);
    }

    return 0;
}

출력 예시:

"madam" is a palindrome.

예제 4: 행렬 곱셈


2차원 배열을 활용해 행렬 곱셈을 수행합니다.

#include <stdio.h>

void multiplyMatrices(int a[2][2], int b[2][2], int result[2][2]) {
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            result[i][j] = 0;
            for (int k = 0; k < 2; k++) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
}

int main() {
    int a[2][2] = {{1, 2}, {3, 4}};
    int b[2][2] = {{5, 6}, {7, 8}};
    int result[2][2];

    multiplyMatrices(a, b, result);

    printf("Resultant matrix:\n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }

    return 0;
}

출력 예시:

Resultant matrix:  
19 22  
43 50

응용 프로그램 요약


이 예제들은 배열을 사용해 데이터를 저장, 처리, 및 정렬하는 다양한 방법을 보여줍니다. 배열을 활용한 프로그램은 효율적이고 간결하며, 다양한 문제를 해결하는 데 핵심적인 도구가 됩니다.

요약


본 기사에서는 C언어에서 배열을 효율적으로 사용하는 다양한 방법과 예제를 살펴보았습니다. 배열의 기본 개념부터 다차원 배열, 동적 배열 관리, 함수와의 결합, 메모리 오류 예방, 그리고 배열을 활용한 실제 응용 프로그램 예제까지 다루며, 배열 활용의 핵심 기술을 익힐 수 있도록 안내했습니다. 배열의 효과적인 사용은 프로그램의 성능과 가독성을 크게 향상시키며, 안정적이고 유지보수 가능한 코드를 작성하는 데 필수적입니다.