Pointer(포인터)를 이용해서, 문자열을 알파벳 순서로 정렬(sort)하는 예제 코드 입니다.


어제 포스팅한 single linked list의 3번째 예제처럼 포인터의 포인터(포인터의 주소)를

전달하여, swap함수에서 두 자료를 교환하고 있습니다.


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
// swap 함수 2016/6/1
 
void swap(char **a, char **b);
void sort(char *ary[], int cnt);
 
 
void swap(char **a, char **b)
{
    char *temp;
    temp = *a;
    *= *b;
    *= temp;
}
 
//sort a, b, c...
void sort(char *ary[], int cnt)
{
    int i, j, min;
    for (i = 0; i < cnt - 1; i++)
    {
        min = i;
        for (j = i + 1; j < cnt;j++)
        {
            if (strcmp(ary[min], ary[j]) > 0)
                min = j;
        }
        swap(&ary[min], &ary[i]);
    }
}
 
void main(void)
{
    int i;
    char *arr[] = { "abecd""ddbeeddd""cedvae","hhxxz" };
    sort(arr, 4);
    for (i = 0; i < 4; i++)
    {
        printf("%s, ", arr[i]);
    }
    printf("Good bye\n");
}
 
cs


Posted by 고무함지
,



C언어를 배우면서... 가장 어려운 것이 포인터이고...


그리고, 이 포인터를 쓰는... 링크드 리스트(Linked List)도 역시나 어렵습니다.


저도 공부하면서... 가장 실수를 많이 한 것이 링크드 리스트인데...




공부해보니 특히나... head 노드 변수를 어느 위치에서 선언하느냐에 따라 


구현 방식의 차이가 있더군요.


이러한 방식은 아래 3가지로 구분할 수 있습니다.




1. 전역 변수로 head를 선언한다.


2. main의 로컬 변수로 head를 선언, 

  링크드 리스트 생성 함수에서, return형으로 Node의 Point를 사용하는 경우


3. main의 로컬 변수로 head를 선언, 

  링크드 리스트 생성 함수에서, return형 없이, Head Node의 주소를 입력 받는 방법



그럼 예제로 설명드리겠습니다. 이 예제는 single linked list로 구현했고, Insert Node를 하면

가장 앞에 새로운 값이 저장되도록 작성되어 있습니다.



< 사진 출처 = https://wiki.cs.auckland.ac.nz/compsci105ss/index.php/Linked_Lists >



1. 전역 변수로 head를 선언한다.


먼저, 아래 Node_T * head; 를 보면... main함수 외부에 전역 변수로 선언되어 있습니다.

그러므로, 이 코드에 있는 어떠한 함수에서도 바로 head에 접근이 가능합니다.


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
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
// linked list 
// case 1 : use global variable for Head
 
typedef struct Node {
    int data;
    struct Node * next;
}Node_T;
 
Node_T * head;
 
void InsertNodeAtHead(int value    );
void PrintNode(void);
 
void InsertNodeAtHead(int value    )
{
    Node_T * temp = (Node_T*)malloc(sizeof(Node_T));
    temp->data = value;
    temp->next = NULL;
 
    if (head != NULL)
        temp->next = head;
    
    head = temp;
}
 
void PrintNode(void)
{
    Node_T * temp = head;
    printf("List :");
    while (temp != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
 
int main(void)
{
    int n, x, i;
    head = NULL;
    printf("How many numbers?");
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        printf("enter number:");
        scanf("%d", &x);
        InsertNodeAtHead(x);
    }
    PrintNode();
    printf("Good Bye!");
 
}
 
cs





2. main의 로컬 변수로 head를 선언, 

  링크드 리스트 생성 함수에서, return형으로 Node의 Point를 사용하는 경우



두번째로는... Node_T * head가 main함수 안쪽으로 가서

main함수의 지역변수로 사용되었습니다.


그러므로 다른 함수에서 head를 받기 위해 parameter로 전달을 해야합니다.

그리고 다시 return으로 head를 받아와야 합니다.


Node_T * InsertNodeAtHead(Node_T * head, int value)


head = InsertNodeAtHead(head, x);



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
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
// linked list 
// case 2 : use local variable for Head
 
typedef struct Node {
    int data;
    struct Node * next;
}Node_T;
 
Node_T * InsertNodeAtHead(Node_T * head, int value);
void PrintNode(Node_T *node);
 
Node_T * InsertNodeAtHead(Node_T * head, int value)
{
    Node_T * temp = (Node_T*)malloc(sizeof(Node_T));
    temp->data = value;
    temp->next = NULL;
 
    if (head != NULL)
        temp->next = head;
 
    head = temp;
    return head;
}
 
void PrintNode(Node_T * node)
{
    Node_T * temp = node;
 
    while (temp != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
 
int main(void)
{
    int n, x, i;
 
    Node_T * head;  // Head node is local variable
 
    head = NULL;
    printf("How many numbers?");
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        printf("enter number:");
        scanf("%d", &x);
        head = InsertNodeAtHead(head, x);
    }
    PrintNode(head);
    printf("Good Bye!");
 
}
cs


3. main의 로컬 변수로 head를 선언, 

  링크드 리스트 생성 함수에서, return형 없이, Head Node의 주소를 입력 받는 방법


마지막으로... 두번째에서 확인한 파라미터로 head를 전달하고, return으로 head를 다시

받는 형태를 좀더 간략히 하기 위해, 파라미터로 전달시 head의 주소로 전달하여

InsertNodeAtHead()함수에서 바로 head를 접근할 수 있도록 합니다.


void InsertNodeAtHead(Node_T ** head, int value);


// 포인터의 포인터이므로, &head로 주소 연산자를 하나 붙여줍니다.

InsertNodeAtHead(&head, x);



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
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
// linked list 
// case 3 : use local variable for Head, 
// and don't use parameter for Insert
 
typedef struct Node {
    int data;
    struct Node * next;
}Node_T;
 
void InsertNodeAtHead(Node_T ** head, int value);
void PrintNode(Node_T *node);
 
void InsertNodeAtHead(Node_T ** head, int value)
{
    Node_T * temp = (Node_T*)malloc(sizeof(Node_T));
    temp->data = value;
    temp->next = NULL;
 
    if (head != NULL)
        temp->next = *head;
 
    *head = temp;
}
 
void PrintNode(Node_T * node)
{
    Node_T * temp = node;
 
    while (temp != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
 
int main(void)
{
    int n, x, i;
 
    Node_T * head;// Head node is local variable
 
    head = NULL;
    printf("How many numbers?");
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        printf("enter number:");
        scanf("%d", &x);
        InsertNodeAtHead(&head, x);
    }
    PrintNode(head);
    printf("Good Bye!");
}
 
cs



코드 참고 : <mycodeschool : https://www.youtube.com/channel/UClEEsT7DkdVO_fkrBw0OTrA >



Posted by 고무함지
,

포인터 사용시 주의해야할 것은 포인터 변수의 크기를 알아 내는 것입니다.

크기를 알아야 자료 복사나, 메모리 할당등을 할 수 있기 때문입니다.


여러가지 예제로 확인해보니, 주의할 점이 보이더군요.


1. 포인터 변수 자체의 크기인 경우


2. 포인터가 가르키는 것이 배열인 경우 그.. 배열의 크기가 됨.


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
void main(void)
{
    int arr[3][4= { {1,2},{3,4,5},{6,7,8,9} };
    //0행 : 1, 2, 0, 0
    //1행 : 3, 4, 5, 0
    //2행 : 6, 7, 8, 9
    printf(" %d,", arr[2][1]);   
    // 배열 2행 1열의 값은 (0열 다음값인) -> 7
 
    printf(" %d,"*(*(arr+2)+1) );
    // 배열 2행 1열의 값은 역시 -> 7
 
    printf(" %d,"sizeof(arr));
    // arr은 전체 배열의 크기인 3x4x4byte = 48
 
    printf(" %d,"sizeof(arr+0));
    // 이건 arr과 동일한 결과가 나올 것으로 예상했으나, 명시적으로 0번째 행을 
    // 지칭 하기 위해서 + 0 을 하는 것임. 0번 행의 포인터이므로 .. 포인터의 크기는 4byte
 
    printf(" %d,"sizeof(arr+1));  // 역시 포인터의 크기 -> 4
    printf(" %d,"sizeof(arr+2));  // 포인터의 크기   -> 4
    printf(" %d,"sizeof(*(arr+2))); 
    // 포인터가 가르치는 곳(*연산자)이므로... 행의 크기 4x4byte = 16
 
    printf(" %d,"sizeof(*(arr + 2)+1));  
    // 포인터의 포인터가 가르키는 곳(**)이므로... 열의 하나의 크기 -> 4 byte
 
    printf("Good bye");
    // 결과  7, 7, 48, 4, 4, 4, 16, 4,
}
 
cs


Posted by 고무함지
,