①
unit 73
p.882에 73.5 연습문제에서
char s1[10][8] = {
"india", "delta", "bravo", "kilo", "alfa",
"echo", "hotel", "jiliett", "golf", "charlie"
};
이라고 되어 있습니다.
하지만
2차원 배열에서
자료형 배열이름[세로크기][가로크기] = {{ 값, 값, 값}, {값, 값, 값}};
으로 알고 있는데
그렇다면
char s1[10][8]은 세로 10줄, 가로 8줄이 되어야하지 않나요??
②
unit 73
p.882에 73.5 연습문제에서
정답이
return strcmp((char *)a, (char *)b); 라고 하는데
return strcmp(*(char *)a, *(char *)b);
이렇게 퀵 정렬은 역참조를 하는 걸로 알고 있는데
하지 않는 이유가 무엇인가요??늘 감사합니다..!
1. 2차원 배열이지만, 1차원 배열은 여기서는 문자열입니다.
10개의 문자열을 저장하고, 각 문자열의 최대 길이는 8자라는 정도로 이해하면 됩니다.
2. 참조, 역참조 아무 상관 없습니다.
무조건 type match입니다.
https://en.cppreference.com/w/c/algorithm/qsort
qsort 첫 번째 인자를 봅시다. void *ptr입니다.
ptr의 타입은? pointer to void이고, 범용이니까 pointer to x라고 이해합시다.
char s1[10][8]인데 s1이 배열 이름인 경우이니
s1은 char(*)[8] 형식의 포인터로 해석됩니다.
즉, char[8] 형식을 가리키는 포인터로 해석됩니다.
pointer to char[8]이죠.
s1[10][8]을 그대로 읽는다면
array of array of char이지만, 간단히 array of char[8]이라고 보면 됩니다.
따라서 void *ptr에 array of char[8]을 던지는 것, pointer to char[8]을 전달하는 것이니까
ptr은 pointer to x이고, s1에서 x에 해당하는 부분은 char[8]이니까 문제가 없는 겁니다.
그러면 왜 compare 함수에서 const void *a, const void *b인지도 이해할 수 있을 겁니다.
void 포인터는 모든 자료형의 주소를 가리키는 용도이지, 값을 비교하는 연산은 할 수 없습니다. 포인터 연산도 못하죠. 따라서 해당 자료형의 포인터로 변환해야 해당 자료형의 값에 접근할 수 있습니다.
문자열을 정렬하려면 각 문자열의 문자라는 값에 접근할 수 있어야 하니까 (char *)로 타입 캐스팅만 해주는 겁니다.
문자열이라고 했어요.
char(*)[8]이니까 pointer to char[8]입니다. 8자까지만 담을 수 있는 문자열에 대한 주소를 전달하는 것.
그러니 compare의 인자가 void *이고,
a의 타입이 pointer to void이고, (char *)로 변환할 수 있는 겁니다.
const 해석은 뺏습니다. 간략하게 쓰기 위해.
type match이기 때문에 C 언어 컴파일러 경고를 모두 켜도 경고 0개입니다.
자꾸 질문이 여기서는 strlen, 저기서는 sizeof
퀵 정렬은 역참조한다... 처럼 공식으로 외우려고 하는데,
공식이 아니라 type match, type mismatch 문제입니다.
원서 읽으면 쉽다고 하는 이유는 영어로 pointer to int, pointer to char라고 쓰여 있기 때문입니다.
cdecl.org에서 정확한 읽기를 배우세요.
위에 설명에서는 s1[10][8]하고 비교하기 쉽게 s1(*)[8]로 썼습니다. 정확한 표기는 char (*s1)[8]입니다.
이것도 마찬가지. 전 이게 무슨 뜻인지 이해도 못합니다.
모릅니다. 퀵 정렬이 역참조를 한다고요? 이게 무슨 말이지? 몰라요.
qsort() 함수의 원형에 따라 해당 인자에 맞춰서 type match로 사용만 하면 됩니다.
어떤 값을 s1으로 던질지, &s1으로 던질지, *s1으로 던질지는 type match의 문제라는 겁니다. '퀵 정렬은 역참조를 한다' 같은 공식은 없습니다. 그렇게 설명하는 책이 있으면 버리거나 중고 서점에 팔아버리세요.
제가 질문을 잘못했던 것도 맞는 거 같고 이해를 못한 것도 맞는 것 같습니다..
말씀대로 void 포인터를 해당 자료형의 포인터로 변환해야 하는 것은 교재를 통해서도 이해하였고, 관리자님의 설명을 통해 다시 한 번 확실히 이해를 하였습니다..
똑같은 질문일 수도 있는 점 먼저 죄송하다는 말씀 드리고 싶습니다..
p.878 예제에서는
int compare(const void *a, const void *b)
{
int num1 = *(int *)a;
int num2 = *(int *)b;
// void 포인터를 int 포인터로 변환한 뒤 역참조하여 값을 가져옴
...
}
이렇게 void 포인터를 해당 자료형으로 ①변환한 후 ②역참조를 하여 값을 가져오는데
p.882
73.5 연습문제
int compare(const void *a, const void *b)
{
return strcmp((char *)a, (char *)b);
}
이렇게 똑같이 void 포인터를 해당 자료형으로 ①변환은 하는데return strcmp(*(char *)a, *(char *)b);
이런 식으로 ②역참조는 왜 안하는지 궁금합니다..
문자열이라서 그런걸까요..?
다시 한번 비슷한 질문드려 죄송합니다..
qsort가 원하는 compare 함수의 원형일 뿐입니다.
878p에서
const void *a로 넘겨 받았습니다.
여기서는 정수를 비교하면서 정렬을 해야 합니다.
그런데 compare로 넘겨 받은 건 pointer to void입니다.
그러니 우선 값에 접근하려면? pointer to int로 변환해야 합니다.
(int *) 형변환 들어갑니다.
근데 pointer to int 상태에서 연산하면 주솟값 비교잖아요? 값에 필요한데요?
int라는 값에는 어떻게 접근해요? pointer to를 제거해야 하죠?
그러니 *(int *)a 형태가 됩니다.
애초에 qsort에서 compare()를 사용할 때 int로 받을 수 없어요.
함수 원형에서 원하는 게 compare(const void *, const void *) 형식이니까요.
882p는 이전 답변에서 충분히 설명했습니다.
char s1[10][8]이고, 8은 무시하고
s1(*)[8]이라고요. 그러니 타입이 일치한다고요. 이건 이전 답변을 다시 읽고, 영어로 읽는 법을 이해하고, type match구나... 이거 이해하세요.
pointer to (char[8])이라고요. 그냥 8글자 담을 수 있는 주소라는 뜻이니 일치합니다.
이건 이전 답변 이상 해줄 설명이 없어요. 하나하나 다 단계별로 나눈 설명이니까요.
compare(const void*, const void*)이니까 무조건 void *로 넘겨야 하는 거고, compare 안에서는 내가 아는 타입, 그 값이 int이면 int로 어떻게든 바꿔서 값을 가져와야죠. 문자열이면 문자열로 가져오고. 문자열은 그 자체가 주소잖아요.
자꾸 이건 역참조, 이건 역참조 안 함... 이런 게 아니라 그냥 type match 문제입니다.
type match 해주려니까 역참조이고, 값을 꺼내오려니까 역참조이고,
배열은 그 자체로 접근하니까 역참조가 필요없고요. 값은 배열에서 참조 연산자 []로 가져오죠. 글자 하나하나 비교하면서 크냐, 작냐를 따지고 정렬하는 것이니까요.
그러니 배열 자체는 역참조가 필요없죠.
str[0] > str[1]을 비교할 때, str은 주소이죠. 그 안에는 값이고요. 그러니 역참조 필요없죠. 근데 굳이 풀면 *(str)이고, *(str+1)로 바꿔 쓸 수 있죠. 둘은 바꿔 쓸 수 있으니까요.
str[1]도 되지만 1[str]도 가능하죠. 어차피 포인터 식으로 풀면 *(str+1)이니까요. 이건 C언어에서 자주 나오는 퀴즈 같은 겁니다. 실무에서 저렇게 코딩하면 등짝 맞으니까요.
type match가 이해 안 되면 2차원 배열로 문자열 정렬할 때는 저렇게 쓴다. 라고 그냥 외워서 코딩하세요. 그러다 보면 어느 순간 이해는 자동으로 오는 겁니다.
암기하면 이해는 따라 옵니다.
qsort 못하는 이유는 간단해요. 매일 아침 100일 동안 qsort 코드 작성하세요. 외워서 작성하세요. 100일 동안 하면 다 암기되고 이해됩니다.
정렬 이해 못하는 경우는 간단해요. 책 보고 예제 1-2번 해보고 어렵다고 해서 그래요.
자전거 타는 법은 자이로스코프 원리나 캐스터 각이 아니라 넘어지면서 페달 밟고 자전거를 탔기 때문에 배우는 겁니다. 자이로스코프 원리 6개월 강의 들어봤자 안 됩니다.
이해해야 하는 포인트가 다르다는 뜻입니다. 이건 참조, 이건 역참조... 이걸 이해하지 말라는 겁니다. 이건 이해의 대상이 아닙니다. 암기의 대상이죠.