๐Ÿ“˜17์žฅ Advanced Uses of Pointers | Study

ํŒŒ์ธยท2022๋…„ 2์›” 3์ผ
0

C

๋ชฉ๋ก ๋ณด๊ธฐ
9/9
post-thumbnail

C Programming, A Modern Approach - K.N.KING์œผ๋กœ C์–ธ์–ด๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.



17.1 Dynamic Storage Allocation
17.2 Dynamic Allocated Strings
17.3 Dynamic Allocated Arrays
17.4 Deallocating Storage
17.5 Linked Lists
17.6 Pointers to Pointers
17.7 Pointers to Functions



๐Ÿ“ Dynamic Storage Allocation (๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น)

๊ณ ์ •๋œ ์‚ฌ์ด์ฆˆ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•  ๊ฒฝ์šฐ ํ”„๋กœ๊ทธ๋žจ์„ ์ˆ˜์ •ํ•˜๊ณ , ๋‹ค์‹œ ์ปดํŒŒ์ผํ•˜์ง€ ์•Š๊ณ ๋Š” size๋ฅผ ๋ณ€๊ฒฝํ• ์ˆ˜๊ฐ€ ์—†๋‹ค.

๋”ฐ๋ผ์„œ C๋Š” ๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น(Dynamic Storage Allocation) ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ์‹คํ–‰ ์‹œ๊ฐ„๋™์•ˆ ์‚ฌ์šฉํ•  ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ํ• ๋‹น๋ฐ›๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.



๐Ÿ“Œ Memory Allocation Functions (๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•จ์ˆ˜๋“ค)

๐Ÿ”Ž ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•จ์ˆ˜๋“ค

  • malloc : ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›๊ณ , ์ดˆ๊ธฐํ™”๋Š” ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • calloc : ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›๊ณ , 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  • realloc : malloc์ด๋‚˜ calloc์œผ๋กœ ํ• ๋‹น๋ฐ›๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

๋ณดํ†ต malloc์ด ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ธ๋‹ค.

์–ด๋–ค ํƒ€์ž…์ด ํ• ๋‹น๋ ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋Š” void* ํ˜•์‹์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. void*์€ ์–ด๋–ค ํƒ€์ž…์œผ๋กœ๋„ ๋ณ€์‹ ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.



๐Ÿ“Œ Null Pointers (๋„ ํฌ์ธํ„ฐ)

๋™์  ํ• ๋‹น ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ๊ทธ๋งŒํผ ์ถฉ๋ถ„ํ•œ ๊ณต๊ฐ„์ด ๋‚จ์•„์žˆ์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ๊ทธ๋Ÿผ ํ•จ์ˆ˜๋Š” null pointer๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
null pointer๋Š” ์•„๋ฌด๊ฒƒ๋„ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š๋Š” ํฌ์ธํ„ฐ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ํฌ์ธํ„ฐ ๋ณ€์ˆ˜์— ์ €์žฅํ•œ ํ›„์— ๋ฐ˜๋“œ์‹œ null pointer์ธ์ง€ ๊ฒ€์‚ฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

null pointer๋Š” ๋งคํฌ๋กœ์— ์˜ํ•ด NULL๋กœ ์„ ์–ธ๋˜์–ด์žˆ๋‹ค. ๋ณดํ†ต #include <stdlib.h>๋ฅผ ์ด์šฉํ•œ๋‹ค.
๋”ฐ๋ผ์„œ malloc์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

p = malloc(10000);
if (p == NULL) { 
	/* allocation failed */
}

p == NULL์ด๋ผ๊ณ  ์“ฐ๋Š” ๋Œ€์‹ 
if (!p) ... ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.




๐Ÿ“ Dynamic Allocated Strings

(๋™์  ํ• ๋‹น๋œ ๋ฌธ์ž์—ด)



๐Ÿ“Œ Using malloc to Allocate Memoery for a String (malloc์œผ๋กœ ๋ฌธ์ž์—ด ํ•จ์ˆ˜์— ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹นํ•˜๊ธฐ)

๐Ÿ”Ž malloc ํ•จ์ˆ˜

void *malloc(size_t size); 

malloc์€ size๋งŒํผ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

char์˜ size๋Š” 1์ด๊ธฐ ๋•Œ๋ฌธ์— malloc์„ ์ด์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด ํ•จ์ˆ˜์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ๋‹ค.

๐Ÿ”Ž ๋ฌธ์ž์—ด ํ•จ์ˆ˜์— n๊ฐœ์˜ ๋ฌธ์ž๋ฅผ ์ €์žฅํ•  ๊ณต๊ฐ„ ํ• ๋‹นํ•˜๊ธฐ

p = malloc(n+1);

๊ทธ๋Ÿผ ํ• ๋‹น์„ ํ•  ๋•Œ p๋Š” char* ์ด ๋œ๋‹ค.



๐Ÿ“Œ Using Dynamic Storage Allocation in String Functions (๋ฌธ์ž์—ด ํ•จ์ˆ˜์—์„œ ๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹นํ•˜๊ธฐ)

๋‘ ๋ฌธ์ž์—ด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ๋‘˜๋‹ค ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ๋ฌธ์ž์—ด์„ ํ•ฉ์ณ๋ณด์ž.
๊ทธ๋Ÿฌ๋ ค๋ฉด ๋จผ์ € ๋‘ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ ์ธก์ •ํ•œ ๋‹ค์Œ malloc์„ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค.
๊ทธ ๋‹ค์Œ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž์—ด์„ ์ƒˆ ๊ณต๊ฐ„์— ๋ณต์‚ฌํ•œ๋‹ค์Œ strcat์„ ํ˜ธ์ถœํ•˜์—ฌ ๋‘๋ฒˆ์งธ ๋ฌธ์ž์—ด์„ ์—ฐ๊ฒฐํ•œ๋‹ค.

๐Ÿ”Ž malloc์„ ์ด์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด ํ•ฉ์น˜๊ธฐ

char* concat(const char* s1, const char* s2)
{
	char* result;

	result = malloc(strlen(s1) + strlen(s2) + 1);
	if (result == NULL) {
		printf("Error : malloc failed in concat\n");
		exit(EXIT_FAILURE);
	}
	strcpy(result, s1);
	strcat(result, s2);
	return result; 
}


๐Ÿ“Œ Arrays of Dynamically Allocated Strings (๋™์  ํ• ๋‹น ๋ฌธ์ž์—ด์˜ ๋ฐฐ์—ด)

์•ž์„œ ๋ฌธ์ž์—ด์„ 2์ฐจ์› ๋ฐฐ์—ด์— ์ €์žฅํ•˜๋ฉด ๊ณต๊ฐ„์ด ๋‚ญ๋น„๋œ๋‹ค๋Š” ๋ฌธ์ œ๋กœ ์ธํ•ด, ๋ฌธ์ž์—ด์„ ํฌ์ธํ„ฐ๋กœ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฐฐ์—ด์„ ์ด์šฉํ•˜์˜€๋‹ค. ์ด๋Š” ๋™์  ํ• ๋‹น๋œ ๋ฌธ์ž์—ด์—๋„ ์ด์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿ“Œ [Program] Printing a One-Month Reminder List (Revisited) (ํ•œ ๋‹ฌ ๋ฆฌ๋งˆ์ธ๋” ๋ชฉ๋ก ํ”„๋ฆฐํŠธํ•˜๊ธฐ)

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

#define MAX_REMIND (50)
#define MSG_LEN (60)

int read_line(char str[], int n);

int main()
{
	char* reminders[MAX_REMIND];
	char day_str[3], msg_str[MSG_LEN + 1];
	int day, i, j, num_remind = 0;

	for (;;) {
		if (num_remind == MAX_REMIND) {
			printf("-- No space left --\n");
			break; 
		}

		printf("Enter day and reminder : ");
		scanf("%2d", &day);
		if (day == 0)
			break;
		sprintf(day_str, "%2d", day);
		read_line(msg_str, MSG_LEN);

		for (i = 0; i < num_remind; i++)
			if (strcmp(day_str, reminders[i] < 0))
				break;
		for (j = num_remind; j > i; j--)
			reminders[j] = reminders[j - 1];

		reminders[i] = malloc(2 + strlen(msg_str) + 1);
		if (reminders[i] == NULL) {
			printf("-- No space left --\n");
			break; 
		}

		strcpy(reminders[i], day_str);
		strcat(reminders[i], msg_str);

		num_remind++;
	}

	printf("\nDay Reminder\n");
	for (i = 0; i < num_remind; i++)
		printf(" %s\n", reminders[i]);

	return 0; 
}

int read_line(char str[], int n)
{
	int ch, i = 0;

	while ((ch = getchar()) != '\n')
		if (i < n)
			str[i++] = ch;
	str[i] = '\0';
	return i; 
}



๐Ÿ“ Dynamic Allocated Arrays (๋™์  ํ• ๋‹น๋œ ๋ฐฐ์—ด)

C์—์„œ๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰ ์ค‘์— ๋ฐฐ์—ด์— ๊ณต๊ฐ„์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿ“Œ Using malloc to Allocate Storage for an Array (malloc์œผ๋กœ ๋ฐฐ์—ด ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹นํ•˜๊ธฐ)

๋ฌธ์ž์—ด์—์„œ์™€ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ์š”์†Œ์˜ ํฌ๊ธฐ๊ฐ€ ๋ฐ˜๋“œ์‹œ 1byte๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ์ ์ด๋‹ค. ๋”ฐ๋ผ์„œ sizeof ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ํฌ๊ธฐ๋ฅผ ๊ณ„์‚ฐํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

n๊ฐœ์˜ ์ •์ˆ˜๋ฅผ ๋‹ด๋Š” array๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

๋จผ์ € ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์ค€๋‹ค.

int *a;

n์ด ์ด๋ฏธ ์„ ์–ธ๋˜์–ด ์žˆ์„ ๋•Œ, ์•„๋ž˜์™€ ๊ฐ™์ด malloc์„ ์ด์šฉํ•˜์—ฌ ๊ณต๊ฐ„์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.

a = malloc(n * sizeof(int));

์ด๋ ‡๊ฒŒ ํ•˜๊ณ  ๋‚˜๋ฉด a๋ฅผ ๋ฐฐ์—ด์˜ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿ“Œ The calloc Function (calloc ํ•จ์ˆ˜)

calloc์€ <stdlib.h>์— ์„ ์–ธ๋˜์–ด ์žˆ๋‹ค.

๐Ÿ”Ž calloc ํ•จ์ˆ˜

void *calloc(size_t nmemb, size_t size);

calloc์€ size ํฌ๊ธฐ์˜ ๋ณ€์ˆ˜๋ฅผ nmemb๊ฐœ ๋งŒํผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•œ ๋‹ค์Œ calloc์€ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

๐Ÿ”Ž calloc ํ•จ์ˆ˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

a = calloc(n, sizeof(int)); 

struct point { int x, y; } *p;
p = calloc(1, sizeof(struct point)); 


๐Ÿ“Œ The realloc Function (realloc ํ•จ์ˆ˜)

realloc์€ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ(ex.array)์˜ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•œ๋‹ค.

๐Ÿ”Ž realloc ํ•จ์ˆ˜

void *realloc(void *ptr, size_t size);

ptr์€ ๋ฐ˜๋“œ์‹œ malloc, calloc, realloc์— ์˜ํ•ด ์–ป์–ด์ง„ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๊ฐ€๋ฆฌ์ผœ์•ผํ•œ๋‹ค. size๋Š” ๋ธ”๋ก์˜ ์ƒˆ๋กœ์šด ์‚ฌ์ด์ฆˆ๋ฅผ ๋งํ•œ๋‹ค. ๋ณดํ†ต์€ ์žฌํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ptr์ด ๋‹ค์‹œ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ํฌ๊ธฐ๋ฅผ ์ค„์ด๋ผ๋Š” ์š”์ฒญ์„ ๋ฐ›์•˜์„ ๋•Œ realloc์€ ๋ธ”๋ก์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ด๋™์‹œํ‚ค์ง€ ์•Š๊ณ  ์ถ•์†Œํ•ด์•ผ ํ•œ๋‹ค. ํ™•์žฅํ•  ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. ๋งŒ์•ฝ ๋ธ”๋ก ๋’ค์— ์˜ค๋Š” ๋ฐ”์ดํŠธ๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์–ด ํ™•์žฅํ•  ์ˆ˜ ์—†์„ ๋•Œ, realloc์€ ์ƒˆ ๋ธ”๋ก์„ ๋‹ค๋ฅธ ๊ณณ์— ํ• ๋‹นํ•œ ๋‹ค์Œ ์ด์ „ ๋ธ”๋ก์˜ ๋‚ด์šฉ์„ ์ƒˆ ๋ธ”๋ก์— ๋ณต์‚ฌํ•œ๋‹ค.




๐Ÿ“ Deallocating Storage (๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ)

malloc๊ณผ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•จ์ˆ˜๋Š” ํž™(heap)์ด๋ผ๊ณ  ํ•˜๋Š” ์ €์žฅ์†Œ ํ’€(storage pool)์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋ฅผ ๋„ˆ๋ฌด ์ž์ฃผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ํฐ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ์š”์ฒญํ•˜๋ฉด ํž™์ด ์†Œ์ง„๋˜์–ด ํ•จ์ˆ˜๊ฐ€ ๋„ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์‹ฌ์ง€์–ด ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ถ”์ ํ•˜์ง€ ๋ชปํ•ด ๊ณต๊ฐ„์„ ๋‚ญ๋น„ํ•  ์ˆ˜ ์žˆ๋‹ค.

p = malloc(...);
q = malloc(...);
p = q; 

์œ„ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ ์•„๋ž˜์ฒ˜๋Ÿผ ๋˜๋ฏ€๋กœ ์ฒซ๋ฒˆ์งธ block์€ ์˜์›ํžˆ ์“ฐ์ด์ง€ ์•Š๋Š”๋‹ค.

์ด๋ ‡๊ฒŒ ๋” ์ด์ƒ ์“ฐ์ด์ง€ ์•Š๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ garbage๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ด๋Ÿฐ garbage๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜(memory leak)์ด ๋ฐœ์ƒํ•œ๋‹ค. ๋ช‡๋ช‡ ์–ธ์–ด์—์„œ๋Š” garbage collector์„ ์ œ๊ณตํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋‚˜ C๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค. ๋Œ€์‹  free ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.



๐Ÿ“Œ The free function (free ํ•จ์ˆ˜)

free ํ•จ์ˆ˜๋Š” <stdlib.h>์— ๋“ค์–ด ์žˆ๋‹ค.

๐Ÿ”Ž free ํ•จ์ˆ˜

void free(void *ptr);

๐Ÿ”Ž free ํ•จ์ˆ˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

p = malloc(...);
q = malloc(...);
free(p);
p = q;

์ด๋ ‡๊ฒŒ ํ•˜์—ฌ p๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ฝ์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ free์˜ ์ธ์ˆ˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•จ์ˆ˜์— ์˜ํ•ด ๋ฐ˜ํ™˜๋œ ํฌ์ธํ„ฐ์ด์–ด์•ผ ํ•œ๋‹ค.



๐Ÿ“Œ The "Dangling Pinter" Problem ("๋งค๋‹ฌ๋ฆฐ ํฌ์ธํ„ฐ" ๋ฌธ์ œ)

free(p)๋Š” p๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์€ ํ•ด์ œํ•˜์ง€๋งŒ p ์ž์ฒด๋ฅผ ๋ฐ”๊พธ์ง€๋Š” ์•Š๋Š”๋‹ค.
๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ํ˜ผ๋ˆ์„ ์•ผ๊ธฐํ•œ๋‹ค.

char *p = malloc(4);
...
free(p);
...
strcpy(p, "abc"); /*** WRONG ***/

์—ฌ๋Ÿฌ ํฌ์ธํ„ฐ๋“ค์ด ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งค๋‹ฌ๋ฆฐ ํฌ์ธํ„ฐ๋“ค์€ ์ฐพ๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค. ๋ธ”๋ก์ด ํ•ด์ œ๋˜๋ฉด ๋ชจ๋“  ํฌ์ธํ„ฐ๊ฐ€ ๋งค๋‹ฌ๋ฆฐ ์ƒํƒœ๋กœ ์œ ์ง€๋œ๋‹ค.




๐Ÿ“ Linked Lists (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ)

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(linked list)๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ ๋ฐ์ดํ„ฐ์™€ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ํ•œ ์ค„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋Š” null pointer๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ๋ฐฐ์—ด์˜ ๋Œ€์•ˆ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ด์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ "random access"๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ์–ด๋ ˆ์ด์˜ ๊ฒฝ์šฐ ๋ชจ๋“  ์š”์†Œ์— ์ ‘๊ทผํ•˜๋Š”๋ฐ ๋™์ผํ•œ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜์ง€๋งŒ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ฒฝ์šฐ ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๋น ๋ฅด๋‹ค.



๐Ÿ“Œ Declaring a Node Type (๋…ธ๋“œํ˜• ์„ ์–ธํ•˜๊ธฐ)

๋…ธ๋“œ๊ฐ€ ์ •์ˆ˜์™€ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

struct node {
	int value; /* data stored in the node */
	struct node* next; /* pointer to the next node */
};

list๊ฐ€ ์–ด๋””์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š”์ง€๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•ด ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด๋ฅผ first๋ผ๊ณ  ํ•˜์˜€๋‹ค.

struct node *first = NULL:

์ฒ˜์Œ์—” ๋น„์–ด ์žˆ์œผ๋ฏ€๋กœ first์— NULL๊ฐ’์„ ๋ถ€์—ฌํ•˜์˜€๋‹ค.



๐Ÿ“Œ Creating a Node (๋…ธ๋“œ ์ƒ์„ฑํ•˜๊ธฐ)

๋…ธ๋“œ๋ฅผ ์•„๋ž˜ 3๋‹จ๊ณ„๋กœ ์ƒ์„ฑํ•œ๋‹ค.

1) ๋…ธ๋“œ๋ฅผ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
2) ๋…ธ๋“œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค.
3) ๋ฆฌ์ŠคํŠธ์— ๋…ธ๋“œ๋ฅผ ๋„ฃ๋Š”๋‹ค.

๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋…ธ๋“œ๋ฅผ ๋ชฉ๋ก์— ์‚ฝ์ž…ํ•  ๋•Œ๊นŒ์ง€ ๋…ธ๋“œ๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด๋ฅผ new_node๋ผ๊ณ  ํ•˜์ž.

struct node *new_node;

malloc์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ ๋…ธ๋“œ์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ๋ฐ˜ํ™˜ ๊ฐ’์„ new_node์— ์ €์žฅํ•œ๋‹ค.

new_node = malloc(sizeof(struct node)); 

๋‹ค์Œ์œผ๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ ๋…ธ๋“œ์˜ value์— ์ €์žฅํ•œ๋‹ค.

(*new_node).value = 10;



๐Ÿ“Œ The -> Operator (-> ์—ฐ์‚ฐ์ž)

-> ์—ฐ์‚ฐ์ž : ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„์— ์ ‘๊ทผ

๐Ÿ”Ž -> ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ์˜ˆ์‹œ

new_node->value = 10; 

-> ์—ฐ์‚ฐ์ž๋Š” *๊ณผ .์˜ ๊ฒฐํ•ฉ์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. new_node๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ’์„ ์ฐพ์€๋‹ค์Œ ๊ทธ ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„๋ฅผ ์„ ํƒํ•œ๋‹ค.

-> ์—ฐ์‚ฐ์ž๋Š” lvalue๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

๐Ÿ”Ž -> ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ์˜ˆ์‹œ (2) - scnaf์—์„œ

scanf("%d", &new_node->value); 


๐Ÿ“Œ Inserting a Node at the Beginning of a Linked List (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ์‹œ์ž‘์ ์— ๋…ธ๋“œ ์ถ”๊ฐ€ํ•˜๊ธฐ)

new_node : node๊ฐ€ ์‚ฝ์ž…๋˜๋Š” ์ง€์ ์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
first : ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

์ด ๋‘๊ฐ€์ง€๋ฅผ ์ด์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ๋ฒˆ์งธ์— ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋จผ์ € new_node์˜ next ๋ฉค๋ฒ„๊ฐ€ ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ์— ์ €์žฅ๋œ ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•œ๋‹ค.

new_node->next = first;

๋‘๋ฒˆ์งธ๋กœ, first๊ฐ€ new_node๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•œ๋‹ค.

first = new_node 

๐Ÿ”Ž ๋น„์–ด์žˆ๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์— 10 ์ถ”๊ฐ€ ํ›„ 20 ์ถ”๊ฐ€

์ด๋Ÿฌํ•œ ๊ณผ์ •์„ add_to_list๋ผ๋Š” ์ด๋ฆ„์˜ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด๋ณด์ž. ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” list(์ถ”๊ฐ€ ์ „ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ), n(์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ์— ์ €์žฅํ•  ์ •์ˆ˜) ๋‘๊ฐ€์ง€ ์ด๋‹ค.

struct node* add_to_list(struct node* list, int n)
{
	struct node* new_node;

	new_node = malloc(sizeof(struct node));
	if (new_node == NULL) {
		printf("Error : malloc failed in add_to_list\n");
		exit(EXIT_FAILURE);
	}
	new_node->value = n;
	new_node->next = list;
	return new_node; 
}

first๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ง€์ ์€ ๋ณ€ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ add_to_list๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— ๋ฐ˜ํ™˜๊ฐ’์„ first์— ์ €์žฅํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

first = add_to_list(first, 10);
first = add_to_list(first, 20);

๐Ÿ”Ž add_to_list ์‚ฌ์šฉ ์˜ˆ์‹œ - ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ •์ˆ˜ ๋„ฃ๊ธฐ

struct node read_numbers(void)
{
struct node
first = NULL;
int n;

printf("Enter a series of integers (0 to terminate) : ");
for (;;) {
	scanf("%d", &n);
	if (n == 0)
		return first;
	first = add_to_list(first, n);
}

}



๐Ÿ“Œ Searching a Linked List (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์—์„œ ํƒ์ƒ‰ํ•˜๊ธฐ)

๐Ÿ”Ž ํฌ์ธํ„ฐ p๋ฅผ ์ด์šฉํ•˜์—ฌ ๋…ธ๋“œ ์ถ”์ 

for (p = first; p != NULL; p = p->next) {
	...
}

๐Ÿ”Ž search_list (1)

struct node* search_list(struct node* list, int n)
{
	struct node* p;

	for (p = list; p != NULL; p = p->next)
		if (p->value == n)
			return p;
	return NULL
}

๐Ÿ”Ž search_list (2)

๋‘๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ p๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๊ณ  list ์ž์ฒด๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

struct node* search_list(struct node* list, int n)
{
	for (; list != NULL; list = list->next)
		if (list->value == n)
			return list;
	return NULL;
}

list๋Š” ๋ณต์‚ฌ๋ณธ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๊ฟ”๋„ ์ƒ๊ด€์—†๋‹ค.

๐Ÿ”Ž search_list (3)

์„ธ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ while ๋ฌธ์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

struct node* search_list(struct node* list, int n)
{
	while (list != NULL && list->value != n)
		list = list->next;
	return list;
}


๐Ÿ“Œ Deleting a Node from a Linked List (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์—์„œ ๋…ธ๋“œ ์‚ญ์ œํ•˜๊ธฐ)

์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์˜ ํฐ ์žฅ์ ์€ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ๊ฐ€ ์‰ฝ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ 3๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

1) ์ง€์šธ ๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ๊ณณ์œผ๋กœ ๊ฐ„๋‹ค.
2) ์‚ญ์ œ๋œ ๋…ธ๋“œ๋ฅผ "ํ†ต๊ณผ"ํ•˜๋„๋ก ์ด์ „ ๋…ธ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.
3) free๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ญ์ œ๋œ ๋…ธ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋˜ ๊ณต๊ฐ„์„ ์ง€์šด๋‹ค.

1๋ฒˆ ๋‹จ๊ณ„์—์„œ ์ง€์šธ ๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ๊ณณ์œผ๋กœ ๊ฐ€๋ฉด 2๋ฒˆ ๋‹จ๊ณ„์—์„œ ์ด์ „ ๋‹จ๊ณ„์— ๋Œ€ํ•œ ์ผ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.
์ด ๋ฌธ์ œ๋ฅผ "trailing pointer" ๊ธฐ์ˆ ์„ ์ด์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
1๋‹จ๊ณ„์—์„œ ๋ชฉ๋ก์„ ๊ฒ€์ƒ‰ํ•  ๋•Œ ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ(cur) ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด์ „ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ(prev)๋„ ์žˆ๊ฒŒ ํ•œ๋‹ค.

for (cur = list, prev = NULL; cur != NULL && cur->value != n; prev = cur, cur = cur->next); 

30 -> 40 -> 20 -> 10 ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์—์„œ 20์„ ์ฐพ๋Š”๋‹ค๊ณ  ํ•  ๋•Œ ์œ„ ๊ตฌ๋ฌธ์„ ์ด์šฉํ•˜์—ฌ 1๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ 2๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๐Ÿ”Ž ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ด์ „ ๋…ธ๋“œ์™€ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๊ธฐ

prev->next = cur-> next;

๐Ÿ”Ž 20 ์‚ญ์ œ

free(cur);

์ด ์„ธ๊ฐ€์ง€ ๊ณผ์ •์„ ํ†ตํ•ด ์›ํ•˜๋Š” ์ •์ˆ˜๋ฅผ ์‚ญ์ œํ•˜๋„๋ก ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๐Ÿ”Ž delete_from_list

struct node* delete_from_list(struct node* list, int n)
{
	struct node* cur, * prev;

	for (cur = list, prev = NULL; cur != NULL && cur->value != n; prev = cur, cur = cur->next);

	if (cur == NULL)
		return list; /* n was not found */
	if (prev == NULL)
		list = list->next; /* n is in the first node */
	else
		prev->next = cur->next; /* n is in some other node */
	free(cur);
	return list; 
}


๐Ÿ“Œ Ordered Lists (์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ)

์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ : ๋…ธ๋“œ๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ
์ด ๊ฒฝ์šฐ ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ฒƒ์€ ๋” ์–ด๋ ต์ง€๋งŒ ๊ฒ€์ƒ‰์€ ๋” ๋น ๋ฅด๋‹ค.



๐Ÿ“Œ [Program] Maintaining a Prats Database (Revisited) (๋ถ€ํ’ˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์œ ์ง€๊ด€๋ฆฌ (์žฌ๋ฐฉ๋ฌธ))

๐Ÿ”Ž inventory2.c

/* Maintains a parts database (linked list version) */

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

#define NAME_LEN (25)

struct part {
	int number;
	char name[NAME_LEN + 1];
	int on_hand;
	struct part* next;
};

struct part* inventory = NULL; /* points to first part */

struct part* find_part(int number);
void insert(void);
void search(void);
void update(void);
void print(void);

int main(void)
{
	char code;

	for (;;) {
		printf("Enter operation code : ");
		scanf(" %c", &code);
		while (getchar() != '\n');
		switch (code) {
		case 'i': insert();
			break;
		case 's': search();
			break;
		case 'u': update();
			break;
		case 'p': print();
			break;
		case 'q': return 0;
		default: printf("Illegal code\n");
		}
		printf("\n");
	}
}

struct part* find_part(int number)
{
	struct part* p;

	for (p = inventory; p != NULL && number > p->number; p = p->next);
	if (p != NULL && number == p->number)
		return p;
	return NULL;
}

void insert(void)
{
	struct part* cur, * prev, * new_node;

	new_node = malloc(sizeof(struct part));
	if (new_node == NULL) {
		printf("Database is full; can't add more parts.\n");
		return;
	}

	printf("Enter part number : ");
	scanf("%d", &new_node->number);

	for (cur = inventory, prev = NULL; cur != NULL && new_node->number > cur->number; prev = cur, cur = cur->next);
	if (cur != NULL && new_node->number == cur->number) {
		printf("Part already exists.\n");
		free(new_node);
		return; 
	}

	printf("Enter part name : ");
	read_line(new_node->name, NAME_LEN);
	printf("Enter quantity on hand : ");
	scanf("%d", &new_node->on_hand);

	new_node->next = cur;
	if (prev == NULL)
		inventory = new_node;
	else
		prev->next = new_node; 
}

void search(void)
{
	int number;
	struct part* p;

	printf("Enter part number : ");
	scanf("%d", &number);
	p = find_part(number);
	if (p != NULL) {
		printf("Part name : %s\n", p->name);
		printf("Quantity on hand : %d\n", p->on_hand);
	} 
	else {
		printf("Part not found.\n");
	}
}

void update(void)
{
	int number, change;
	struct part* p;

	printf("Enter part number : ");
	scanf("%d", &number);
	p = find_part(number);
	if (p != NULL) {
		printf("Enter change in quantity on hand : ");
		scanf("%d", &change);
		p->on_hand += change;
	}
	else
		printf("Part not found.\n");
}

void print(void)
{
	struct part* p;
	printf("Part Number Part Name Quantity on Hand");
	for (p = inventory; p != NULL; p = p->next)
		printf("%7d		%-25s11d\n", p->number, p->name, p->on_hand);
}



๐Ÿ“ Pointers to Pointers (ํฌ์ธํ„ฐ์˜ ํฌ์ธํ„ฐ)

ํฌ์ธํ„ฐ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•จ์œผ๋กœ์จ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•˜๊ณ ์ž ํ•  ๋•Œ ํฌ์ธํ„ฐ์˜ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ๋‹ค.

์•ž์„œ ์ž‘์„ฑํ•œ add_to_list์—์„œ๋Š” new_node๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ new_node๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹ ์— list๊ฐ€ new_node๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๋ฐ”๊พผ๋‹ค๊ณ  ํ•ด๋ณด์ž.

list = new_node 

ํฌ์ธํ„ฐ๋Š” pass by value๊ธฐ ๋•Œ๋ฌธ์— ์œ„ ๊ตฌ๋ฌธ์€ ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

์˜ฌ๋ฐ”๋ฅธ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๐Ÿ”Ž ํฌ์ธํ„ฐ์˜ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•œ add_to_list

void add_to_list(struct node** list, int n)
{
	struct node* new_node;

	new_node = malloc(sizeof(struct node));
	if (new_node == NULL) {
		printf("Error : malloc failed in add_to_list\n");
		exit(EXIT_FAILURE);
	}
	new_node->value = n;
	new_node->next = *list;
	*list = new_node; 
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด new_node์˜ next๊ฐ€ ์›๋ž˜ list๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋˜ ๊ณณ(์ฒซ๋ฒˆ์งธ์˜€๋˜ ๋…ธ๋“œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋˜๊ณ , list๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ณณ์€ new_node๋กœ ๋ณ€ํ•œ๋‹ค.




๐Ÿ“ Pointers to Functions (ํ•จ์ˆ˜ ํฌ์ธํ„ฐ)

ํ•จ์ˆ˜๋“ค๋„ ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— C์—์„œ๋Š” ํฌ์ธํ„ฐ๊ฐ€ ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.



๐Ÿ“Œ Function Pointers as Arguments (์ž…๋ ฅ๋ณ€์ˆ˜๋กœ์„œ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ)

์  a๋ถ€ํ„ฐ b๊นŒ์ง€ ์ ๋ถ„ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ํ•  ๋•Œ f๋ฅผ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋กœ ์„ ์–ธํ•  ๊ฒƒ์ด๋‹ค.

double integrate(double (*f) (double), double a, double b);

f์•ž์— ํฌ์ธํ„ฐ๋ฅผ ๋ถ™์—ฌ์„œ f๊ฐ€ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. * ์—†์ด ๊ทธ๋ƒฅ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ์“ฐ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

double integrate(double f(double), double a, double b);

integrate๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์ œ๊ณตํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ํ•จ์ˆ˜๋Š” sin ํ•จ์ˆ˜๋ฅผ 0๋ถ€ํ„ฐ ใ… /2๊นŒ์ง€ ์ ๋ถ„ํ•œ๋‹ค.

result = integrate(sin, 0.0, PI/2);

์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์œ„ ์ฝ”๋“œ์—์„œ sin์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ integrate์— sin์˜ ํฌ์ธํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๋œ๋‹ค.

์ด ๊ฐœ๋…์€ a๊ฐ€ ๋ฐฐ์—ด์˜ ์ด๋ฆ„์ธ ๊ฒฝ์šฐ a[i]๋Š” ๋ฐฐ์—ด์˜ ํ•œ ์š”์†Œ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , a ์ž์ฒด๋Š” ๋ฐฐ์—ด์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ f๊ฐ€ ํ•จ์ˆ˜๋ผ๋ฉด f(x)๋Š” ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ๋กœ ์ƒ๊ฐํ•˜์ง€๋งŒ, f ๊ทธ์ž์ฒด๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋กœ ์ทจ๊ธ‰ํ•œ๋‹ค.

integrate์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด f๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

y = (*f)(x);

*f๊ฐ€ f๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์—, integrate(sin, 0.0, PI/2) ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ *f์˜ ํ˜ธ์ถœ์€ ์‚ฌ์‹ค์ƒ sin์˜ ํ™€์ถœ๊ณผ ๊ฐ™๋‹ค.



๐Ÿ“Œ The qsort Function (qsort ํ•จ์ˆ˜)

C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์œ ์šฉํ•œ ํ•จ์ˆ˜๋“ค์˜ ๋Œ€๋ถ€๋ถ„์ด ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ <stdlib.h>์˜ qsort ํ•จ์ˆ˜์ด๋‹ค.

qsort๋Š” ์šฐ๋ฆฌ๊ฐ€ ์„ ํƒํ•œ ๊ธฐ์ค€์— ๋”ฐ๋ผ ๋ชจ๋“  ๋ฐฐ์—ด์„ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์ •๋ ฌ๋˜๋Š” ๋ฐฐ์—ด์˜ ์š”์†Œ๋“ค์€ ์–ด๋–ค ํƒ€์ž…์ด๋“  ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ตฌ์กฐ์ฒด๋‚˜ ๊ณต์œ ์ฒด ํƒ€์ž…์˜ qsort๋Š” ๋‘ ๋ฐฐ์—ด ์š”์†Œ ์ค‘ ์–ด๋–ค ๊ฒƒ์ด "๋” ์ž‘์€"์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฐ€๋ฅด์ณ์•ผ ํ•œ๋‹ค. ๋น„๊ต ํ•จ์ˆ˜(comparison function)์„ ์ž‘์„ฑํ•˜์—ฌ qsort์—๊ฒŒ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ๊ฒƒ์ด๋‹ค.

void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));

base : ์–ด๋ ˆ์ด์˜ ์ฒซ ๋ฒˆ์งธ ์›์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
nmemb : ์ •๋ ฌ๋˜์–ด์•ผ ํ•  ์›์†Œ์˜ ๊ฐฏ์ˆ˜
size : ๊ฐ ์›์†Œ์˜ ์‚ฌ์ด์ฆˆ (๋ฐ”์ดํŠธ ๋‹จ์œ„)
compar : ๋น„๊ตํ•  ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ

๐Ÿ”Ž qsort ์‚ฌ์šฉ ์˜ˆ์‹œ

qsort(inventory, num_parts, sizeof(structpart), compare_parts);

๐Ÿ”Ž compare_parts ํ•จ์ˆ˜ ์ž‘์„ฑํ•˜๊ธฐ

qsort์—์„œ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ void ์œ ํ˜•์„ ๋ฐ›์ง€๋งŒ, void ํฌ์ธํ„ฐ๋ฅผ ํ†ตํ•ด part ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. ์ด ๋ฉค๋ฒ„๋“ค์€ struct part* ์œ ํ˜•์˜ ํฌ์ธํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด compare_parts์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ p, q๋ฅผ struct part*์˜ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜์—ฌ ์›ํ•˜๋Š” ์œ ํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•˜์˜€๋‹ค.

int compare_parts(const void* p, const void* q)
{
	const struct part* p1 = p;
	const struct part* q1 = q;

	if (p1->number < q1->number)
		return -1;
	else if (p1->number == q1->number)
		return 0;
	else
		return 1; 
}

p์™€ q๋Š” const ํฌ์ธํ„ฐ๊ธฐ ๋•Œ๋ฌธ์— const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์—๋งŒ ํ• ๋‹น๋  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿ“Œ Other Uses of Function Pointers (ํ•จ์ˆ˜ ํฌ์ธํ„ฐ์˜ ์—ฌ๋Ÿฌ ์‘์šฉ)

ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด์˜ ์š”์†Œ ๋˜๋Š” ๊ตฌ์กฐ์ฒด๋‚˜ ๊ณต์šฉ์ฒด์˜ ๋ฉค๋ฒ„๋กœ์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๐Ÿ”Ž ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜

void (*pf)(int);

pf๋Š” intํ˜•์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›๊ณ , ๋ฐ˜ํ™˜ ๊ฐ’์ด void ํ˜•์ธ ๋ชจ๋“  ํ•จ์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

pf๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

(*pf)(i);

๋˜๋Š”

pf(i);

๐Ÿ”Ž ์š”์†Œ๊ฐ€ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ์ธ ๋ฐฐ์—ด

void (*file_cmd[])(void) = { new_cmd, open_cmd, close_cmd, close_all_cmd };

๋ฐฐ์—ด ์ฒจ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

(*file_cmd[n]))(); /* or file_cmd[n](); */


๐Ÿ“Œ [Program] Tabulating the Trigonometric Functions (์‚ผ๊ฐํ•จ์ˆ˜ ํ‘œ๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ)

๐Ÿ”Ž cos, sin ๋ฐ tan ํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋ณด์—ฌ์ฃผ๋Š” ํ‘œ๋ฅผ ์ถœ๋ ฅ

/* Tabulates values of trigonometric functions */

#include <math.h>
#include <stdio.h>

void tabulate(double (*f)(double), double first, double last, double incr);

int main(void)
{
	double final, increment, initial;

	printf("Enter initial value : ");
	scanf("%lf", &initial);

	printf("Enter final value : ");
	scanf("%lf", &final);

	printf("Enter increment : ");
	scanf("%lf", &increment);

	printf("\n      x	       cos(x)"
			  "\n   -------    -------\n");
	tabulate(cos, initial, final, increment);

	printf("\n      x	       sin(x)"
		"\n   -------    -------\n");
	tabulate(sin, initial, final, increment);

	printf("\n      x	       tan(x)"
		"\n   -------    -------\n");
	tabulate(tan, initial, final, increment);

	return 0; 
}

void tabulate(double (*f)(double), double first, double last, double incr)
{
	double x;
	int i, num_intervals;

	num_intervals = ceil((last - first) / incr);
	for (i = 0; i <= num_intervals; i++) {
		x = first + i * incr;
		printf("%10.5f %10.5f\n", x, (*f)(x));
	}
}


๐Ÿ“Œ [C99] Restricted Pointers (์ œํ•œ ํฌ์ธํ„ฐ)

๐Ÿ”Ž restrict

int* restrict p;

์œ„์ฒ˜๋Ÿผ restrict๋กœ ์„ ์–ธ๋œ ํฌ์ธํ„ฐ๋ฅผ ์ œํ•œ ํฌ์ธํ„ฐ(restricted pointer)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

์ด๋ ‡๊ฒŒ ์„ ์–ธํ•˜๋ฉด p๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐœ์ฒด๊ฐ€ ๋‹ด๊ธด ๋ฉ”๋ชจ๋ฆฌ์—๋Š” ๋‹ค๋ฅธ ํฌ์ธํ„ฐ๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์ด์ƒ์˜ ๋ฐฉ๋ฒ•์„ aliasing์ด๋ผ๊ณ  ํ•œ๋‹ค.

int* restrict p;
int* restrict q;

p = malloc(sizeof(int));

q = p;
*q = 0; /* casus undefined behavior */

p๊ฐ€ ์ œํ•œ ํฌ์ธํ„ฐ์ด๊ธฐ ๋•Œ๋ฌธ์—, *q = 0 ์ด ์ •์˜๋˜์ง€ ์•Š๋Š”๋‹ค.

์ œํ•œ๋œ ํฌ์ธํ„ฐ p๊ฐ€ ์™ธ๋ถ€ ์ €์žฅ์†Œ ํด๋ž˜์Šค ์—†์ด ๋กœ์ปฌ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ๋˜๋ฉด, restrict๋Š” p๋กœ ์„ ์–ธ๋œ ๋ธ”๋ก์ด ์‹คํ–‰๋  ๋•Œ๋งŒ p์— ์ ์šฉ๋œ๋‹ค.

restrict ์‚ฌ์šฉ๋ฒ•์„ ๋” ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด <string.h>์— ์žˆ๋Š” memcpy์™€ memmove๋ฅผ ์•Œ์•„๋ณด์ž.

๐Ÿ”Ž memcpy

void *memcpy(void* restrict s1, const void* restrict s2, size_t n); 

memcpy๋Š” ํ•œ ๊ฐœ์ฒด์—์„œ ๋‹ค๋ฅธ ๊ฐœ์ฒด๋กœ ๋ฐ”์ดํŠธ๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค.

  • s2 : ๋ณต์‚ฌํ•  ๋ฐ์ดํ„ฐ
  • s1 : ๋ณต์‚ฌ๋ณธ์˜ ๋Œ€์ƒ
  • n : ๋ณต์‚ฌํ•  ๋ฐ”์ดํŠธ ์ˆ˜
    s1, s2์— restrict๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ณต์‚ฌํ•  ๊ฒƒ๊ณผ ๋ณต์‚ฌ๋ณธ์˜ ๋Œ€์ƒ์ด ๊ฒน์น˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

๋ฐ˜๋Œ€๋กœ memmove์—์„œ๋Š” restrict๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿ”Ž memmove

void *memmove(void *s1, const void *s2, size_t n);

์ฐจ์ด์ ์€ ์†Œ์Šค์™€ ํƒ€๊นƒ์ด ๊ฒน์น˜๋”๋ผ๋„ memmove๋Š” ์ž‘๋™์ด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, memmove๋ฅผ ์ด์šฉํ•˜์—ฌ ์–ด๋ ˆ์ด์˜ ์›์†Œ๋“ค์„ ํ•œ์นธ์”ฉ ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

memmove(&a[0], &a[1], 99 * sizeof(int));

restrict๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์— ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋ณด๋‹ค ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•จ์œผ๋กœ์จ ์ตœ์ ํ™”(optimization)์„ ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ตœ์ ํ™”๋ฅผ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ œํ•œ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.



๐Ÿ“Œ [C99] Flexible Array Members (์œ ๋™์  ๋ฐฐ์—ด ๋ฉค๋ฒ„)

๋ฌธ์ž์—ด ์ €์žฅ์„ ์ข€ ๋” ์œ ๋™์ ์ด๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž

struct vstring {
	int len;
	char chars[N];
};

์ด๋Ÿฐ ๊ณ ์ • ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์—ด์€ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ ์ œํ•œํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‚ญ๋น„ํ•œ๋‹ค.

C ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค์€ ์ „ํ†ต์ ์œผ๋กœ ๋ฌธ์ž ๊ธธ์ด๋ฅผ 1๋กœ ์„ ์–ธํ•˜๊ณ  ๊ฐ ๋ฌธ์ž์—ด์„ ๋™์ ์œผ๋กœ ํ• ๋‹นํ•จ์œผ๋กœ์จ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์™”๋‹ค.

struct vstring {
	int len;
	char chars[1];
};
...
struct vstring* str = malloc(sizeof(struct vstring) + n - 1);
str->len = n;

์ด๋Ÿฐ ๋ฐ”๋ฒ•์€ "struct hack"์ด๋ž€ ์ด๋ฆ„์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ๋‹ค.

struct hack์˜ ์œ ์šฉ์„ฑ ๋•Œ๋ฌธ์— C99์—์„œ๋Š” ์œ ๋™์  ๋ฐฐ์—ด ๋ฉค๋ฒ„(flexible array member) ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

๐Ÿ”Ž flexible array member

struct vstring {
	int len;
	char chars[]; /* flexible array member - C99 only */
};
...
struct vstring* str = malloc(sizeof(struct vstring) + n);
str->len = n;

์œ ๋™์  ๋ฐฐ์—ด ๋ฉค๋ฒ„๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๊ตฌ์กฐ์ฒด๋Š” ์™„์ „ํ•˜์ง€ ์•Š์€ ์œ ํ˜•(incomplete type)์ด๋‹ค. ์ด๋Ÿฌํ•œ ํƒ€์ž…์€ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„๊ฐ€ ๋˜๊ฑฐ๋‚˜ ์–ด๋ ˆ์ด์˜ ์›์†Œ๊ฐ€ ๋  ์ˆ˜ ์—†๋‹ค. ํ•˜์ง€๋งŒ ์–ด๋ ˆ์ด๊ฐ€ ์ด ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜๋Š” ์žˆ๋‹ค.

profile
๊ณต๋ถ€์ •๋ฆฌ์šฉ

0๊ฐœ์˜ ๋Œ“๊ธ€