구조체를 함수에서 사용하기
함수의 전달인자로 구조체 자체를 전달할 것인지, 아니면 구조체를 가리키는 포인터를 전달할 것인지 사용자가 선택할 수 있다. 또는 구조체 멤버를 전달인자로 사용할 수 있다.
피호출 함수에서 호출함수에 있는 구조체 값에 영향을 주고자 한다면 구조체의 주소나 구조체 멤버의 주소를 전달인자로 넘겨주면 된다. 구조체 주소를 얻기 위해서는 &를 사용해야 한다. 배열 이름과 다르게 구조체 이름은 주소가 아니다.
구조체는 같은 데이터형 구조체간에 대입하는 것을 허용한다. 즉 A_data 와 B_data가 같은 데이터형 구조체라면 다음과 같이 대입할 수 있다.
ex) A_data = B_data;
이것은 A_data의 각 멤버에 B_data의 각 멤버의 값이 대입되게 한다.
또한 같은 데이터형의 구조체라면, 한 구조체를 다른 구조체로 초기화 할 수 있다.
struct names right_field = {"Ruthine","George"};
struct names captain = right_field;
구조체를 함수의 전달인자로 사용할 수 있고 함수의 리턴값으로도 리턴할 수 있다. 구조체를 함수의 전달인자로 사용하면, 함수에 구조체 정보를 전달할 수 있다. 구조체를 함수의 리턴값으로 사용하면, 피호출 함수로부터 호출 함수로 구조체 정보를 전달할 수 있다.
구조체 포인터를 전달인자로 사용하는 것은 주소 하나만 전달하기 때문에 빠르다. 그러나 피호출 함수에서 수행하는 특정 동작에 따라 원본 구조체에 들어있는 값에 영향을 줄 수 있다. 이러한 문제는 함수 전달인자에 const를 넣어 해결 할 수 있다.
구조체 안에 문자열을 저장해야 한다면, 문자 배열 멤버를 사용하라. 구조체 안에 char형 포인터는 값 저장을 엉뚱한 곳에 저장하려고 시도할 수 있어 프로그램이 먹통이 될 수 있다.
구조체안에 문자열 포인터를 사용하는 바람직한 방법은 malloc()을 사용하여 메모리를 할당하고, 그 주소를 포인터에 보관하는 방법이다.
복합 리터럴은 이름이 없는 오브젝트 즉 명명되지 않은 데이터 객체이다. 이러한 복합 리터럴은 함수의 전달인자로 사용되는 구조체나 다른 구조체에 대입되는 구조체를 생성하는데 사용할 수 있다. 복합 리터럴을 사용하여 구조체를 만들 때는 초기화 값 리스트에 적용되는 것과 동일한 신택스 규칙이 복합 리터럴에 적용 되어야 한다.
플렉서블 배열 멤버(flexible array member)
구조체의 마지막 멤버가 특별한 속성을 가지는 배열을 가질 수 있다. 이러한 배열 멤버를 플렉서블 배열 멤버라고 한다. 이 배열의 첫번째 특별한 속성은, 플렉서블 배열 멤버가 지금 당장은 존재하지 않는 배열이라는 것이다.
두번째 특별한 속성은, 플렉서블 배열 멤버를 마치 그것이 존재하는 것처럼 그리고 필요한 만큼 원소를 가지고 있는 것처럼, 적당한 코드와 함께, 사용할 수 있다는 것이다.
함수의 전달인자로 구조체를 활용할 때는 구조체 멤버를 전달, 구조체 주소로 전달, 구조체 자체를 전달 할 수 있다.
플렉서블 배열 멤버를 선언하는 규칙
- 플렉서블 배열 멤버는 구조체의 마지막 멤버가 되어야 한다.
- 다른 멤버가 최소한 하나 있어야 한다.
- 플렉서블 배열은, 각괄호 안을 비워 놓는다는 것을 제외하고, 보통의 배열처럼 선언한다.
ex)
struct flex
{
int count;
double average;
double scores[];
};
struct flex 형 변수를 선언하더라도, scores를 사용할 수 없다. scores를 위한 메모리가 할당되지 않았기 때문이다.
이러한 플렉서블 배열 멤버가 있는 구조체는 변수 선언을 의도한 것이 아니라 struct flex형을 가리키는 포인터를 선언하고, struct flex형의 정규 내용들을 저장할 공간과 플렉서블 배열 멤버를 위해 원하는 만큼의 공간을 할당 받기위해 malloc()을 사용하려고 의도하는 것이다.
예를 들어 double 형 값 5개 짜리 배열을 scores로 나타내기 위해서
ex)
struct flex *pf;
pf = malloc(sizeof(struct flex)+5*sizeof(double));
로 나타낼 수 있다.
malloc()할당을 통해 count, average, double형 값 5개짜리 배열을 저장할 수 있는 메모리 덩어리가 확보된다. 이후 각 멤버에 접근할 때는 포인터 pf를 사용하여 접근하면 된다.
pf->count = 5;
pf->scores[2] = 18.5;
felxible 배열 멤버를 가지고 있는 구조체를 다룰 때는 구조체 대입을 하면 안된다.
ex)
struct flex *pf1, *pf2;
*pf2 = *pf1;
위와 같이 하면 안된다. 위와 같은 대입은 flexible 멤버를 제외한 멤버들만 복사할 것이다. 값을 대입하고 싶을 때는 대입연산자가 아닌 memcpy()를 사용하라.
fexible 멤버가 있는 구조체는 구조체 값을 전달하는 함수와 함께 사용하면 안된다. 값을 전달인자로 전달하는 것은 대입과 같다.
flexible 멤버가 있는 구조체를 다른 구조체의 멤버로 사용할 수 없다.