2013-08-14 3 views
1

다음 코드에서 문자열을 비교하는 주석 처리 된 부분을 제거하면 seg 11 오류가 발생합니다. 나는 이유를 이해할 수 없다! 나머지 코드는 정상적으로 작동합니다. 어떤 도움을 주셔서 감사합니다! compare_names()에서QSORT 함수가 C

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int compare_scores_desc(const void* scorea, const void* scoreb){ 
int a = *(int*)scorea; 
int b = *(int*)scoreb; 
return a-b; 
} 

int compare_names(const void* namea, const void* nameb){ 
char** a = *(char**)namea; 
char** b = *(char**)nameb; 
return strcmp(*a,*b); 
} 

int main(int argc, char* argv[]){ 
int scores[7] = {456,234,65,563,67,19,100}; 
int i; 
qsort(scores,7,sizeof(int),compare_scores_desc); 
puts("\nThese are the scores in order : \n"); 
for(i=0;i<7;i++) 
    printf("%i\n",scores[i]); 
char *names[] = {"Krishna","Rama","Bhishma","Arjuna"}; 
/*qsort(names,4,sizeof(char*),compare_names);*/ 
puts("------------------"); 
puts("The names in order are : \n"); 
for(i=0;i<4;i++) 
    printf("%s\n",names[i]); 
return 0; 
} 

답변

6

, 당신은 부적절 캐스트 후 인수를 역 참조한다. 지역 변수의 유형은 char **이지만 인수를 char **으로 캐스팅하고 역 참조를 사용하면 char *이됩니다.

nameanameb은 배열 names[]의 요소에 대한 포인터이며 main()에 선언되어 있습니다. 즉, 해당 유형은 실제로 char *을 가리키는 포인터입니다. 이러한 인수를 역 참조하지만 char **에 할당하면 로컬 변수에서 char *char **으로 처리합니다 (컴파일러가이 문제에 대해 경고하는 진단을 발행해야 함). 이제 char * 인 포인터 값을 가져 와서 strcmp()에 전달하면 역 참조합니다. 이로 인해 프로그램에서 strcmp() 함수의 포인터 값으로 문자열의 sizeof(char *) 바이트를 처리합니다.이 포인터를 사용하려고 시도 할 때 4 또는 8 (또는 어떤 sizeof(char *)이든) 바이트가 인쇄 가능한 문자로 구성되어 포인터 값으로 다시 해석되면 유효한 포인터가 거의 생성되지 않으므로 세그먼트 오류가 발생합니다.

하나의 가능한 수정 프로그램은 로컬 변수를 초기화 할 때 참조를 해제하지 않는 것입니다. 그러나, 인수 const void *, 그래서 당신이 const 유형에 대한 포인터로 해당 지역 변수를 선언하는 경우에는 전부 캐스트 방지 할 수 있습니다

int compare_names(const void* namea, const void* nameb){ 
char* const * a = namea; 
char* const * b = nameb; 
return strcmp(*a,*b); 
} 

compare_scores_desc()의 구현이 실패하면 부호있는 정수 오버 플로우에 a - b 결과 . 예를 들어 aINT_MAX이고 b-1 인 경우 모든 경우에 적용되도록 구현을 수정해야합니다.

int compare_scores_desc(const void* scorea, const void* scoreb){ 
const int *a = scorea; 
const int *b = scoreb; 
return (*a > *b) - (*a < *b); 
} 
+0

아래 투표에 대한 설명에 감사드립니다. 감사합니다! – jxh

+0

그 좋은 (* a> * b) - (* a <* b)'+1. – Kaz

+0

@ 카즈 : 전에 본 적이 있었지만, [Ambroz의 대답] (http://stackoverflow.com/a/10997428/315052)을 읽었을 때 나는 그것을 마음에 담아 냈습니다. – jxh

2

문제는 문자열 비교 기능이며,이를 해결하기위한 최소한의 방법은 아마도 :

int compare_names(const void* namea, const void* nameb){ 
char* a = *(char**)namea; 
char* b = *(char**)nameb; 
return strcmp(a,b); 
} 

nameanameb 인수가 문자열 벡터에 포인터입니다. 이것을 이해 했으므로 char ** 유형을 사용했습니다.

그러나 함수에서 수행해야 할 작업은 해당 배열에서 char * 포인터를 검색하는 것뿐입니다. 이 char * 포인터는 이미 문자열입니다. 당신은 그들을 다시 참조 할 필요가 없습니다. 그냥 strcmp으로 전달하십시오.

원본 코드에 진단이 필요한 제약 조건 위반이 있습니다.을 밀고해야한다 : 당신은 char * 생산하는 char **를 역 참조하고 있지만함으로써 잘못 포인터로 문자 데이터를 처리, 다시 char **에 그것을 저장하고 다시 역 참조하고

/* originally */ 
char** a = *(char**)namea; /* error: initialization from incompatible type */ 

.

+0

+1입니다. – jxh