본문 바로가기

BackEnd/C

구조체 변수로 가능한것과 불가능한 것

반응형

1. 구조체 변수로 가능한것과 불가능한 것


구조체 변수의 활용방법은 일반변수와 크게 차이가 없다. 변수로 가능한 대부분의 일이 가능하다.


1) 함수의 인자로 전달도 가능하다.


2) 반환도 가능하다. 


3) 대입 연산의 피연산자로도 사용이 가능하다. 


4) 단 사칙연산은 불가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
 
struct __point
{
    double xPos;
    double yPos;
};
typedef struct __point point;
 
point IncrePos(point pnt)
{
    pnt.xPos++;
    pnt.yPos++;
    return pnt;
}
 
int main(void)
{
    point p1, p2, p3;
    p1.xPos=0.5;
    p1.yPos=1.5;
 
    p2=p1;
    p3=IncrePos(p2);
    
    printf("X: %g \n", p3.xPos);
    printf("Y: %g \n", p3.yPos);
    return 0;
}
cs


1
2
X: 1.5
Y: 2.5
cs


• 10행 : point가 자료형의 이름이기 때문에 이를 반환형과 매개변수형으로 선언할 수 있다. 즉 함수 IncrePos는 point형 데이터를 인자로 받고, point형 데이터를 반환하는 함수이다.


• 23행 : 일반 변수와 동일하게 대입연산이 가능하다. 이 대입연산으로 인해서 p1의 모든 값은 p2에 복사된다. 


• 24행 : IncrePos 함수를 호출하면서 p2를 인자로 전달하고 있다. 따라서 p2에 저장된 값이 전달되어 매개변수가 초기화 된다. 그리고 반환 값은 p3에 저장이 된다.


참고로 위 예제 24행에서 이뤄지는 값의 복사 과정을 그림으로 정리하면 다음과 같다.



그리고 구조체 변수를 이용한 사칙연산도 위 예제를 보면 가능할 것도 같아 보인다. point 구조체를 


형성하는 두 개의 구조체 멤버가 실수이기 때문이다. 그러나 구조체 변수를 이용한 사칙연산은 허용


되지 않는다. 구조체 멤버에는 문자열의 저장이 가능한 char형 배열처럼 사칙연산을 적용하기 어려 


운 대상도 포함될 수 있기 때문이다.


그리고 구조체 변수는 복합대입 연산자 += 의 피연산자가 될수 없다.  왜냐하면 연산자 += 의 경우 


대입연산 이전에 덧셈연산을 거쳐야 하기 때문이다. 


2. 배열을 멤버로 하는 구조체의 정의와 대입연산


구조체의 멤버에는 배열도 올 수 있다. 그리고 이렇게 멤버로 배열이 오게 될 경우,대입연산을 


통해서 배열을 통째로 복사하는 것이 가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <string.h>
#define NAME_LEN  30
#define PID_LEN   15
 
struct __person
{
    char name[NAME_LEN];  // 이름
    char ID[PID_LEN];     // 주민등록 번호
    unsigned int age;     // 나이
};
typedef struct __person  person;
 
void ShowPersonData(person prsn)
{
    printf("이름: %s \n", prsn.name);
    printf("주민등록 번호: %s \n", prsn.ID);
    printf("나이: %u \n", prsn.age);
}
 
int main(void)
{
    person jongsoo;
    person copyman;
 
    strcpy(jongsoo.name, "한종수");
    strcpy(jongsoo.ID, "900218-1012589");
    jongsoo.age=20;
 
    copyman=jongsoo;
    ShowPersonData(copyman);
 
    return 0;
}

cs


1
2
3
이름: 한종수
주민등록 번호: 900218-1012589
나이: 20
cs


• 8, 9행 : 구조체의 멤버로 배열이 선언되었다. 이처럼 구조체 안에는 배열이 선언될 수 있다.


• 14행 : 이 함수는 구조체 person의 데이터를 인자로 전달받아서, 그 안에 저장되어 있는 데이터를 출력하도록 정의되었다.


• 26, 27행 : 23행에서 선언한 구조체 변수의 멤버 일부를 초기화하고 있다. 문자열을 복사 저장해야 하기 때문에 strcpy 함수의 도움을 받아야 한다. 


• 30행 : 구조체 변수 jongsoo에 저장된 값을 동일한 자료형의 변수인 copyman에 대입연산을 통해서 


복사하고 있다. 이 경우에 jongsoo에 저장된 모든 멤버의 데이터가 copyman에 그대로 복사 된다.


• 31행 : 30행의 대입연산으로 초기화 된 변수 값의 출력을 위해 ShowPersonData 함수를 호출하고 있다.


지금까지는 대입연산을 통한 배열의 복사가 불가능했다. 뿐만 아니라 함수의 전달인자로 배열의 주소 


값만 전달이 가능했을 뿐,배열 자체를 전달하는 것도 불가능했다. 그러나 위 예제에서는 대입연산을 


통해서 배열을 복사도 하고,함수의 매개 변수로 배열 자체를 전달도 하고 있다. 비록 구조체의 멤버


로 선언된 배열이긴 하지만 말이다. 


다음 그림은 위 예제의 30행과 31행에서 일어나는 상황을 정리해 놓은 것이다.


- 대입연산과 인자전달 과정에서의 구조체 멤버의 복사방식



3. 구조체와 구조체 포인터


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <string.h>
#define NAME_LEN  30
#define PID_LEN   15
 
struct __person
{
    char name[NAME_LEN];  // 이름
    char ID[PID_LEN];     // 주민등록 번호
    unsigned int age;     // 나이
};
typedef struct __person  person;
 
void ShowPersonData(person * ptr)
{
    printf("이름: %s \n", (*ptr).name);
    printf("주민등록 번호: %s \n", (*ptr).ID);
    printf("나이: %u \n", ptr->age);
}
 
int main(void)
{
    person jongsoo;
    person copyman;
    person * personPtr;
 
    strcpy(jongsoo.name, "한종수");
    strcpy(jongsoo.ID, "900218-1012589");
    jongsoo.age=20;
 
    copyman=jongsoo;
    personPtr=&copyman;
    
    ShowPersonData(personPtr);
 
    return 0;
}

cs


1
2
3
이름: 한종수
주민등록 번호: 900218-1012589
나이: 20
cs

• 14행 : 구조체 person의 주소값을 인자로 전달받도록 함수가 변경되었는데, 여기서 사용된 매


개변수의 포인터 선언 방식은 기본 자료형 변수의 포인터 선언방식과 동일하다.


• 25행 : 구조체 변수의 포인터 선언방식을 보여준다. 


• 32행 : 구조체 변수의 주소 값을 얻을 때도 & 연산자를 사용한다.


• 16~18행 : 포인터를 이용한 구조체 변수의 접근과 관련된 내용으로, 34행의 함수 호출문장이 


실행되면, 14행에 선언된 매개변수 ptr은 24행에 선언된 구조체 변수 copyman을 가리키게 된


다. 따라서 (*ptr)은 구조체 변수 copyman을 의미하게 되어, copyman의 멤버에 접근하기 위해서


는 다음과 같이 연산문을 구성해야 한다.


• ptr이 가리키는 구조체 변수의 name 접근 : (*ptr).name 

• ptr이 가리키는 구조체 변수의 ID 접근 : (*ptr).ID 

• ptr이 가리키는 구조체 변수의 age 접근 : (*ptr).age


멤버에 접근하는 위 문장에서 괄호가 필요한 이유는 . 연산자보다 * 연산자의 우선순위가 낮기 때


문이다. 그리고 C언어에서는 위와 같이 포인터를 이용한 구조체 멤버의 접근을 간단히 처리할 


수 있도록 -> 연산자를 제공하고 있다. 이 연산자를 사용하면 다음과 같은 방식으로 접근이 가능


하다. 


• ptr이 가리키는 구조체 변수의 name 접근 : ptr->name 

• ptr이 가리키는 구조체 변수의 ID 접근 : ptr->ID 

• ptr이 가리키는 구조체 변수의 age 접근 : ptr->age


즉 (*pointer).member는 pointer->member와 완전히 동일한 연산문이다. 


그러나 후자의 방식이 보다 간결한 형식을 띠기 때문에 일반적으로 많이 사용된다.


4. 구조체 변수의 선언과 초기화


구조체 변수의 초기화 방법은 마치 배열의 초기화와 유사하다. 즉 초기화할 값을 중괄호 안에 쉼


표로 구분 지어 표시하면 된다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#define NAME_LEN  30
#define PID_LEN   15
 
struct __person
{
    char name[NAME_LEN];  // 이름
    char ID[PID_LEN];     // 주민등록 번호
    unsigned int age;     // 나이
};
typedef struct __person  person;
 
void ShowPersonData(person * ptr)
{
    printf("이름: %s \n", (*ptr).name);
    printf("주민등록 번호: %s \n", (*ptr).ID);
    printf("나이: %u \n\n", ptr->age);
}
 
int main(void)
{
    person jongsoo={"한종수""900218-1012589"20};
    person sungeun={"이성은""910218-1012589"19};
    
    ShowPersonData(&jongsoo);
    ShowPersonData(&sungeun);
    return 0;
}

cs


1
2
3
4
5
6
7
이름: 한종수
주민등록 번호: 900218-1012589
나이: 20
 
이름: 이성은
주민등록 번호: 910218-1012589
나이: 19
cs


• 22, 23행 : 구조체 변수를 선언과 동시에 초기화하고 있다. 중괄호 안에다가 구조체의 멤버가 선언된 순서대로, 초기화할 값을 정리해서 삽입하고 있다.

반응형

'BackEnd > C' 카테고리의 다른 글

구조체 배열  (0) 2019.03.23
구조체의 정의에 포함되는 typedef 선언  (0) 2019.03.23
구조체의 정의  (0) 2019.03.22
구조체의 필요성  (0) 2019.03.21
대표적인 선행처리 명령문  (0) 2019.03.21