CS/자료구조

배열, 구조체, 포인터

Meluu_ 2024. 6. 28. 12:04

✔️ 배열


같은 자료형의 변수들이 연속된 메모리 공간을 차지하는 자료구조

 

인덱스와 인덱스에 대응하는 데이터들로 이루어진 자료구조이다. 

 

int arr[5]; // 배열 선언
arr[0] = 10; // 0번째 인덱스에 접근하여 값을 바꿈, set 연산
int value = arr[0] // 0번째 인덱스에 접근하여 값을 가져옴, get 연산

int arr[] = {1, 2, 3, 4}; // 배열 바로 초기화

 

 

1차원 배열 :  base(주소값) + n * sizeof(자료형) 
2차원 배열 :  base(주소값) + (i * 열의 개수 + j )* sizeof(자료형)       // i : 행,  j : 열

 

이러한 형식으로 실질적인 배열 인덱스에 접근한다.

 

응용 : 행렬 (matrix)

2차원 배열을 이용하여 배열의 전체 요소를 저장하는 방법

장점 : 행렬의 연산들을 간단하게 구현 가능

단점 : 희소 행렬의 경우 많은 메모리 공간 낭비 

 

희소 행렬 : 대부분의 항들이 0인 행렬

 

 

0이 아닌 요소들만 저장하는 방법

장점 : 희소 행렬의 경우, 메모리 공간의 절약

단점 : 각종 행렬 연산들의 구현이 복잡

 

 

✔️ 구조체


하나 이상의 변수를 묶어 그룹화하는 사용자 정의 자료형

  • 동일한 타입의 구조체는 대입이 가능
  • 함수의 매개변수로 전달 할 때 구조체는 그대로 전달하면 복사된다.
    • 그러나 배열은 시작주소만 전달될 뿐이다.

 

// 구조체 선언
struct Friend {
    char name[16];  // 문자배열
    int age;       // 나이 
};

// 구조체 변수 생성
struct Friend friend1; // 바로 값을 초기화 가능

// 값 초기화
strcpy(friend1.name, "길동무");
friendA.age = 12;

 

typedef를 사용하여 구조체의 형식을 정의할 수 있다. 

// 구조체 선언
typedef struct {
    char str[16];
    int age;
} Friend;

// 구조체 변수 생성
Friend friend1 = { "홍길동", 12 };

 

 

 

 

배열과 구조체의 차이점

배열 : 자료형이 같은 데이터들의 묶음

구조체 : 자료형이 다른 데이터들의 묶음

              대입이 가능

 

다음 코드는 초기화된 구조체 Friend를 구현한 friend1에 값을 초기화하고 friend2 에 대입후 friend2에서 age 값을 15로 바꿨을 때 if 조건문에서 True라면 구조체의 참조값을 대입한 것이고, 서로 다르다면 대입시 friend1의 값을 그대로 대입했다고 볼 수 있다. 

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

typedef struct {
    char name[16];
    int age;
} Friend;

int main() {
    Friend friend1 = { "홍길동", 12 };
    Friend friend2 = friend1;

    friend2.age = 15;

    if (strcmp(friend1.name, friend2.name) == 0 && friend1.age == friend2.age) {
        printf("구조체 대입시 참조값을 가진다.\n");
    }
    else {
        printf("구조체 대입시 값이 그대로 대입된다.\n");
    }

    return 0;
}

 

결과 

 

 

✔️ 포인터


다른 변수의 주소를 가지는 변수

 

포인터 연산자 : * 

포인터가 가리키는 내용

char a = 'A'; 
char *p; // char형 포인터

p = &a; // 주소값을 전달

p가 가리키는 a의 주소값

 

❓ 궁금증

p = a; 하면 어떻게 될까 ?

p가 가리키는 a의 실제 값 자체의 주소

포인터는 a변수의 실질적인 값 그 자체를 가리키게 된다. 

a = 'A' 이고 'A'는 메모리에서 41번째에 있다. 즉, 'A'라는 문자 값 자체를 가리키게된 것이다.

 

참고 : 'A' 는 ASCII 에서 65 이지만 메모리 주소는 16진수로 표현되기 때문에 4 x 16^1 + 1x16^0 이므로 65이다.

 

 

 

 

 

배열에서 포인터

배열의 이름이 사실상 포인터와 같은 역할이다

 

int arr[] = { 1,2,3 };
printf("%d\n", *arr);

// 출력결과 
// 1

for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
	printf("%d ", *(arr + i)); 
}

// 출력 결과
// 1 2 3


//sacnf를 사용하여 배열에 값 넣기
scanf_s("%d", &arr[0]);

 

 

✔️ 동적 메모리 할당 / 반납


프로그램 실행 도중 메모리를 할당 받는 것

필요한 만큼 할당받고 필요한 때에 사용하고 반납

메모리를 매우 효율적으로 사용가능

 

동적할당

1. 메모리에서 Heap 영역에 할당한다. 

2. 할당시 포인터를 사용하여 할당한다.

 

// 동적 할당
int *p;
p = (int *)malloc(크기 * sizeof(int));

// 2차원 배열 할당
int *p = calloc(n*m, sizeof(int)); // 1차원 각 요소들
int **pp = malloc(n*sizeof(int)); // 2차원 n행 
for (int i = 0; i < n; i++) {
	pp[i] = p + i*m; // 요소 + i번째 행 * 열크기
    				 // 이 경우 행 x 열을 하면 pp[0] 은 p + 0, pp[1] = 1*m이 된다. 
                     // 즉, 한 배열 열에서 열 개수만큼 잘라서 행을 구성한다.
}

// 반납
free(p);

// 일반화
(자료형 *)malloc(크기 * sizeof(자료형));

 

 

 

 


🔖 참고자료


  • C로 쉽게 풀어쓴 자료구조 - 생능출판사

'CS > 자료구조' 카테고리의 다른 글

연결리스트  (0) 2024.07.09
큐(queue)와 덱(deque)  (0) 2024.07.02
스택 (Stack)  (0) 2024.07.01
순환  (0) 2024.01.26
자료구조의 정의  (0) 2024.01.26