qsort() 문자열 정렬 관련 질문
글쓴이: 야구볼까축구볼까@Naver / 작성시간: 수, 2017/03/29 - 10:37오후
입력받은 문자열을 qsort함수를 이용해 정렬하려고 하는데 제대로 정렬되지 않습니다. 무엇이 문제일까요?
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SIZE 10 int compare_string(const void *first, const void *second) { return (strcmp((char*)first, (char*)second)); } int input_data(char **arr) { char string[200]; char *token; int arr_size; gets(string); token = strtok(string, " "); arr[0] = _strdup(token); arr_size = 1; do { token = strtok(NULL, " "); if (token == NULL) break; arr[arr_size++] = _strdup(token); } while (1); return arr_size; } int main() { char **arr; int arr_size; int i; arr = (char**)malloc(sizeof(char*) * MAX_SIZE); arr_size = input_data(arr); qsort((void*)arr, arr_size, sizeof(arr[0]), compare_string); for (i = 0; i < arr_size; i++) printf("%s ", arr[i]); free(arr); return 0; }
입력 : zoo apple car banana melon
원하는 출력 : apple banana car melon zoo
Forums:
#include <stdio.h>
친절하고 설명 감사합니다!!!
친절하고 설명 감사합니다!!!
함수의 동작원리도 제대로 이해안하고 그냥 가져다 쓰다 보니 이런 문제가 나오네요;;
그럼 한 가지 더 궁금한 점이 있습니다!
배열을 위와 같이 동적 할당하지 않고 2차배열로 선언해서
비교 함수를 질문했던 방식으로
하면 정상적으로 정렬되는 이유는 무엇인가요?
비교함수에 들어가는 원소, 즉 first, second에 들어가는 값이
동적할당한 배열과 직접 선언한 2차원 배열이 달라서 그런건가요?
C언어에서 배열과 포인터의 관계는 오묘하기
C언어에서 배열과 포인터의 관계는 오묘하기 그지없습니다.
1차원 배열을 쓸 때는 그 차이를 의식할 필요가 거의 없으며 어지간하면 프로그래머가 바라는 대로 동작합니다.
2차원 배열부터는 얘기가 달라집니다.
char **arr
와char array[5][10]
을 비교해 보면, 우선 전체적인 메모리 구조부터 다르지요.전자는 우선
arr
가char *
의 배열을 가리키고, 그 배열의 각 원소가char
의 배열을 가리키는 구조입니다. 실질적으로char
타입의 원소를 접근하기 위해서는 두 번의 포인터 역참조가 필요한 구조이지요.후자는 5 × 10바이트의 연속된 메모리 공간입니다. 이 구조는
char *
타입의 어떤 포인터도 저장하고 있지 않습니다.여기까지 이해가 잘 안 되신다면, 종이를 한 장 가져오셔서 두 경우에서 메모리가 어떻게 할당되어 어떻게 가리키고 있는지 그려 보세요.
qsort
는 매개변수가 어떤 포인터인지 알 수 없으므로(void *
로 캐스팅 되어 들어오니까요.) 그 포인터에 원소의 크기(셋째 매개변수)의 배수를 더하여 각 원소의 주소를 얻습니다.arr
의 경우 원소의 크기는sizeof(char *)
일 것이고,array
의 경우는 10이겠죠.arr
의 값에sizeof(char *)
를 한 번 더해 봤자arr
가 가리키는char *
배열의 둘째 원소의 주소일 뿐이죠. 굳이 타입으로 나타내자면char **
입니다. 한 번 역참조해야strcmp
에 넘겨줄 문자열 주소가 나오는 겁니다.반면에
array
의 값에 10을 더해주면 앞서 말씀드린 5 × 10바이트의 연속된 메모리 공간의 앞에서 10바이트 지점의 주소가 됩니다. 바로"apple"
이 있는 주소이지요. 사실 그 타입은 엄밀히 따지면char (*)[10]
라고 할 만 합니다만, 그 값은strcmp
에 넘겨줄 수 있는 문자열 포인터 그대로이기 때문에char *
로 강제 변환하여 고스란히 쓸 수 있습니다.설명하기도 복잡하네요. 원래
&arr[1]
와&array[1]
의 예를 들어 가면서 C언어의 배열-포인터 변환에 대해서 본격적으로 설명드려볼까 했습니다만, 안 그래도 복잡한 설명이 더 복잡해질 것 같아서 관뒀습니다. 어차피 여기 쟁점은qsort
의 동작이니까요.제가 설명을 못 한 탓도 없지 않겠습니다만 원래 C언어에서 배열이라는 게 생각 없이 쓰기는 딱 좋은데 파고들어야 할 일이 생기면(특히 2차원 이상) 골치아파지는 측면이 있습니다. 사실 프로그래밍 하면서 이런 위험한 경우는 정말 자신있지 않으면 피해서 가는 편이 좋습니다. 자신 있다고 해도 최대한 주의해서 쓰는 편이 바람직하고요.
정말 명쾌합니다!!!
정말 명쾌합니다!!!
처음 배울 때 원리를 제대로 이해하지 않고 사용법만 보고 그대로 따라 사용하니 이런 문제가 발생한 것같습니다.
답변자님의 답변을 보고 완전히 이해하지 않고 그냥 방법을 가져다 쓰는 제 잘못된 프로그래밍 습관을 깨닫게 되었습
니다. 그리고 복잡할 수 도 있는 내용을 알기 쉽게 설명하시는 답변자님의 내공이 정말 대단하시네요. 덕분에 문
제도 해결하고 제 습관에 대해 다시 한 번 생각해 볼 수 있었던 좋은 계기가 되었습니다. 진심으로 감사합니다.
진짜진짜 감사합니다!!
질문자는 아니지만 굉장히 헤매던 중 정말 큰 도움이 되었습니다!!!
현자님..
댓글 달기