C 언어 구조체 포인터 배열 매개변수 - C eon-eo gujoche pointeo baeyeol maegaebyeonsu

-목차- 

1. 구조체 포인터 변수

2. 구조체 매개 변수 : "구조체 복사" vs "구조체 포인터"  

3. 시간, 날짜와 관련된 C언어 표준 라이브러리 함수 


1. 구조체 포인터 변수

구조체 변수 값을 swap하는 함수 만들기

#include <stdio.h>

typedef struct student {
	int id;
	char *pname;
	double points;
} STUD;

void stud_printx(STUD s) {
	printf("[%d:%s] = %lf\n", s.id,s.pname,s.points);
}

void stud_swap(STUD s1, STUD s2) {
	STUD tmp = s1;
	s1 = s2;
	s2 = tmp;
}

int main(void) {
	STUD s1 = {1,"Kim",100};
	STUD s2 = {2,"Hwang",98};
	
	stud_printx(s1);
	stud_printx(s2);
	
	stud_swap(s1,s2);
	stud_printx(s1);
	stud_printx(s2);
	
	return 0;
}

- 구조체 변수값을 swap하기 위해 stud_swap( ) 함수를 만들었다. 그러나 실행 결과 swap이 이루어지지 않았다!!

- swap이 되지 않은 이유는 Call by Value때문이다. 구조체 변수 역시 매개 변수로 값이 복사된다

※ 해결책??

- 구조체 자료형에도 포인터 사용 가능

- 구조체 포인터에서 구조체 멤버로 접근하기 위해 -> 연산자를 사용하자  ★★★★

C 언어 구조체 포인터 배열 매개변수 - C eon-eo gujoche pointeo baeyeol maegaebyeonsu
#include <stdio.h>

typedef struct student {
	int id;
	char *pname;
	double points;
} STUD;

void stud_printx(STUD* s) {
	printf("[%d:%s] = %lf\n", s->id,s->pname,s->points);
}

void stud_swap(STUD* s1, STUD* s2) {
	STUD tmp = *s1;
	*s1 = *s2;
	*s2 = tmp;
}

int main(void) {
	STUD s1 = {1,"Kim",100};
	STUD s2 = {2,"Hwang",98};
	
	stud_printx(&s1);
	stud_printx(&s2);
	
	stud_swap(&s1,&s2);
	stud_printx(&s1);
	stud_printx(&s2);
	
	return 0;
}

- stud_printx 함수의 매개 변수 인자를 STUD* s 로 설정함으로써 구조체 포인터 변수를 매개 변수로 설정하였다. ( 구조체 포인터 변수에 접근하기 위해서는 '->' 연산자를 사용해야 함!! )

- stud_swap 함수의 매개 변수 인자를 STUD* s1, STUD* s2로 설정하여 포인터 변수를 활용해 주소값에 접근하여 swap을 해주었다.

+) 주의할 점

- 연산자를 하나만 사용하여 구조체 포인터값에 접근하는것이 일반적이다.

- 두 개의 연산자 *,-> 를 사용할시 -> 연산자의 우선순위가 *연산자의 우선순위보다 높다

#include <stdio.h>

typedef struct student {
	int id;
	char *pname;
	double points;
} STUD;

int main(void) {
	STUD s1 = {1,"Kim",100};
	STUD* ps1 = &s1;
	
	s1.id = 2;
	ps1->id = 3;		// GOOD
	(*ps1).id = 4;		// OK
	*ps1.id = 5;		// Error
	
	
	return 0;
}

2. 구조체 매개 변수 : "구조체 복사" vs "구조체 포인터"

배열의 경우

- 대입 연산을 적용할 수 없고

- 함수 매개변수일 때 배열이 복사되는 것이 아니라 배열의 주소가 복사된다

구조체의 경우

- 대입 연산을 적용할 수 있고

- 함수 매개변수일 때 값이 복사되는 것을 확인하였다

구조체 복사, 즉 메모리 복사는 CPU의 효율을 떨어뜨리는 연산이다. 따라서 포인터 사용 추천!!

- 다만 함수 내에서 원하지 않는 구조체 내용 변경 등 Side Effect가 발생할 경우가 있다.


3. 시간, 날짜와 관련된 C언어 표준 라이브러리 함수

time_t time ( time_t *arg ) ;

- 1970년 1월 1일 자정을 기준으로 현재까지 흐른 시간을 초 단위로 계산하여 반환한다. 

- param : 시간값이 저장될 포인터 변수 혹은 NULL 포인터

- return : 성공시 1970년 1월 1일부터 현재까지 흐른 시간을 초단위로 반환함. 실패시 -1 반환

+) T2K 문제와 비슷한 문제를 가지고 있다. (2038년이 되면 overflow가 발생함) 

+) <time.h> 헤더파일에 typedef를 통해 정의되어 있음 

ex)

#include <stdio.h>
#include <time.h>

int main(void) {
	time_t tnow = time(NULL);
	
	printf("The current thime is %ld seconds since the Epoch\n",tnow); // ld로 출력함을 잊지 말자
	printf("sizeof(time_t) = %d\n",sizeof(time_t));
	
	return 0;
}

struct tm* gmtime ( time_t* time ); ★★

- time*t time 매개변수값을 활용해 UTC로 바꿔줌.

- param : time_t 포인터 변수

- return : 성공시 구조체 tm의 포인터 변수를 반환, 실패시 NULL 포인터 변수 반환

C 언어 구조체 포인터 배열 매개변수 - C eon-eo gujoche pointeo baeyeol maegaebyeonsu
#include <stdio.h>
#include <time.h>

int main(void) {
	time_t tnow = time(NULL);
	struct tm * pnow;
	pnow = gmtime(&tnow);
	
	if (pnow != NULL) {
		printf("Today is %d.%d.%d and it\'s", 
			pnow->tm_year+1900, pnow->tm_month+1,pnow->tm_day);
		switch(pnow->tm_wday) {
			case 0 : puts("Sunday"); break;
			case 1 : puts("Monday"); break;
			case 2 : puts("Tuesday"); break;
			case 3 : puts("Wednesday"); break;
			case 4 : puts("Thursday"); break;
			case 5 : puts("Friday"); break;
			case 0 : puts("Saturday"); break;
		}
	}
	
	return 0;
}

+) sturct tm -> time_t 로 돌리는 함수 : time_t mktime(struct tm* time);

char* asctime( struct tm* ptime );

- 주어진 struct tm* ptime 포인터 변수를 통해 요일 달 일 시간의 정보가 담긴 char 배열로 반환한다.

- param : sruct tm* ptime 포인터 변수

- return : 시간의 정보가 담긴 char 배열로 반환

struct tm * localtime( time_t *time );     ★★

- 주어진 struct tm* ptime 포인터 변수를 통해 현위치에서의 시간을 계산하여 반환

- param : sruct tm* ptime 포인터 변수

- return : 현 위치의 시간의 정보가 담긴 포인터 변수를 반환

ex)

#include <stdio.h>
#include <time.h>

int main(void) {
	time_t tnow = time(NULL);
	struct tm * ptm_now;
	
	//
	ptm_now = gmtime(&tnow);
	if (ptm_now) {
		printf("Now in UTC : %s",asctime(ptm_now));
	}
	
	ptm_now = localtime(&tnow);
	if (ptm_now) {
		printf("Now in Local : %s",asctime(ptm_now));
	}
	
	//
	time_t tepoch = 0,
	ptm_now = gmtime(&tepoch);
	if (ptm_now) {
		printf("Now in UTC : %s",asctime(ptm_now));
	}
	
	ptm_now = localtime(&tnow);
	if (ptm_now) {
		printf("Now in Local : %s",asctime(ptm_now));
	}
	
	
	return 0;
}

+) 오늘 날짜, 오늘의 요일, 100일 이후의 날짜, 100일 이후의 요일를 출력하는 프로그램을 작성해보자

#include <stdio.h>
#include <time.h>

int main(void) {
	time_t tnow = time(NULL);
	struct tm *pnow; 
	
	// 오늘
	pnow = gmtime(&tnow);
	printf("오늘 날짜: %d.%d.%d 오늘 요일 : ", 
		pnow->tm_year+1900,pnow->tm_mon+1,pnow->tm_mday);
	switch(pnow->tm_wday) {
		case 0 : puts("Sunday"); break; 
		case 1 : puts("Monday"); break;
		case 2 : puts("Tuesday"); break; 
		case 3 : puts("Wednesday"); break;
		case 4 : puts("Thursday"); break; 
		case 5 : puts("Friday"); break;
		case 6 : puts("Saturday"); break;
	}
	
	// 100일 이후  
	time_t tnow_100 = tnow + 60*60*24*100;
	pnow = gmtime(&tnow_100);
	printf("100일 후 날짜: %d.%d.%d 오늘 요일 : ", 
		pnow->tm_year+1900,pnow->tm_mon+1,pnow->tm_mday);
		switch(pnow->tm_wday) {
		case 0 : puts("Sunday"); break; 
		case 1 : puts("Monday"); break;
		case 2 : puts("Tuesday"); break; 
		case 3 : puts("Wednesday"); break;
		case 4 : puts("Thursday"); break; 
		case 5 : puts("Friday"); break;
		case 6 : puts("Saturday"); break;
	}
	
	return 0;
}