C Style "범 형" (상): 함수 swap lsearch

4414 단어 c모범
C 언어 에 서 는 범 형 능력 을 제공 하지 않 았 지만 신기 한 void * 가 있 습 니 다. 적당 한 사용 만 하면 통용 되 는 '범 형' 함 수 를 쓸 수 있 습 니 다.여기 서 '범 형' 은 따옴표 로 C \ # 라 는 범 형 언어 를 지원 하 는 의미 가 아니 라 통용 되 는 뜻 을 나타 낸다.
이 주제 에 관 해 서 는 상하 두 편 을 쓸 계획 이다.위의 함수 자 체 는 두 개의 함수 swap 와 lsearch 를 써 서 어떻게 void * 를 이용 하여 통용 되 는 프로그램 을 쓰 는 지 설명 합 니 다.다음은 C 언어 에서 도 통용 되 는 데이터 구 조 를 쓸 수 있다 는 것 을 설명 하기 위해 통용 되 는 Stack 을 쓰 겠 습 니 다.
먼저 첫 번 째 예 를 들 어 swap 함 수 는 쓰기 어렵 지 않 고 많은 사람들 이 C 언어 를 배우 기 시 작 했 을 때 썼 다.예 를 들 어 int 두 개 를 교환 하려 면 함 수 를 쓸 수 있 습 니 다. 함수 설명 은 대체적으로 다음 과 같 습 니 다.
void swap(int*, int*)

이제 더 블 두 개 를 바 꾸 고 사용자 정의 구조 체 두 개 를 바 꾸 려 면 어떻게 해 야 합 니까?유사 한 함 수 를 두 개 더 쓰 는 것 은 분명히 적합 하지 않다.
우 리 는 통용 되 는 함 수 를 써 서 이 일 을 할 수 있다.우 리 는 교환 대상 의 주 소 를 두 개 입력 했다.int 버 전의 swap 함수 에 대해 컴 파일 러 는 4 개의 바 이 트 를 교환 하 는 것 을 알 고 있 습 니 다. double 버 전의 swap 함 수 는 8 개의 바이트 이지 만 void * 는 유사 한 정 보 를 포함 하지 않 기 때문에 우 리 는 교환 대상 의 크기 를 표시 하 는 int 를 전송 해 야 합 니 다.다음은 유 니 버 설 스 왑 함수 입 니 다.
void swap(void *p1, void *p2, int size)
{
    char buffer[size];
    memcpy(buffer, p1, size);
    memcpy(p1, p2, size);
    memcpy(p2, buffer, size);
}

우 리 는 먼저 데 이 터 를 캐 시 하기 위해 크기 와 대상 크기 가 일치 하 는 공간 을 열 었 다.그 다음 에 전형 적 인 세 단계 입 니 다. 대상 1 을 buffer 에 넣 고 대상 2 를 대상 1 에 넣 고 마지막 으로 buffer 안에 있 는 것 을 대상 2 에 넣 습 니 다.여기 서 주의해 야 할 것 은 함수 의 첫 번 째 문장 은 컴 파일 러 의 지원 이 필요 합 니 다. 다행히 현대 컴 파일 러 는 기본적으로 모두 지원 되 었 습 니 다.몇 줄 의 코드 를 써 서 간단하게 테스트 할 수 있 습 니 다.
int x = 17;
int y = 27;
swap(&x, &y, sizeof(int));
std::cout << x << "\t" << y <<:endl/>

다음은 선형 검색 함 수 를 쓰 겠 습 니 다.검색 하려 면 키워드 가 있어 야 합 니 다. 그래서 우 리 는 비교 대상 의 주 소 를 입력 하고 하나의 배열 과 크기 를 입력 해 야 합 니 다. 앞에서 말 한 것 처럼 void * 는 정 보 를 거의 포함 하지 않 기 때문에 검색 대상 의 크기 를 입력 해 야 합 니 다. 마지막 으로 두 대상 을 비교 하려 면 비교 함수 가 필요 합 니 다.선형 검색 에 있어 서 는 전송 하지 않 아 도 됩 니 다. memcmp 로 비교 하면 두 대상 이 같은 지 알 수 있 지만 2 분 검색 에 서 는 안 됩 니 다.간단 한 예 일 뿐 이지 만 통용 성 을 충분히 고려 해 야 한다.
void* lsearch(void *key, void *base, int n, int eleSize, int(*cmp)(void*, void*))
{
    for (int i = 0; i < n; ++i)
    {
        void *eleAddr = (char*)base + i * eleSize;
        if (cmp(key, eleAddr) == 0)
        {
            return eleAddr;
        }
    }

    return NULL;
}

먼저 데 이 터 를 옮 겨 다 니 며 대상 마다 key 와 비교 해 야 합 니 다.void * 는 포인터 의 가감 연산 을 할 수 없습니다. 우 리 는 char * 로 전환 한 다음 에 현재 옮 겨 다 니 는 i 와 대상 크기 에 따라 몇 개의 바이트 를 뒤로 이동 하여 비교 대상 의 주 소 를 얻 을 수 있 습 니 다.그 다음 에 비교 하 는 것 입 니 다. 들 어 오 는 비교 함 수 를 호출 하여 일치 하면 이 주 소 를 되 돌려 줍 니 다.마지막 으로 옮 겨 다 니 며 찾 지 못 하면 NULL 로 돌아 갑 니 다.
이번 에는 약간 복잡 한 코드 를 써 서 테스트 합 니 다. 같은 문자열 을 찾 습 니 다.우 리 는 비교 함수 가 필요 하 다.
int strCmp(void *p1, void *p2)
{
    char *s1 = *(char**)p1;
    char *s2 = *(char**)p2;

    return strcmp(s1, s2);
}

주의해 야 할 것 은 문자열 이 원래 char * 입 니 다. 검색 함수 에 있어 서 char *, lsearch 가 필요 로 하 는 대상 의 주 소 를 비교 하려 면 char * 의 주소 로 들 어 갑 니 다. 즉, key 의 유형 은 char * * 이 고 base 배열 안에 char * 입 니 다.그래서 우리 의 비교 함수 p1 p2 는 char * * 이 고 먼저 강하 게 전환 한 다음 에 인용 을 풀 겠 습 니 다.char * s1 = (char *) p1 로 쓰 면,그러면 s1 의 의 미 는 예상 한 것 과 일치 하지 않 습 니 다. p1 을 char * 로 하고 주 소 를 분석 하 며 해당 하 는 곳 으로 이동 합 니 다. 귀신 은 그곳 이 무엇 인지 알 고 있 습 니 다. 근본적으로 방문 할 권리 가 없 을 수도 있 습 니 다. 방문 할 수 있다 고 가정 하면 그곳 부터 0 끝 을 찾 을 수 있 습 니 다. s1 이 어떤 귀신 문자열 인지 아 는 사람 이 없습니다.쉽게 말 하면 지침 을 이해 하고 한 번 뛰 는 것 과 두 번 뛰 는 것 의 차 이 를 이해 해 야 한다.
char *notes[] = {"Ab", "F#", "B", "Gb", "D"};
char *favoriteNote = "Eb";
char **found = (char**)lsearch(&favoriteNote, notes, 5, sizeof(char*), strCmp);
std::cout << (found == NULL) << std::endl;
favoriteNote = "Gb";
found = (char**)lsearch(&favoriteNote, notes, 5, sizeof(char*), strCmp);
std::cout << *found << std::endl;

테스트 코드 에서 char * * 를 쉽게 이해 할 수 있 습 니 다. 마지막 두 번 째 매개 변 수 는 char * 의 크기 입 니 다. 비교 할 대상 유형 은 char * 임 을 설명 합 니 다.앞에서 말 한 바 와 같이 첫 번 째 매개 변 수 는 대상 의 주소 이 고 favoriteNote 는 char * 입 니 다. 우 리 는 그것 (char *) 을 비교 해 야 하기 때문에 주 소 를 찾 아 보 냅 니 다.
'범 형' 함 수 는 여기까지 쓰 고 나중에 '범 형' 데이터 구조 - Stack 을 계속 쓸 시간 이 있 습 니 다.
원문 은 2015 년 6 월 에 쓰 여 자신의 작은 역 에 발표 되 었 다.

좋은 웹페이지 즐겨찾기