ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 구조체 - 바로 실행해보면서 배우는 C언어
    CS/C언어 2020. 1. 5. 23:06

    구조체를 사용하면 자료형이 다른 여러 개의 변수를 편리하게 사용하고 관리할 수 있다.

    사용자가 직접 자료형(사용자 정의 자료형)을 만들어 하나 이상의 변수를 묶어서 관리한다.

    ex) 회원정보 저장, 관리 - 아이디(문자열), 나이(숫자), 전화번호(숫자) 등

     

    구조체 정의하고 사용하기

    구조체는 보통 main 함수 전에 선언한다. (main 함수 안에 선언하면 main 함수 안에서만 사용할 수 있다.)

    구조체 안의 변수들은 '구조체 멤버'라고 한다.

    구조체 선언만으로는 바로 사용할 수 없고(자료형만 선언한 것이기 때문),

    main 함수 안에서 선언한 구조체 자료형을 가진 변수를 선언한 후 사용할 수 있다.

     

    구조체 선언하기

    struct 구조체이름 { 구조체 멤버들 }; 형태로 선언하고,

    main 함수에서 struct 구조체이름 변수이름; 과 같이 선언한 후 사용한다.

    struct student {
    	char name[15];
    	int student_id;
    	int age;
    	char phone_number[14];
    }; //구조체 선언
    
    int main(){
    	struct student goorm; 
    	//자료형이 student 구조체인 goorm 변수 선언
    
    	scanf("%s", goorm.name);
    	scanf("%d", goorm.age);
    	//변수이름.구조체멤버이름을 통해 구조체멤버에 접근할 수 있다
    
    	return 0;
    }

    구조체 단위로 묶어서 처리하면 관리가 편하고 가독성도 높일 수 있다.

     

    구조체 멤버의 초기화

    main에서 구조체를 선언하면서 구조체 멤버에 값을 대입해 초기화할 수 있다.

    멤버 연산자. 와 중괄호{}를 사용한다.

    int main(){
    	struct student codigm = { .age = 20, .phone_number = "010-1234-5678" }; 
    	//( .멤버이름 = 값 }으로 초기화
    	struct student goorm = { "구름이", 2020110049, 21, "010-4567-8910" };
    	/*
    	멤버이름을 적지 않고 초기화
    	(구조체 정의했던 순서대로 값이 들어감. 값을 넣어주지 않은 멤버는 0으로 초기화 됨.)
    	*/
    	return 0;
    }

     

    typedef를 이용한 구조체 선언

    위에서 언급한 선언방법 외에도,

    typedef 키워드를 사용해 구조체를 편리하게 선언할 수 있다. typedef를 사용하면 main 함수에서 구조체를 선언할 때 매번 struct를 써줄 필요가 없고 구조체 이름도 생략할 수 있다.

    typedef는 C언어에서 자료형 이름을 새롭게 붙일 때 쓰는 키워드로,

    typedef를 사용할 때에는 구조체 별칭이 필요하다.

    구조체 별칭은 구조체를 정의할 때 중괄호 뒤에 써주면 된다.

     

    구조체 이름을 생략하지 않는 경우

    구조체 이름과 별칭을 둘 다 쓸 때는 일반적으로 구조체 이름 앞에 _를 붙인다.

    typedef struct _Student {
    	int age;
    	char phone_number[14];
    } Student;
    
    int main(){
    	Student goorm;
    
    	return 0;
    }

     

    구조체 이름을 생략하는 경우 (익명 구조체)

    typedef struct {
    	int age;
    	char phone_number[14];
    } Student;
    
    int main(){
    	Student goorm;
    	
    	return 0;
    }

    구조체 이름을 생략하고 별칭만 사용하는 익명 구조체로 선언할 수도 있다.

    익명 구조체도 다른 구조체와 문법은 같으므로 멤버에 접근할 때는 멤버 연산자. 을 이용하면 된다.

     

    구조체 배열

    구조체도 다른 자료형처럼 배열에 담아 관리할 수 있다.

    구조체 배열은 일반 배열처럼 선언하면 된다.

     

    구조체 배열의 선언 및 초기화

    
    typeof struct {
    	char name[30];
    	int age;
    } Student;
    
    int main(){
    	Student goorm[3] = { {.name = "Harry"}, {.name = "Hermione"}, {.name = "ron"} };
    	
    	goorm[0].age = 10;
    	goorm[1].age = 10;
    	goorm[2].age = 10;
    
    	return 0;
    }

    구조체도 문자열은 선언과 동시에 초기화해야 한다. 정수인 나이는 선언 후 값을 대입할 수 있다.

     

    구조체 포인터

    구조체 포인터 : 구조체를 가리키는 포인터 변수

    struct student *p;

    struct student 부분이 자료형이나 마찬가지이기 때문에 위와 같이 선언해준다.

    이 때 p는 구조체를 가리키는 포인터이고, 구조체가 아니다. 헷갈리지 말 것

     

    구조체 포인터 선언하기

    typedef struct {
    	int s_id;
    	int age;
    } Student;
    
    int main(){
    	Student goorm;
    	Student *p;
    	
    	p = &goorm;
    
    	(*p).s_id = 20200105; //괄호 사용
    	p->age = 20; //화살표 기호 사용
    
    	return 0;
    }

    포인터를 사용할 때는 *p.age처럼 바로 사용하는 것이 아니라

    (*p).age와 같이 괄호를 사용해야 한다.

    괄호를 사용하지 않으면

    멤버 연산자. 가 구조체가 아닌 포인터 변수를 구조체처럼 참조하려고 해 오류가 발생하기 때문이다.

    괄호 대신 → 라는 기호를 사용할 수도 있다. 이 기호를 이용하면 괄호를 쓰지 않아도 구조체를 참조할 수 있다.

    괄호를 쓰는 것보다 화살표 기호를 쓰는 것이 더 편리하고 가독성도 좋다.

    *단, 구조체 배열은 포인터로 넘겨받아도 s[i]→kor과 같이 화살표 기호로 참조하지 않으며, 일반적인 구조체처럼 s[i].kor로 참조해야 한다.

     

    중첩 구조체

    구조체 안에 구조체를 선언해 다른 구조체를 멤버로 포함할 수 있다.

    구조체를 중첩해 사용하면 여러가지 정보를 관리하기에 용이하다.

    typedef struct {
    	char name[15];
    	int age;
    } Teacher;
    
    typedef struct {
    	char name[15];
    	int age;
    	Teacher teacher; //Teacher 구조체를 Student 구조체의 멤버로 포함시켰다.
    } Student;
    
    int main(){
    	Student stuent;
    	Teacher teacher;
    	
    	Student.teacher.age = 30; //구조체이름.멤버구조체이름.멤버구조체의멤버이름
    	Teacher.name = "Emma";
    
    	return 0;
    }

     

    자가 참조 구조체

    구조체는 자기 자신을 가리키는 포인터를 멤버로 가질 수 있다.

    자신과 같은 타입의 구조체를 멤버로 가지고 자기 자신을 참조할 수 있다.

    typedef struct {
    	char name[15];
    	int age;
    	sturct Student *p; //구조체 선언이 끝나기 전에 구조체 안에 구조체를 선언했다.
    } Student;

    자기 참조 구조체는 연결 리스트나 트리(자료구조)를 만들 때 사용된다.

     

    구조체와 함수

    구조체를 함수에 전달하기

    구조체를 함수에 인자로 전달할 때는, 포인터로 전달(바로가기)하거나 구조체 자체를 전달(복사)할 수 있다.

    구조체를 전달할 때는 원본 값을 바꿀 필요가 없는 경우에도 주로 포인터를 사용해 전달한다.

    구조체를 복사해 전달하기 위해서는 복사할 공간이 필요한데, 구조체 크기가 커질수록 공간이 많이 필요해 비효율적이기 때문이다.

     

    구조체를 인자로 전달하기

    typedef struct {
    	int s_id;
    	int age;
    } Student;
    
    void print_student(Student s){
    	s.s_id = 2000;
    	s.age = 25;
    
    	printf("%d, %d\n", s.s_id, s.age);
    }
    
    //구조체를 인자로 전달하기
    
    int main(){
    	Student s;
    
    	s.s_id = 1000;
    	s.age = 20;
    
    	print_student(s);
    	printf("%d, %d", s.s_id, s.age);
    
    	return 0;
    }
    
    //출력하기
    
    > 2000, 25
    1000, 20
    
    /*
    구조체를 복사해서 전달했기 때문에
    함수에서 값을 변경해도 원본 값에 영향을 미치지 않는다.
    */

     

    포인터로 전달하기

    typedef struct {
    	int s_id;
    	int age;
    } Student;
    
    void print_student(Student *s){
    	s->s_id = 2000;
    	s->age = 25;
    	
    	printf("%d, %d", s->s_id, s->age);
    }
    
    //구조체를 포인터로 전달하기
    
    int main(){
    	Student s;
    
    	s.s_id = 1000;
    	s.age = 20;
    
    	print_student(&s); //매개변수가 포인터이므로 구조체의 주소값을 전달해야 한다. 
    	printf("%d, %d", s.s_id, s.age);
    
    	return 0;
    }
    
    //출력하기
    
    > 2000, 25
    2000, 25
    
    /* 
    포인터로 전달했기 때문에
    함수를 호출해 구조체 멤버의 값을 변경하면 
    원본 값도 같이 변경된다.
    */

    댓글

Designed by Tistory.