2014-09-06 3 views
-3

왜이 오류가 발생하는지 명확히해야합니까?strcmp() 함수의 사소한 오류

char name[50]; 
clrscr(); 
cout<<"Please enter the name of the medicine: ";cin>>name; 
pharmacy_personnel *ob2;//pharmacy_personnel is a class 
ob2 = new pharmacy_personnel[total]; 
for(int i=0; i<total; i++){ 
    if(strcmp(name,ob2[i].get_name_of_medicine())==0) 
    { 
     //code 
    } 
} 

오류는 말한다 strcmp() 기능입니다 : - 유형 "문자"의

인수 유형 "CONST 문자 *"

어떤 제안의 매개 변수와 호환되지 않습니다?

+0

-1 내 첫 번째 제안은 들여 쓰기를 수정하는 것입니다. – kay

+1

컴파일러 오류 중 어느 부분이 불분명합니까? 그건 그렇고, 말도 안되는 제한이 없다면 C++이 어떻게 쓰여지는 것은 아닙니다. – chris

+0

'strcmp'는'const char *'타입의 두 개의 인수를 받아들입니다. –

답변

0

C++ 스트림 (cin, cout)을 C 스타일 strcmp와 혼합합니다. 이는 좋은 생각이 아니므로 호환되지 않는 개체를 비교하게됩니다. 특히 cin>>name은 자신이 생각하는대로하지 않습니다. name을 std :: string으로 지정하고 strcmp 대신 동등성을 사용하는 것이 좋습니다.

에 대해std::find 범위에 대해 알면 코드도보다 명확하고 강력 해집니다. 이제는 더 나은 코드를 작성해야 할 가치가 있습니다.

+0

-1이 이유를 설명해 주시겠습니까? –

+0

cstdio와 iostream의 혼합은 문제가 아닙니다. – kay

+1

'cin >> name; '은 대부분 예상되는 것을 수행하지만, 최대 길이를 완전히 무시하는 것은 끔찍한 생각입니다. 나는'std :: string'을 사용해야한다고 동의한다. – chris

2

의견이 있으십니까?

네, 상당수.

먼저 오류가 발생하여 직접 해결할 수없고 도움을 청하기로 결정한 경우 문제를 재현하는 코드를 게시하십시오. 오류가 어디에서 발생하는지 파악할 수 없으면 프로그램의 어느 부분이 오류와 관련이 있고 그렇지 않은 부분이 올바른지 결정할 수 없습니다. 내 평소 접근 방식은 오류가 다시 나타날 때까지 새 파일로 시작하고 코드를 추가하는 것입니다. 필자는 복사 및 붙여 넣기를 피하면서 다시 타이핑하기를 바보로 오타를 복제하지 않기 때문에 붙여 넣기를 권장합니다. 종종 최소한의 작업 (또는 실패한 경우) 예제를 작성하여 문제를 직접 해결하는 방법을 배우게됩니다. 당신의 질문과 관련이 없다면 당신의 예제에서 비표준 의존성을 피하십시오. 귀하의 예에서는 clrscr 기능을 제거해야합니다. 또한 코드를 읽을 수있는 형식으로 포맷팅하는 데 2 ​​분의 시간을 더 걸리는 것이 좋습니다.

코드 작성 : 나는 최소한의 실용 예제를 만들었습니다.

#include <cstddef> 
#include <cstdlib> 
#include <cstring> 
#include <iostream> 

struct pharmacy_personnel 
{ 
    pharmacy_personnel(const char *const name_of_medicine = "Tonic Water") 
    { 
    std::strncpy(this->name_of_medicine_, name_of_medicine, 50); 
    this->name_of_medicine_[49] = '\0'; 
    } 

    const char * 
    get_name_of_medicine() const 
    { 
    return this->name_of_medicine_; 
    } 

private: 
    char name_of_medicine_[50]; 
}; 


int 
main() 
{ 
    const std::size_t total = 10; 
    char name[50]; 
    //clrscr(); 
    std::cout << "Please enter the name of the medicine: "; 
    std::cin >> name; 
    pharmacy_personnel * ob2 = new pharmacy_personnel[total]; 
    for (std::size_t i = 0; i < total; ++i) 
    { 
     if(std::strcmp(name, ob2[i].get_name_of_medicine()) == 0) 
     { 
      std::cout << "Yes, we have that medicine.\n"; 
      return EXIT_SUCCESS; 
     } 
    } 
    std::cout << "Sorry, we don't have that medicine.\n"; 
    return EXIT_FAILURE; 
} 

"갑자기"오류없이 컴파일됩니다. 이는 원래 질문에 관련 정보가 누락되었음을 나타냅니다. 내 최선의 방법은 pharmacy_presonnel::get_name_of_medicine()의 구현이 const char *을 반환해야 할 때 char을 반환한다는 것입니다.

하지만이 코드에는 정말 고쳐야 할 사항이 많이 있습니다.

첫 번째 놀라운 수 있습니다이 하나

$ ./a.out 
Please enter the name of the medicine: Tonic Water 
Sorry, we don't have that medicine. 

아마 두 번째이 하나 (공격자가 수행하기 전에 당신이 그것을 발견 할 희망) :

$ ./a.out 
Please enter the name of the medicine: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
Segmentation fault 

두 문제는 C를 사용하지 않는 사용자로부터 발생 ++ 기술이지만 안전하지 못한 저수준 C 스타일 I/O. 그들은 확실히 C 스타일 프로그래밍으로 고정 될 수 있지만, 왜 C++을 전혀 사용하지 않는가?

C++에서 우리는 보통 std::string 클래스에 문자열을 저장합니다. 이 클래스는 문자열에 충분한 크기의 버퍼를 할당하고 객체가 범위를 벗어날 때이를 할당 해제합니다. 그런 다음 실제로는 pharmacy_personnel 클래스에서 C++ 문자열을 사용해야합니다.

std::string에 대한 또 다른 좋은 점은 연산자 ==을 사용하여 간단히 비교할 수 있다는 것입니다. 이로 인해 cstring 헤더가 중복됩니다.

일반 "입력 연산자">>은 공백으로 멈 춥니 다. 의약품의 이름에는 빈칸이있을 가능성이 높기 때문에 std::getline 함수를 사용하여 전체 입력란을 읽는 것이 좋습니다. 우리가 얻을 모든 적용

:

#include <cstddef> 
#include <cstdlib> 
#include <iostream> 
#include <string> // This is the C++, not the C header! 

struct pharmacy_personnel 
{ 
    pharmacy_personnel(const std::string& name_of_medicine = "Tonic Water") 
    : name_of_medicine_(name_of_medicine) 
    { 
    } 

    std::string 
    get_name_of_medicine() const 
    { 
    return this->name_of_medicine_; 
    } 

private: 
    std::string name_of_medicine_; 
}; 


int 
main() 
{ 
    const std::size_t total = 10; 
    std::string name; 
    std::cout << "Please enter the name of the medicine: "; 
    std::getline(std::cin, name); 
    pharmacy_personnel * ob2 = new pharmacy_personnel[total]; 
    for (std::size_t i = 0; i < total; ++i) 
    { 
     if(name == ob2[i].get_name_of_medicine()) 
     { 
      std::cout << "Yes, we have that medicine.\n"; 
      return EXIT_SUCCESS; 
     } 
    } 
    std::cout << "Sorry, we don't have that medicine.\n"; 
    return EXIT_FAILURE; 
} 

이는 문자열 관련 문제를 해결하지만 다른 사람들이 여전히있다. 나는 nametotal 동일한 문자열과 비교하는 목적이 "벗은"운영자의 것이어야한다고 확신하지는 않습니다. new은 거의 확실하게 나쁜 생각입니다. (지금까지 게시 된 프로그램은 바로 그 이유 때문에 메모리 누출이 있습니다.) C++의 std::vector으로 업그레이드 할 것입니다.

// Other headers as before. 
#include <vector> // for std::vector 

// No changes to struct pharmacy_personnel. 

int 
main() 
{ 
    const std::size_t total = 10; 
    std::string name; 
    std::cout << "Please enter the name of the medicine: "; 
    std::getline(std::cin, name); 
    std::vector<pharmacy_personnel> ob2(total); 
    for (std::size_t i = 0; i < ob2.size(); ++i) 
    { 
     if(name == ob2[i].get_name_of_medicine()) 
     { 
      std::cout << "Yes, we have that medicine.\n"; 
      return EXIT_SUCCESS; 
     } 
    } 
    std::cout << "Sorry, we don't have that medicine.\n"; 
    return EXIT_FAILURE; 
} 

이미 C++ (11)를 사용하는 경우, 우리는 코드가 더 많은 표현 (오류가 발생하기 쉬운 이하) 루프 범위-에 대한 사용하여 만들 수 있습니다. 이렇게하면 벡터 요소에 명시 적으로 번호를 매길 필요가 없습니다. (반복자를 사용하여, 나는이 반복자를 사용하여 수동으로 더 읽기 코드를 만드는 것을 발견 적이 없다. 당신은 C++ 98 중 하나에 그렇게 할 필요는 없지만, 새로운 구문이 훨씬 청소기입니다.)

for (const auto& iter : ob2) 
    { 
    if(name == iter.get_name_of_medicine()) 
     { 
     std::cout << "Yes, we have that medicine.\n"; 
     return EXIT_SUCCESS; 
     } 
    } 

마지막 일을 내가 언급 할 수 있듯이 네이밍 및 클래스 디자인이 향상 될 수 있습니다. ob2 이름은 무엇을 말해야합니까? 더 중요한 이유 : 클래스 pharmacy_personnel (직원을 대변하기로되어 있습니까?)과 관련된 약의 이름이있는 이유는 무엇입니까? 모든 직원이 정확히 하나의 약에 대한 책임이 있지만 이상하게 들릴 경우 결국에는 의미가 있습니다. 이상적으로, 클래스는 도메인 (즉, 실제)을 최대한 가깝게 모델링합니다. 그렇게하기 위해 코드를보다 체계적으로 구성하고 이해하기 쉬우 며 따라서 유지 관리가 쉬우 며 코드를 만드는 것이 더 중요합니다.

+0

팁 주셔서 감사합니다.하지만 학교에서 이것을 배우고 있으며 STL을 벡터처럼 사용할 수 없으며 원거리 for 루프도 이해하지 못했습니다. 설명해 주시겠습니까? – Yashodhan

+0

[Range-for] (https://en.wikipedia.org/wiki/C%2B%2B11#Range-based_for_loop)는 C++ 11의 기능으로, 범위를 반복하지 않고도 범위를 반복 할 수 있습니다. 시작, 현재 색인 및 종료 (컴파일러가 사용자를 대신하여 수행). 다른 언어는이 기능을 "for-each"로 알고 있습니다. 불행히도, STL 컨테이너에서 가장 유용하지만, 컴파일 타임에 길이를 알 수있는 C 스타일 배열에서도 사용할 수 있습니다 (링크 참조). – 5gon12eder