250526 공부 노트 - Hwanghyewon06/c- GitHub Wiki

당신이 공부한 struct, 포인터, 메모리 구조, 그리고 함수 전달 방식에 대한 내용을 정리해서 설명

📌 1. 구조체(struct)의 기본

struct Point {
    int x;
    int y;
};
  • Point 구조체는 int형 멤버 x, y를 가짐.
  • 각각 4바이트이므로 Point 구조체 하나는 8바이트를 차지함.

📌 2. 구조체를 함수에 포인터로 전달

void PrintPoint(Point* p) {
    printf("(%d, %d)\n", p->x, p->y);
}
  • Point 구조체의 주소를 전달하여 복사 없이 직접 접근 가능.
  • -> 연산자는 포인터가 가리키는 구조체의 멤버에 접근할 때 사용.
  • 효율적인 방법 (대용량 구조체일 때 유리).

📌 3. 구조체를 함수에 값으로 전달

void PrintPoint(Point pt) {
    printf("(%d, %d)\n", pt.x, pt.y);
}
  • 구조체 전체가 복사되어 전달됨.
  • 포인터보다 메모리 사용량이 더 많고, 성능 측면에서 불리할 수 있음 (작은 구조체는 괜찮음).

📌 4. 포인터로 구조체 멤버 접근

Point* p = &pt;
(*p).x;   // 또는 p->x;
  • *p.x는 문법적으로 잘못됨. . 연산자의 우선순위가 *보다 높기 때문.
  • 올바른 표현: (*p).x 또는 p->x

📌 5. 구조체 변수와 주소 출력

printf("%p %p\n", &pt, &pt + 1);
  • &pt는 구조체 전체의 주소, &pt + 1은 그 다음 구조체 주소 (즉, 8바이트 차이).
  • &pt.x&pt.x + 1은 int형 기준으로 4바이트 차이.

📌 6. 메모리 크기 확인 관련 설명

Point pt = {2, 3};
  • 구조체 pt의 크기는 int x(4) + int y(4) = 8바이트
  • 구조체는 연속된 메모리 공간에 저장되며 멤버들은 순서대로 배치됨.
  • pt.x, pt.y 각각은 해당 구조체 내에서 이름으로 접근됨.

✍️ 총정리

항목 설명
구조체 정의 struct 키워드로 사용자 정의 데이터 타입 생성
멤버 접근 변수일 때: pt.x / 포인터일 때: p->x 또는 (*p).x
함수 전달 방식 포인터 전달(주소): 효율적, 원본 직접 접근 / 값 전달: 복사됨
메모리 크기 각 멤버의 크기 합 (여기서는 4 + 4 = 8바이트)
포인터 연산 *p.x는 오류 → (*p).x 또는 p->x 사용
주소 출력 구조체 단위, 멤버 단위로 주소 확인 가능

네! 이해했습니다. 주어진 코드들을 쪼개서 핵심 개념 위주로 깔끔하게 정리해드릴게요.


1. 헤더 파일 포함과 타입 별칭

#include <stdio.h>
#include <stdlib.h>
typedef int I;
typedef int* PI;
  • #include <stdio.h>: 입출력 함수(printf, scanf) 사용 가능하게 함
  • #include <stdlib.h>: 동적 메모리 함수(malloc, free) 사용 가능하게 함
  • typedef int I;: intI라는 이름으로 별칭 생성 → 코드 간결화
  • typedef int* PI;: int*PI라는 이름으로 별칭 생성 → 포인터 표현 간단히

2. 함수에서 포인터를 이중 포인터로 받아 메모리 주소 할당하기

void AssignAddress(PI* pp, I* pdata)
{
	*pp = pdata;
}
  • PI* ppint** pp와 동일.
  • AssignAddress는 포인터 변수 p의 주소를 받아서 p가 가리키는 값을 pdata(즉, 변수 주소)로 설정함.
  • 이렇게 하면 main에서 포인터 변수의 값을 변경할 수 있음 (call by reference 역할).

3. 포인터 주소 전달 방식 예제

int main()
{
	I a = 10;
	I b = 20;
	PI p = NULL;

	AssignAddress(&p, &b);

	printf("data : %d\n", *p);
}
  • I a, bint a, b와 같음
  • PI pint* p
  • AssignAddress(&p, &b);p 포인터 변수의 주소를 넘겨서 pb의 주소를 가리키도록 함
  • 출력은 *pb의 값인 20 출력됨

4. 이중 포인터로 직접 할당하는 함수 예제

void AllocIntArray(int** pp, int capacity)
{
	*pp = (int*)malloc(sizeof(int) * capacity);
}
  • 함수 파라미터 int** ppint* 포인터 변수의 주소
  • *pp = malloc(...) 을 통해 실제 포인터 변수에 동적 할당 주소를 저장
  • main에서 포인터 변수를 넘길 때는 &pa 형태로 주소를 넘겨야 함

5. 배열 초기화 및 출력 함수 예제

void InitIntArray(int* pa, int size)
{
	for (int i = 0; i < size; ++i)
		pa[i] = i + 1;
}
void PrintIntArray(int* pa, int size)
{
	for (int i = 0; i < size; ++i)
		printf("data : %d\n", pa[i]);
}
  • paint 배열의 시작 주소
  • 배열 요소를 순회하면서 값 초기화 및 출력 수행

6. 동적 배열 할당부터 해제까지 완성형 예제

int main()
{
	int* pa = 0;
	
	AllocIntArray(&pa, 10);
	InitIntArray(pa, 10);
	PrintIntArray(pa, 10);
	free(pa);
}
  • AllocIntArray에서 포인터 변수 pa의 주소를 넘겨서 동적 메모리 할당
  • 할당된 메모리에 값 초기화 및 출력 수행
  • 사용 후 free(pa);로 메모리 해제

7. 포인터 변수에 직접 주소 할당 후 출력

int main()
{
	int a = 10;
	int b = 20;
	int* p = NULL;

	p = &b;

	printf("data : %d\n", *p);
}
  • p에 변수 b의 주소 직접 대입
  • *p를 통해 b의 값 20 출력

정리표

개념 설명 코드 예시
헤더 포함 표준 입출력, 동적 메모리 함수 사용 #include <stdio.h> #include <stdlib.h>
typedef 별칭 타입 이름을 간단하게 별칭 생성 typedef int I; typedef int* PI;
이중 포인터 함수 전달 포인터 변수 주소를 넘겨 내부에서 포인터 값 변경 가능 void AssignAddress(PI* pp, I* pdata)
동적 메모리 할당 이중 포인터 받아 malloc한 주소를 포인터 변수에 저장 void AllocIntArray(int** pp, int capacity)
배열 초기화 및 출력 포인터로 배열 접근하여 값 세팅 및 출력 InitIntArray, PrintIntArray 함수
메모리 해제 사용한 동적 메모리는 반드시 free로 해제해야 함 free(pa);
포인터 직접 주소 대입 포인터 변수에 변수 주소 직접 저장 후 접근 가능 p = &b; printf("%d", *p);

네! 주어진 여러 코드들을 쪼개서 핵심 개념별로 깔끔하게 정리해드리겠습니다. 아래 내용은 동적 메모리 할당, 포인터 사용, 함수 분리, CRUD 개념 위주로 단계별 설명입니다.


1. 헤더 파일 포함

#include <stdio.h>
#include <stdlib.h>
  • stdio.h : 입출력 함수(printf, scanf) 사용 가능
  • stdlib.h: 동적 메모리 함수(malloc, free) 사용 가능

2. 동적 메모리 할당 함수들

int* AllocInt()
{
    return (int*)malloc(sizeof(int));
}

double* AllocDouble()
{
    return (double*)malloc(sizeof(double));
}
  • malloc으로 int, double 크기만큼 메모리 동적 할당
  • (int*) , (double*) 캐스팅은 C 스타일 타입 변환 (필수는 아님, C++은 권장)
  • 반환값은 각각 int*, double*

3. 값 저장 함수

void SetInt(int* p, int data)
{
    *p = data;
}

void SetDouble(double* p, double data)
{
    *p = data;
}
  • 포인터 p가 가리키는 주소에 데이터 저장 (*p = data)
  • 외부에서 값을 직접 저장하지 않고 함수로 캡슐화

4. 값 출력 함수

void PrintInt(int data)
{
    printf("int :%d\n", data);
}

void PrintDouble(double data)
{
    printf("double :%g\n", data);
}
  • 직접 값(int, double)을 받아 출력
  • 포인터가 아니라 값을 받는 이유: 출력 시 값 복사만 하면 됨

5. 메모리 해제 함수

void FreeInt(int* p)
{
    free(p);
}

void FreeDouble(double* p)
{
    free(p);
}
  • 할당된 메모리 해제
  • 메모리 누수 방지를 위해 malloc 후 반드시 호출해야 함

6. CRUD 작업 흐름이 담긴 main 함수 예제

int main()
{
    int* pa = NULL;
    double* pb = NULL;

    // Create: 동적 메모리 할당
    pa = AllocInt();
    pb = AllocDouble();

    // Update: 값 저장
    SetInt(pa, 10);
    SetDouble(pb, 3.14);

    // Read: 출력
    PrintInt(*pa);
    PrintDouble(*pb);

    // Delete: 메모리 해제
    FreeInt(pa);
    FreeDouble(pb);

    return 0;
}
  • 포인터 변수 pa, pb 선언 후 NULL 초기화
  • 할당, 값 저장, 출력, 해제 단계를 함수 호출로 분리하여 명확하게 관리
  • *pa, *pb는 실제 값에 접근할 때 사용

7. 동적 메모리 할당과 직접 사용 예 (함수 없이)

int main()
{
    int* pa = (int*)malloc(sizeof(int));
    double* pb = (double*)malloc(sizeof(double));

    *pa = 10;
    *pb = 3.14;

    printf("int :%d\n", *pa);
    printf("double :%g\n", *pb);

    free(pa);
    free(pb);

    return 0;
}
  • mallocfree 직접 사용
  • 동적 메모리 할당 시, 항상 free 호출 필요
  • 함수로 분리하지 않아 코드가 간결하지만, 재사용성과 가독성은 떨어짐

요약 정리

기능 구현 방법 및 특징 코드 핵심
동적 메모리 할당 malloc으로 크기만큼 메모리 확보, 포인터 반환 int* pa = (int*)malloc(sizeof(int));
값 저장 포인터로 주소를 받아 *p = data로 값 저장 SetInt(int* p, int data)
값 출력 값을 복사받아 출력 PrintInt(int data)
메모리 해제 할당된 메모리는 반드시 free 호출 FreeInt(int* p)
함수 분리 기능별 함수 분리하여 코드 관리 용이 AllocInt(), SetInt(), 등
포인터 직접 사용 함수 없이 동적 할당, 직접 포인터 조작 가능 *pa = 10; printf("%d", *pa);

⚠️ **GitHub.com Fallback** ⚠️