Skip to content

[필기] 11주차 수업 (25.05.26)

syunlei edited this page Jun 8, 2025 · 9 revisions

ver.1

1. 복습

아래 코드들의 결과값은 모두 동일

  • heep 변수 앞에 형식변환 연산자
# include <stdio.h>
# include <stdlib.h>
int main()
{
	int* pa = NULL; //Stack
	double* pb = NULL;

	pa = (int*)malloc(sizeof(int)); //Heep, *pa
	pb = (double*)malloc(sizeof(double)); //*pd
        //변수 4개
	//(int*), (double*): 형식변환 연산자, 해당 형식의 주소로 사용을 선언

	*pa = 10;
	*pb = 3.14;

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

	free(pa);
	free(pb);
}
  • Alloc
# include <stdio.h>
# include <stdlib.h>
int* AllocInt()
{
	return (int*)malloc(sizeof(int));
}
double* AllocDouble()
{
	return (double*)malloc(sizeof(double));
}
int main()
{
	int* pa = NULL; 
	double* pb = NULL;

	pa = AllocInt(); //함수가 끝나면 정수형 주소가 있어야 함
	pb = AllocDouble();
   
	*pa = 10;
	*pb = 3.14;

	printf("int : %d\n", *pa);
	printf("double : %g\n", *pb);
	
	free(pa);
	free(pb);
}
  • Set
# include <stdio.h>
# include <stdlib.h>

int* AllocInt()
{
	return (int*)malloc(sizeof(int));
}
double* AllocDouble()
{
	return (double*)malloc(sizeof(double));
}
void SetInt(int* p, int data)
{
	*p = data;
}
void SetDouble(double* p, double data)
{
	*p = data;
}
void PrintInt(int data)
{
	printf("int : %d\n", data);
}
void PrintDouble(double data)
{
	printf("double : %g\n", data);
}
void FreeInt(int* p)
{
	free(p);
}
void FreeDouble(double* p)
{
	free(p);
}
int main()
{
	int* pa = NULL; 
	double* pb = NULL;

	pa = AllocInt(); 
	pb = AllocDouble(); 
//생성
   
	SetInt(pa, 10); //*pa = 10;와 동일한 코드
	SetDouble(pb, 3.14); //*pb = 3.14;와 동일한 코드
//읽기, 변경

	PrintInt(*pa);
	PrintDouble(*pb);
//출력
	
	FreeInt(pa); 
	FreeDouble(pb); 
//제거
}

2. 코드의 순서 CRUD

Create: 생성
Read: 읽기
Update: 변경
Delete: 제거

3. 코드를 분리

관련성 있는 코드끼리 분리해서 코드 활용이 편리해짐

  • 파일 분리

프로젝트 추가: 솔루션 우클 > 추가 > 새 프로젝트
현재 실행 프로젝트 설정: 프로젝트 우클 > 시작 프로젝트로 설정(볼드처리)
헤더파일: .h / 소스파일: .cpp

1) Int.h

int 함수의 시그니처 정보

#pragma once
int* AllocInt();
void SetInt(int* p, int data);
void PrintInt(int data);
void FreeInt(int* p);

2) Int.cpp

int 함수의 정의 정보

#include <stdio.h> //printf
#include <stdlib.h> //malloc

int* AllocInt()
{
	return (int*)malloc(sizeof(int));
}
void SetInt(int* p, int data)
{
	*p = data;
}
void PrintInt(int data)
{
	printf("int : %d\n", data);
}
void FreeInt(int* p)
{
	free(p);
}

3) Double.h

double 함수의 시그니처 정보

#pragma once
double* AllocDouble();
void SetDouble(double* p, double data);
void PrintDouble(double data);
void FreeDouble(double* p);

4) Double.cpp

double 함수의 정의 정보

# include <stdio.h> //printf
# include <stdlib.h> //malloc

double* AllocDouble()
{
	return (double*)malloc(sizeof(double));
}
void SetDouble(double* p, double data)
{
	*p = data;
}
void PrintDouble(double data)
{
	printf("double : %g\n", data);
}
void FreeDouble(double* p)
{
	free(p);
}

5) Main.cpp

#include "Int.h"
#include "Double.h"

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

	pa = AllocInt();
	pb = AllocDouble();

	SetInt(pa, 10); 
	SetDouble(pb, 3.14); 

	PrintInt(*pa);
	PrintDouble(*pb);

	FreeInt(pa);
	FreeDouble(pb);
}

4. 라이브러리 함수를 사용자 함수로 변경

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

int main()
{
	int* pa = (int*)malloc(sizeof(int) * 10);

	for (int i = 0; i < 10; ++i)
		pa[i] = i + 1;
	for (int i = 0; i < 10; ++i)
		printf("data : %d\n", pa[i]);
	free(pa);
}

** 아래 동일**

#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int** pp, int capacity) 
{
	*pp = (int*)malloc(sizeof(int) * capacity);
}
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]);
}
void FreeIntArray(int* pa)
{
	free(pa);
}
int main()
{
	int* pa = 0;

	AllocIntArray(&pa, 10);
	InitIntArray(pa, 10);
	PrintIntArray(pa, 10);
	FreeIntArray(pa)
}
#include <stdio.h>
#include <stdlib.h>

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

	p = &b;

	printf("data : %d\n", *p);
}

** 아래 동일**

#include <stdio.h>
#include <stdlib.h>
void AssignAddress(int** pp, int* pdata)
{
	*pp = pdata;
}
int main()
{
	int a = 10;
	int b = 20;
	int* p = NULL;

	AssignAddress(&p, &b);

	printf("data : %d\n", *p);
}

5. 변수의 주소(*)

  • typedef

이름을 변경하는 함수

#include <stdio.h>
#include <stdlib.h>
typedef int I;
typedef int* PI;

void AssignAddress(PI* pp, I* pdata)
{
	*pp = pdata;
}
int main()
{
	I a = 10;
	I b = 20;
	PI p = NULL;

	AssignAddress(&p, &b);

	printf("data : %d\n", *p);
}

6. 구조체

멤버 2개 이상의 데이터를 명명하기 위해 사용

  • struct
#include <stdio.h>
struct Point
{
	int x; 
	int y;
	//멤버 변수라고 명칭
};
int main()
{
	int n = 10; //4Bite
	Point pt = { 2,3 }; //8Bite
	//2=pt.x, 3=pt.y

	printf("%d\n", n);
	printf("(%d,%d)\n", pt.x,pt.y);
}
#include <stdio.h>
struct Point
{
	int x; 
	int y;
};
int main()
{
	Point pt = { 2,3 }; 

	printf("(%d,%d)\n", pt.x,pt.y);

	printf("%p &p\n", &pt, &pt+1);
	printf("%p &p\n", &pt.x, &pt.x+1);

	Point* p1 = &pt;
	int* p2 = &pt.x;
}
  • ->
#include <stdio.h>
struct Point
{
	int x; 
	int y;
};
int main()
{
	Point pt = { 2,3 }; 
	Point* p = &pt;

	printf("(%d, %d)\n", pt.x, pt.y);
	printf("(%d, %d)\n", p->x, p->y);

}
  • 사용자 함수 사용
#include <stdio.h>
struct Point
{
	int x; 
	int y;
};
void PrintPoint(Point* p)
{
	printf("(%d, %d)\n", p->x, p->y);
}
int main()
{
	Point pt = { 2,3 }; 
        Point pt2 = { -1,3 };

	PrintPoint(&pt); //함수는 주소로만 참조
        PrintPoint(&pt2);
}

ver.2

1. 복습

프로그래밍은 명령어와 데이터로 나눠지고 데이터는 글로벌 스택 힙으로 나눠진다. 힙 메모리가 제일 큰 용량을 차지한다.

#include <stdio.h>
int main()
{
	int* pa = NULL;
	double* pb = NULL;

이 코드에서 pa와 pb는 stack 메모리에 저장된다.

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//stack
	int* pa = NULL;
	double* pb = NULL;

	//heap 생성 malloc
	pa = (int*)malloc(sizeof(int)); //*pa
	pb = (double*)malloc(sizeof(double)); //*pb

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

	free(pa);
	free(pb); //heap을 종료하기 위해서 free에 pa와 pb 주소를 입력
}

heap메모리에 저장하기 위해서는 #include <stdlib.h>와 메멀락, 프리가 필요하다. (int*),(double*)는 int형, double형 주소를 사용하겠다는 의미. main.cpp를 변경할 필요 없다.

2. CRUD

Create 생성 Read 읽기 Update 변경 Delete 제거

#include <stdio.h>
#include <stdlib.h>
//int, double형 메모리 생성
int* AllocInt()
{
	return (int*)malloc(sizeof(int));
}
double* AllocDouble()
{
	return (double*)malloc(sizeof(double));

}
void SetInt(int* p, int data)
{
	*p = data;
}
void SetDouble(double* p, double data)
{
	*p = data;
}
void PrintInt(int data)
{
	printf("int : %d\n", data);
}
void PrintdDouble(double data)
{
	printf("double : %g\n", data);
}
void FreeInt(int* p)//정수의 주소
{
	free(p);
}
void FreeDouble(double* p)//정수의 주소
{
	free(p);
}
int main()
{
	int* pa = NULL;
	double* pb = NULL;

	//메모리 생성 함수, C
	pa = AllocInt();//정수형 주소 반환 필요
	pb = AllocDouble();//실수형 주소 반환 필요

        //R
	SetInt(pa, 10);//*pa = 10
	SetDouble(pb, 3.14);//*pb = 3.14

        //U
	PrintInt(*pa);
	PrintdDouble(*pb);

        //D
	FreeInt(pa);
	FreeDouble(pb);
}

라이브러리 함수를 전부 사용자 함수로 변경

솔루션 -> 마우스 오른쪽 -> 추가, 새프로젝트 -> 솔루션 안에 프로젝트가 2개 됨 -> 프로젝트 이름에 우클릭 -> 시작 프로젝트로 지정을 누르면 먼저 실행하는 프로젝트로 지정됨

관련성 있는 코드끼리 모으려고 헤더와 cpp를 분리함

헤더 파일에 Int.h, Double.h 파일을 만듦
소스 파일에 Int.cpp, Double.cpp, Main.cpp를 만듦
헤더 파일에는 각각 Int, Double의 시그니처만 남기고 바디는 다 삭제
소스 파일에는 #include <stdio.h>, #include <stdlib.h>를 작성, 각각 Int, Double 코드만 남기고 다 삭제
Main 소스 파일에는 #include "Int.h", #include "Double.h"를 작성해서 헤더 파일을 불러옴
>>그럼 위에서 모여있던 코드와 동일한 결과 값이 실행됨

image

#pragma once
//시그니처만 남기고 바디는 다 삭제, 인트형 헤더가 됨
int* AllocInt();
void SetInt(int* p, int data);
void PrintInt(int data);
void FreeInt(int* p);

Int.h

#pragma once
//더블형 헤더
double* AllocDouble();
void SetDouble(double* p, double data);
void PrintdDouble(double data);
void FreeDouble(double* p);

Double.h

#include <stdio.h> //함수 선언, 헤더 파일 불러옴 / printf
#include <stdlib.h>// malloc
int* AllocInt()
{
	return (int*)malloc(sizeof(int));
}
void SetInt(int* p, int data)
{
	*p = data;
}
void PrintInt(int data)
{
	printf("int : %d\n", data);
}
void FreeInt(int* p)
{
	free(p);
}

Int.cpp

#include <stdio.h> // printf
#include <stdlib.h>// malloc
//cpp에는 함수의 정의가 있어야해서 바디를 남김
double* AllocDouble()
{
	return (double*)malloc(sizeof(double));

}
void SetDouble(double* p, double data)
{
	*p = data;
}
void PrintdDouble(double data)
{
	printf("double : %g\n", data);
}
void FreeDouble(double* p)//정수의 주소
{
	free(p);
}

Double.cpp

#include "Int.h"
#include "Double.h"
int main()
{
	int* pa = 0;
	double* pb = 0;//NULL=0

	pa = AllocInt();
	pb = AllocDouble();

	SetInt(pa, 10);
	SetDouble(pb, 3.14);

	PrintInt(*pa);
	PrintdDouble(*pb);

	FreeInt(pa);
	FreeDouble(pb);
}

Main.cpp

3. 포인터 변수 아웃 파라미터로 변형

#include <stdio.h>
#include <stdlib.h>
int* AllocIntArray(int capacity)//갯수만큼의 주소를 반환
{
	return (int*)malloc(sizeof(int) * capacity);
}
void InitIntArray(int* pa, int size)
{
	for (int i = 0; i < 10; ++i)
		pa[i] = i + 1;

}
void PrintIntArray(int* pa, int size)
{
	for (int i = 0; i < 10; ++i)
		printf("data : %d\n", pa[i]);
}
void FreeIntArray(int* pa)
{
	free(pa);
}
int main()
{
	int* pa = AllocIntArray(10);
	InitIntArray(pa, 10);
	PrintIntArray(pa, 10);
	FreeIntArray(pa);
}
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int** pp, int capacity)//갯수만큼의 주소를 반환
{
	return (int*)malloc(sizeof(int) * capacity);
}
void InitIntArray(int* pa, int size)
{
	for (int i = 0; i < 10; ++i)
		pa[i] = i + 1;

}
void PrintIntArray(int* pa, int size)
{
	for (int i = 0; i < 10; ++i)
		printf("data : %d\n", pa[i]);
}
void FreeIntArray(int* pa)
{
	free(pa);
}
int main()
{
	AllocIntArray(&pa, 10);
	InitIntArray(pa, 10);
	PrintIntArray(pa, 10);
	FreeIntArray(pa);
}

리턴으로 받았던 pa의 주소를 리턴 하지 않고 pa의 주소를 바로 넘겨서 받는 코드로 변경 그래서 pa의 주소를 넘기기 위한 &pa 추가 int** pp에 이 메모리를 담으면 됨

지피티에게 인트형식 포인터 변수를 아파라미터로 변경하는 방법

4. 아웃파라미터 변환 복습

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a = 10;
	int b = 20;
	int* p = NULL;

	//p = &a;
	p = &b;

	printf("data : %d\n", *p);
}
#include <stdio.h>
#include <stdlib.h>
void AssignAddress(int** pp, int* pdata)
{
	*pp = pdata;
}
int main()
{
	int a = 10;
	int b = 20;
	int* p = NULL;

	//p = &a;
	//p = &b;
	AssignAddress(&p, &b);

	printf("data : %d\n", *p);
}

이전 코드를 함수로 만듦, 리턴 타입 사용 안함

#include <stdio.h>
#include <stdlib.h>
typedef int I;
typedef int* PI; //타입을 정의함, 이름을 짓는것임
void AssignAddress(PI* pp, I* pdata)
{
	*pp = pdata;
}
int main()
{
	I a = 10;
	I b = 20;
	PI p = NULL;

	//p = &a;
	//p = &b;
	AssignAddress(&p, &b);

	printf("data : %d\n", *p);
}

5. 구조체(struct)

#include <stdio.h>
struct Point
{
	//멤버 변수라고 함
	int x;
	int y;
};
int main()
{
	int n = 10;
	Point pt = { 2, 3 };//순서대로 점을 표현하는 형식, 변수, 값
	//n은 4B, Point는 8B(int x + int y)

	printf("%d\n", n);
	printf("(%d, %d)\n", pt.x, pt.y);
}

구조체 메모리의 이름은 .연산자를 사용해서 이름 참조가 가능

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	int n = 10;
	Point pt = { 2, 3 };
	

	printf("%d\n", n);
	printf("(%d, %d)\n", pt.x, pt.y);

	printf("%p %p\n", &pt, &pt+1);
	printf("%p %p\n", &pt.x, &pt.x+1);

	Point* p1 = &pt; //전체 포인트의 주소
	int* p2 = &pt.x; //인트의 주소
}
#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	int n = 10;
	Point pt = { 2, 3 };
	Point* p = &pt;

	printf("(%d, %d)\n", pt.x, pt.y);
	printf("(%d, %d)\n", p->x, p->y);

}
#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	int n = 10;
	Point pt = { 2, 3 };
	Point* p = &pt;

	printf("(%d, %d)\n", pt.x, &pt.y);
	printf("(%d, %d)\n", (*p).x, p->y);
	//.보다 연산자 우선순위가 높은()를 붙임

}

화살표 연산자를 이용해서 주소를 참조 사본 출력(구조체가 값을 복사해서)

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
void PrintPoint(Point pt)
{
	print("(%d %d)\n", pt.x, pt.y);
}
int main()
{
	Point pt = { 2, 3 };

	PrintPoint(pt);

}

일반적으로 PrintPoint(pt); 같은 형식으로 명령을 내림, 코드 용이, 확장성 등의 관점에서 훨씬 용이하기 때문 원본 출력(인수를 불러와서 값을 도출해서)

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
void PrintPoint(Point pt)
{
	printf("(%d %d)\n", pt.x, pt.y);
}
int main()
{
	Point pt = { 2, 3 };
	Point pt2 = { -1, 3 };

	PrintPoint(pt);
	PrintPoint(pt2);

}

구조체는 멤버 2개 이상의 데이터를 명명하기 위해 사용 멤버는 사이즈가 큼 구조체는 항상 값이 아닌 주소를 전달함

과제 - 포인트를 이용해서 두 점을 정하고 교점을 출력하기

Clone this wiki locally