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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /*노드 개수를 박으면 자동으로 개수만큼의 노드를 가진 연결리스트를 싸는 프로그램 *노드에 데이터 넣는 걸 인간이 할지, 알아서 할지는 함수로 조절 한다.*/ #include <stdio.h> #include <stdlib.h> typedef struct Node { int num; struct Node* link; } Node; typedef struct LinkedList { Node* phead; int length; } LinkedList; const int NODE_SIZE = sizeof(Node); void insertNode(Node** pHead, Node* prev, Node* newNode); Node* makeNode(void); int userInput_int(void); LinkedList makeLinkedList(int length); int main(){ int len; LinkedList list0; Node* traveler; printf("how many node?"); scanf("%d", &len); list0 = makeLinkedList(len); printf("만든 연결리스트 길이 %d \n",list0.length); traveler = list0.phead; while(traveler != NULL){ printf("%d \n", traveler->num); traveler = traveler->link; } return 0; } //삽입함수 : 새로운 노드를 연결리스트에 삽입하는 함수다. //1. phead == NULL, prev == NULL : 빈 연결리스트에 삽입 //2. phead != NULL, prev == NULL : 리스트의 가장 앞쪽에 삽입 //3. phead != NULL, prev != NULL : 리스트의 중간 혹은 끝에 삽입. void insertNode(Node** phead, Node* prev, Node* newNode) { if(*phead == NULL){// 빈 리스트에 삽입 *phead = newNode; newNode->link = NULL; } else if(prev == NULL){// 가장 앞쪽에 삽입 newNode->link = *phead; *phead = newNode; } else{// 끝이나 중간에 삽입 newNode->link = prev->link; prev->link = newNode; } } //자기참조 구조체 생성함수 : 데이터를 입력하면 그 데이터를 가지고 연결되지 않은 노드 하나를 생성한다. Node* makeNode(void) { Node* node = (Node*)malloc(NODE_SIZE); node->num = userInput_int(); node->link = NULL; return node; } //정수데이터를 사용자가 입력시킬 때 쓰는 함수. int userInput_int(void) { int temp; printf("만들 노드가 가질 데이터(정수)를 입력하라. "); scanf("%d", &temp); return temp; } //길이를 입력하면 그 길이만큼의 연결리스트를 생성한다. LinkedList makeLinkedList(int length) { int i; Node* phead = NULL; Node* prevNode = NULL; LinkedList linkedList; for(i = 0; i < length; i++){ Node* nowNode = makeNode();//생성 insertNode(&phead, prevNode, nowNode);//삽입 prevNode = nowNode; } linkedList.length = length; linkedList.phead = phead; return linkedList; } | cs |
출력
연결리스트의 생성까지만 만듬.
이제 요기에 노드를 넣고 빼고 바꾸고 찾는 함수들을 만들 예정.
조언대로 책을 안 보고 걍 인터넷에서 ppt 좀 보고 만들었습니다.
그러니까
지금은 아니지만 중대한 문제가 될 수 있는것
거슬리거나 맘에 안드는 것 등을 지적해주시길
지적충 등판좀!
typedef struct Node { ... } Node; 식으로 tag name과 redefined name을 같게 하는 건 별로 권장하지 않음. typedef struct tagNode { ... } Node; 식으로 구분할 것.
LinkedList 구조체 설계에서 Node*는 struct Node *로 고쳐. (struct tagNode로 했다면 struct tagNode *) struct를 붙이고 안 붙이는 건 큰 차이가 있다. 전자는 Node 정의를 무조건 앞쪽에다가 해야하는데 struct Node *로 쓰면 struct Node 정의가 뒤에 와도 돼.
같으면 뭐가 안 좋나요?
구조체 tag name은 설령 선언만 되고 정의는 되지 않았어도 포인터로 참조해서 쓸 수 있거덩. 예를 들어 struct xxx *yyy; 식으로 쓰고 struct xxx { ... }; 안 써도 컴파일되고 잘 쓸 수 있다. 물론 yyy->xxx 같은 거 하려고 들면 에러가 나겠지만. 포인터로써는 유효해.
같아도 딱히 상관은 없는데 애매모호하게 하지 말고 확실하게 태그 이름과 타입 이름을 구분짓자는 의미임.
이건 코딩 스타일의 문제기도 한데, 많은 프로그래머들이 태그 이름과 타입 이름은 구분해 주거덩. 윈도우 API 구조체만 봐도.
그리고 insertNode 함수 불필요한 분기 들어있는 거 알아?
음 그렇군요.
*phead == NULL이든 아니든 가장 앞쪽에 삽입할 때는 똑같이 하면 돼. newNode->link = *phead; 에 의해 어차피 *phead가 NULL이 아니면 NULL이 아닌 값이, NULL이면 NULL이 들어갈텐데.
뭐를 빼야하죠?
허 그렇겠네요 저건 ppt에 있던 건데 ㅋ(물론 최초로 내가 쓴 코드는 더 더러웠슴)
http://pastebin.com/Rizuq3PH
이거 먼 툴이야 ? 디게 깔끔하게 나오네 ?
심지어 prev도 필요가 없어. 왠줄 알아?
phead에다가 &(원하는항목->link) 집어넣으면 되잖아.
나는 insertNode 함수가 복잡해 보인다 그냥.
@쏜씨
http://colorscripter.com/
복붙만 하면 됨요
insertNode를 호출할 때 &phead;를 넣으면 처음에, &item;->link에 넣으면 그 item 다음에 삽입하는 게 되지 ㅋㅋ
응? ;가 왜 붙었지. 다 빼고 보길.
makeNode함수에서 입력 받는 행위를 하는거 자체보다, 파라미터로 넘기는 형태가 좋지 않을까 싶은데
구리고 중요한 free 함수 호출을 하지 않은건 옳바르지 않을거 같앙
입력 대신 makeNode함수의 파라미터로 넘기기요?
굳이 안해도 됨. 저런 예제 수준의 코드에선 ㅋㄷ 물론 습관을 잘 들이는 건 중요하지.
free는 나중에 삭제 함수 만들 때 해볼 생각...
Memory Leak이라는 건 프로그램이 돌아가고 있을 때 발생하는 거지 프로그램이 바로바로 종료되는 경우라면 굳이 free 필요 없음.
ㅇㅇ 삭제 함수도 아직 안 만들어져 있기도 하고.
츄럴 // 응 그냥 개인적인 스탈인부분이얌 . 사실 저 함수의 이름은 makeNode 라 보다 makeNoeAndInputInt 랄까 ?
makeNodeAndInputInt 오타 ㅋ
나는 낙타를 좋아하니까 make_node_and_input_int
makeNodeFromInput() 이라고 하면 될 듯 ㅋ
고것구 괜찮구 ㅋㅋ
좋네요 ㅋㅋ
난 태그 통일하는게 좋다고 주장.
어차피 class ~~~{ }; 랑 별반 하는짓 차이도 없는데 후자는 네이밍 하나만 쓰면서 네이밍 둘 쓰는거 단지 네이밍테이블 낭비일 뿐.
전혀 합리적이지 않음.
컴파일러, 디버거에 따라선 tag name과 redefined type name이 같을 경우 둘을 구분하지 못하는 문제가 있는 경우가 있다고 하죠. 대표적인 케이스가 Windows API 구조체들의 경우인데 Windows API 구조체들이 죄다 그 형식(tag name과 typedef name을 구분)인 건 Visual C++ 구버전(4.0 이전)에서의 문제 때문이고요.
어차피 struct랑 typedef name의 namespace는 서로 다르기 때문에 전혀 naming table 낭비가 아니죠.
그래서 구분하나 안하나 사실상 차이가 없는 셈인데(namespace가 다르므로) 다만 구분을 안할 경우엔 일부 환경에서의 호환성 문제가 있을 수 있으므로 구분해 주는 게 이상적이죠.
져도 병신, 이겨도 병신이라면 이기는 병신이 되라고들 하죠.
이건 병림픽에서의 예지만, 약간 말을 바꾸자면, 구분해도 구분 안해도 똑같다면 호환성 문제가 없는 쪽이 낫겠죠?
낭비 맞음. 요즘 누가 VC++ 4.12 같은거 씀?
그거 구분해서 쓰는데 내 머리는 낭비아님?
어차피 tag name과 type name namespace는 서로 다르잖아요.
이름짓는거 얼마나 귀찮은데 그런걸함. 그럴꺼면 하위 호환성 살려서 람다도 쓰지 말지 그래.
성님 말씀대로 굳이 그럴 거라면 typedef struct { } Node; 식으로 쓰는 게 차라리 낫죠. tag name을 아예 안 써버리면 오히려 더 덜 낭비죠.
귀찮은거 안해도 되는쪽으로 갈아탈수 있으면 얼른 얼른 갈아타는게 나음.
응 나도 그걸 바라.
가장 바람직한건 class 로 통일하고 public default 가 되는거지.
네. 이상적이라면 저거죠. typedef struct Node { } Node; 는 어정쩡해도 너무 어정쩡하죠.
tag name을 쓸 거면 구분을 지어주던가. 네임스페이스 낭비가 싫은거면 아예 tag name을 안 쓰는 게 오히려 더 덜 낭비죠.
ㅅㅅㅅ가 늙으면 알게 돼.
던가 => 든가
늙어서 좋은건 뭐가 귀찮은건지 분명하게 보인다는거야
ㅋㅋㅋ 늙으면 자기 자신이 잘 안 바뀌게 되죠. 소위 말하는 꼰대가 되어 감 ㅋㅋㅋ
아닝 그건 내경우랑 상관없음 누구 경운진 모르겠지만..
제가 이렇게 발악발악 우기는 것도 꼰대 기질이 있어서일듯 ㅋㅋㅋ 20대인데 벌써부터 꼰대라니 ㅠㅠ
성님은 10대시잖아요 ㅋㅋㅋ 20대한테 성님 소리 듣는 코세 청소년님 (퍽)
아 그룹챗에서 메이플스토리 이야기 한다 미치겠다.
메이플스토리 이야기 자꾸 들으면 히스테릭해져 ㅡㅡㅋ
메이플스토리 극혐 ㅋㅋ
MMORPG는 바람의 나라부터 쭉 싫어했음.
뭐가 좋다고 MMORPG 함. 레벨이라는 숫자 쪼가리 하나 올리는 게임에 불과한 것을 ㅡㅡㅋ 머리가 좋아지는 것도 아니고 그냥 몹 잡으려고 손가락 노가다 뛰는 거에 불과한 것을 ㅡㅡㅋ
뭐 똑같은 시간 낭비긴 하지만 체스 같은 건 머리라도 좋아짐.
자체 교정: 발악발악 => 바락바락. 느낌상 바락바락이 그냥 흔히 쓰는 표기여서 이게 틀리고 발악발악 같아서 교정했었는데 오버 교정이었네 ㅡㅡㅋ
로그라이크 해보셈 ㅋ
공감함 : ) 근데 재밌는 MMO들도 좀 있긴함.
글고 더 재밌게 만들수도 있긴함 : )
insertNode를 ㅅㅅㅅ가 말한대로 고치면 되긴 하는데 방향이 반대로 됨... 이래도 괜찮은가??