본문 바로가기

프로그래밍./C언어.

구조체. ->연산자 .연산자

구조체. 서로다른 자료형들을 하나로 묶는 것.

#include <Stdio.h>
#include <stdlib.h>

struct student{ // 구조체 이름 또는 태그(tag)
int number; // 학번
char name[10]; // 이름
double height; // 키
};

void main()
{
struct student s; // 구조체 변수 선언.

s.number = 20060603;
strcpy(s.name, "김동규");    //scanf("%s", s.name)와 동일. 
s.height = 163.5;

printf("학번 : %d\n", s.number);
printf("이름 : %s\n", s.name);
printf("키 : %f\n", s.height);
}

구조체는 변수 이다. 구조체를 선언 하고 변수를 만들어야 한다.
struct student 라는 자료형으로 s라는 변수를 만든다.
여기서 2가지 방법으로 나뉜다. 방법은 두가지지만 사용하는 방법은 하나 일듯;

struct student{
 int num;
 int kor;


}STU;

이렇게 한다면. struct student s 라고 적는 대신에 STU s; 라고 하면 된다.
struct student 를 STU 라고 대체 한다는 이야기 이다.

typedef 라는 것과 같은 형식이다. 모른다면 아래의 링크를 참조하자.
typedef란? typedef 사용법

또한 매개변수로 넘겨줄시 struct student 가 자료형 이기 때문에 구조체를 넘겨주고
void test(struct student s); 이런식으로 자료형을 제대로 써 주어야 한다.

선언과 동시에 초기화 하고 싶다면
구조체 정의 끝에 } s = {20060603, "김동규", 163.5}; 로 사용.

구조체에서 문자열을 저장하는 경우에는 strcpy를 통해서 저장해야 한다. strcpy(s.name, "김동규")


구조체와 포인터.
struct student *p;

struct student s = {20100001, "김동규", 163.5};
struct student *p;

p = &s;

printf("학번=%d 이름 =%s 키="%f \n", s.number, s.name, s.height);
printf("학번=%d 이름 =%s 키="%f \n", (*p).number, (*p).name, (*p).height);

또는 -> 라는 연산자가 있는데 간접 멤버 연산자(indirect membership operator)이라고 부르며
p->name; 와 (*p).name는 동일하다.  ->를 많이 사용한다.

*p.number은 연산자 우선순위에 의해서 *(p.number) 로 되는데 p의 멤버 number가 가리는 값이다.
따라서 number은 반드시 포인터여야 한다. 

*(p->number)도 마찬가지. ()안의 변수가 가르키는 값 이니 때문에 ()에는 주소가 있어야 하고
즉, 포인터야 한다. 

포인터를 멤버로 가질수도 있다.

#include <Stdio.h>
#include <stdlib.h>

struct date {
int mon;
int day;
int year;
};

struct student{
int number;
char name[10];
double height; 
        struct date *pointer; // 구조체를 가르키는 포인터
};

void main()
{
struct date d = {9, 11, 1987};
struct student s={20060603, "kim", 163.5};

s.pointer = &d; // 포인터에 구조체를 연결.

s.number = 20060603;
strcpy(s.name, "김동규");
s.height = 163.5;

printf("학번 : %d\n", s.number);
printf("이름 : %s\n", s.name);
printf("키 : %f\n", s.height);
printf("생일 : %d년 %d월 %d일 \n", s.pointer->year, s.pointer->mon, s.pointer->day);
}

student 안에 있는 date를 가르키는 포인터를 생성하고 그 주소를 연결한다.


문자열 배열과 문자 포인터의 차이점.
초기화에서 직접 문자열을 써 주는 경우에는 문제가 없다.
문제는 배열은 name[], 포인터는 *name 인데 키보드로 입력 받는 경우
포인터로 사용하는 경우 가르킬 곳이 없다는 것이다.

struct test{
char name[10];
};

scanf("%s", s.name);는 가능하지만 


struct test{
char *name;
};

scanf("%s", s.name);는 불가능. 사실 당연한거겠지, 포인터에 키보드로 입력 받아 넣는다는게 말이 되나;
포인터에는 주소밖에 들어가지 않으니.

따라서 구조체에서 문자열을 저장하고 변경하는 경우 배열을 사용한다.


구조체를 함수의 인수로 넘기기.

int test(struct student s);
{
  .
  .
}
struct student라는 자료형으로 s라는 변수명으로 사용한다 라고 하면 되지.   int s 처럼. 
구조체는 변수라고 봐도 무관할테니 말이다.


팁? 때문에 함수의 인자로 넘기는 경우. 일반 변수처럼 복사되어 넘어간다. 실제로 넘어가는게 아니다. 
문제는 그런 구조체들을 단순히 비교만 하는 함수를 사용하는 경에서, 만약 구조체가 크다면
단지 비교만을 위해서 큰 구조체들을 복사해서 비교하는 것은 불필요하다.

따라서 구조체포인터를 이용해서 값을 비교하는게 효과적이다.
test(s1, s2); // 함수로 넘겨주고

int test(struct student *p1, struct student *p2 .....)
{
.
.
}

이런한 방법에서 문제점은 이렇게 주로를 넘겨주는 경우 실제 원본의 값이 변경될 수도 있다는 것이다.
이러한 실수를 방지하는 방법으로 const를 사용하는데

const는 자료형과 변수명 사이에 사용하면.
int const *p;    *p의 값을 변경하는 것을 막는다. 

자료형 앞에 사용하는 경우 
const int *p;    *p가 가르키는 곳, 즉 p의 주소가 변경되는 것을 막는다.
 





유익한 정보가 되셨다면 아래의 추천도 부탁드려요 ^-^