프로그래밍 프로젝트 (구조체)

13장 구조체

구조체 : 서로 다른 자료형을 하나로 묶는 구조

자바 object_oriented랑 굉장히 비슷.

구조체 선언 : struct라고 붙어있으면 다 구조체다.

구조체 타입의 선언은 변수 선언이 아니다. 이런 타입이 있다고 그저 정의하는 것 뿐.(메모리 공간을 받아오는 작업을 하진 않음. 물론 컴파일러 내에서 저장하기는 함. 하지만 변수로서 직접 컨트롤 할 수 있는 메모리 공간 할당은 아니다)

구조체 변수 선언

  • 구조체 정의와 구조체 변수 선언은 다르다.

구조체를 정의한 다음에

main function 안에 구조체 변수를 선언해야한다. ex) 구조체 struct student를 정의했다면

struct student s1; 이런 식으로 구조체 변수를 선언해야한다.

s1이 가지게 되는 메모리 공간. 그 사이의 갭이 없다. 즉 앞에서 부터 순서대로 쭉 다들어간다. 필요한 사이즈에 대해서 통채로 메모리 공간을 할당받게 된다.

구조체 초기화

struct student s1 = {24, “Kim”, 178,9};

구조체 멤버 참조

.을 사용한다. 구조체에서 멤버를 참조할 때 사용하는 연산자이다.

s1.number = 26; // 정수 멤버 strcpy(s1.name,”Kim”); // 문자열 멤버 s1.height = 183.2; // 실수 멤버

구조체를 멤버로 가지는 구조체

구조체를 멤버로 가지는 구조체 (구조체 안에 구조체 포함)

s1.dob.year = 1983; (s1이라는 구조체 변수 선언 이후 dob(구조체 안에 있는 구조체 원형)의 멤버 값을 정의하는 것)

구조체 변수의 대입과 비교

image

같은 구조체 변수끼리 대입은 가능하지만 비교는 불가능하다.

구조체 배열 선언

구조체 배열 선언 , 구조체 배열 초기화 -> 2차원 배열처럼. 멤버들 리스트를 적용해서 채워넣을 수 있다.

구조체 배열 예제

%s -> 받게 되는 입력은 주소값이어야 한다.

구조체와 포인터

구조체를 가리키는 포인터

ex) struct student *p

struct student s = {20070001, "홍길동", 180.2};

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);

괄호를 잘 쳐줘야해 (*p).number .의 우선순위가 높기 때문이다.

구조체 student를 가리킬 수 있는 포인터

-> 연산자

p가 가리키는 구조체 멤버에 접근하려고 할 때, 사용한다. p는 주소를 저장하고 있다. 얘가 가리키고 있는 메모리 공간은 구조체변수이다. 그 구조체 변수에서 정의되어 있는 멤버들 이름을 적는다는 걸 잊지마라

*printf(“sdfsdfSDF”,p->number, p -> name, p->height); 즉 (p).number == p->number ** 즉

image

포인터를 멤버로 가지는 구조체

포인터를 멤버로 가지는 구조체.

image

자체 참조 구조체

2018-04-19 3 43 22

c언어 -> 자체 참조 구조체 가능하게 해놓음. Q)안에다가 정의를 계속하면 안의 변수들이 사이즈를 결정하지 못하니까. 문제가 생기는 거 아니야 ? 자기참조를 써서 point 변수가 가리키는 비트 정해져있음. 오히려 똑같은 구조체 타입을 써도, 고정되어있는 메모리 공간을 할당해야한다는 걸 컴파일러에게 알려야함

struct student *first = NULL; struct student *current = NULL;

first = & s1; s1.next = &s2; s2.next = NULL; s1이 next로 s2를 가리키게 된다.

이렇게 만든게 링크드 리스트. current라는 포인터 하나만 써서 링크드 리스트 안에 있는 element들을 하나식 탐색해서 넣게 된다.

메모리 공간에서 주소를 알 수 있는 방법 -> 메모리 주소는 무조건 next를 봐야해 (따로 저장해놓지 않은 이상)

즉 길이가 길어지면 원하는 메모리 공간에 접근하는게 시간이 오래 걸릴 수 있어. 그럴 때. 앞에서 찾는 애들 말고 뒤에서 부터 찾는 애들을 만든다면, 가장 마지막에 있는 애들을 먼저 찾고 싶다면 ? 역 방향으로 접근하고 싶다. 그러면 포인터 두개 쓰면 된다. forward, backword 두 개를 만들면 된다. before에는 전에 있는 엘리먼트들을 가리키면 된다. 그러면 자연스럽게 왔다갔다 가능

binary tree로 만든다면 ? root가 하나 있고 (값을 저장하는 공간,메모리 ) 내려가면서 tree형식으로 나아감. 몽땅다 바이너리 트리

가장 맨 위 - 멤버값들이 젖아된다. 구조체라면 멤버들 할당하는 지점 노드. 노드 간의 얘네들을 연결하는 걸 엣지. 노드 두개를 연결 할 때, 화살표로 그려놓은 건. 가리키고 있다는 이야기다. 구조체로 바이너리 트리를 만든다면, 구조체 멤버변수하고 포인터 하나는 얘를 가리키고 재를 가리키고 링크의 갯수 만큼 포인터를 만들어주면 된다.

노드라는 스트럭쳐 데이터 타입을 일관되게 사용한다면 구조체 타입의 포인터를 똑같이 사용하게 된다면, 자체참조구조체 그걸 확장해서 트리를 만드는게 가능 .

left pointer , right pointer. 이렇게 왼쪽오른쪽 참조 가능

이게 연결 되면 그래프다. 제약조건이 아예 없는 노드 간의 연결상태를 나타낸게 그래프다.

노드마다 가리켜야할 다른 엘리먼트들의 갯수가 2개를 넘지 않는다. 그래프를 사용하기 시작하면 하고 싶은 대로 다 표현할 수 있다. 그래프 데이터 스트럭쳐 굉장히 중요하다. 실제로 받게 되는 데이터들은 굉장히 그래프 스트럭쳐로 표현 가능하다. 이산적인 데이터를 표현하는 제일 표현력이 높은 데이터스트럭쳐기 때문이다. 아무거나 만들 수 있는 데이터 구조를 사용할 때, 링크되는 부분이 제약이 없다.

최대 사이즈 정해놓고 배열을 하면 된다. 또는 저기 안에 들어가는 참조하려고 하는 포인터들의 링크드 리스트를 다시 가지고 있어도 된다.

무한대로 우리가 링크를 조절해서 어떻게 만들까.

IPCP 같은 문제 풀려고하다보면 다 그래프스트럭쳐다. 그래프를 만들어보는 연습은 어느 정도 해봐야 한다.

그 다음에 실용적인 거 뭐가 있냐면

링크드 리스트 만들고, 어레이로 따로 만들어서 리스트로 접근안하고 어레이로 접근하는 이런 방식 들 다양하게 섞어서 쓰는 구조체도 만들 수 있다.

큰 모델을 만든다고 하면 얘끼했던 내용들 거의 다 하게 될 것이다.

구조체와 함수

  • 구조체를 함수의 인수로 전달하는 경우
    • 구조체의 복사본이 함수로 전달하게 된다.
    • 만약 구조체의 크기가 크면 그만큼 시간과 메모리가 소요된다.

**구조체는 call by value로 들어온다. **구조체 멤버 갯수가 많아져서, 많은 양을 카피된다면. 함수가 너무 많이 불러온다면 메모리가 모자른 경우도 생김

구조체 포인터를 만들고, 그 구조체 변수들의 주소값을 넘겨주게 되면, 방금 말한 사실들을 피할 수 있다.

call by reference로 직접 컨트롤 해줘야 한다.

  • 구조체의 포인터를 함수의 인수로 전달하는 경우
    • 시간과 공간을 절약할 수 있다.

구조체를 반환하는 경우

  • 복사본이 반환된다.

구조체의 복사본이 반환되기에 비효율적이다. call by value이다. 이것도 피하려면 주소값을 어떻게 넘길까?

구조체 변수가 안에서 생성되엇기에 ,s를 통째로 넘기고 싶은데, s의 주소를 넘기면 안된다. 날아간다. 그러니까 s를 넘길 목적이었다면 파라미터로 주소를 받아서 왔어야 한다. 그렇게 해서 밖에서 만든 우리가 접근 가능한 메모리 공간에다가 어떤 값을 저장하도록 함수를 구현하면 되는데, 동적할당 써도 된다. 공통으로 사용할 영역에다가 공통으로 할당 받기에, 어디서 써도 상관 없다.

memory allocation -> 개발자가 다 컨트롤. 메모리 문제 써야 되는 경우는 대부분 항상 프로그램 시작 부터 종료 될 때 까지 유지해야하는 데이터 스트럭쳐를 위해서는 괜찮다. 그게 아니라 임시적으로 사용하는 애들은 메모리 어로케이션은 안쓰는게 편리하다.

열거형 (enumeration)

구조체랑 비슷한 타입의 데이터 생성 키워드

enumeration 은 필수적이라고 보긴 어려운 데이터. 사용하기 편한거지 얘를 꼭 써야하는 상황이 생기지는 않는다. enum이란 키워드 사용 enum 태그_이름{값1,값2, ...}

작은 값부터 하나씩 증가시키면서 아이디를 할당시켜준다.

아무것도 안쓰면 default값부터 하나씩 증가시켜준다.

enum을 쓰는건, #define을 그대로 대신한다고 보면 된다.

typedef

  • typedef은 새로운 자료형(type)을 정의(define)

  • C의 기본 자료형을 확장시키는 역할

다른 사람들이 볼 때는 readablity가 떨어질 수 있다.

typedef와 #define을 비교

  • 이식성을 높여준다
    • 코드를 하드웨어에 독립적으로 만들 수 있다.
  • #define을 이용해도 typedef와 비슷한 효과를 낼 수 있다.

  • 문서화의 역할도 한다

참고자료

프로그래밍 프로젝트

0%