2016-05-28 12 views
0

私はC++に関する知識を広げるために小さなプロジェクトを作成していましたが、問題が発生しました。ユーザー名を受け入れるとき、私はそれがすでに使用されているかどうかを確認したかったのです。その特定のユーザー名が使用された場合は、ユーザーに質問を再印刷しました。最初のループは正常に動作しますが、それ以降はユーザーのVector内に存在していても何も受け付けません。私の機能ではなく、確認した場合、それは正常に動作しますbのC++での参照とvsの値による関数へのベクトルの受け渡し

 bool verify(char * a, vector<User> b){ 
14   for(int i = 0; i < b.size(); i++){ 
15     if(strcmp(a, b[i].getUsername()) == 0){ 
16       return false; 
17     } 
18   } 
19   return true; 
20 } 
21 
22 int main(){ 
23 
24   vector<User> users; 
25 
26   User us1((char *)"foo", (char *)"bar"); 
27   users.push_back(us1); 
28 
29   
30   do{ 
31     cout << "Enter Username: "; 
32     scanf(" %s", username); 
33     
34     
35   } while(!verify(username, users)); 
36   
37   return 0; 
38 } 

しかし、ベクトル&になります。誰かがなぜこれが起こっているのか説明できますか?

User.cpp

User:: User(char * userName, char * passWord){ 
    9 
10   this->userName = strdup(userName); 
11   this->passWord = strdup(passWord); 
12 
13 } 
14 
15 User:: ~User(){ 
16 
17   delete userName; 
18   delete passWord; 
19 
20 } 
21 
22 void User::getMessage(){ 
23 
24   cout << message << endl; 
25 } 
26 
27 char * User:: getUsername(){ 
28 
29   return userName; 
30 } 
31 
32 char * User :: getPassword(){ 
33 
34   return passWord; 
35 } 
36 
37 void User:: printUser(){ 
38 
39   cout << "User Information" << endl; 
40   cout << "Username: "<< userName << endl; 
41   cout << "Password: "<< passWord << endl; 
42   cout << "Messages: "<< ((message == NULL) ? "User has no messages\n" : "User has 1 message\n"); 
43 
44 } 
+2

です。 'std :: string'はあなたの友人です。 –

+3

私の推測では 'User'は' char * 'を含み、あなたは3つのルールに違反しています。しかし、あなたが 'User'のコードを投稿していないので、あなたの質問は現在答えられません。投稿[MCVE]。 –

+0

あなたは 'cout'を使い、' cin'も使います。変数 'username'はここでは宣言されていません。 – coyotte508

答えて

0

私は非常に可能な限り、それは通常より読みやすく、よりエラーを起こしやすいですCのものの上にC++の機能を使用してお勧めします。

あなたのコードには複数の問題があり、@AlanStrokes' commentが正しく、主な問題は3つのルールを正しく処理していません。

あなたのUserクラスは動的割り当てを行いますが、コピーコンストラクタと代入演算子は定義しません。問題を示す簡単なスニペットについては、スニペットhereをご覧ください。それは指し示されている実際のデータではなく、アドレスだけをコピーするので、最初のコピーが削除されると他のすべてが無効になります。

また、strdupは移植性がありません。これはC標準の一部ではありません。これはPOSIX標準の一部なので、その標準を実装しているシステムでのみ利用可能です。また、それはmallocでメモリを割り当てるC関数ですが、freeをCから返し、C++のdeleteを返さないポインタを削除する必要があります。

また、文字列リテラルがC++でconst char[]であるという理由があります。実際にはCではchar[]ですが、編集は許可されていないため、実質的にconstです。これは、コンパイラでは、実行可能ファイルの読み取り専用の場所に文字列リテラルを配置できるためです。したがって、文字列リテラルをchar *にキャストする代わりに、関数を正しくconst char *にしてください。

ここ
class User { 
    private: 
    std::string userName; 
    std::string password; 

    User(const std::string &userName, const std::string & passWord); 
    std::string getUsername(); 
    std::string getPassword(); 
    void printUser(); 
}; 

User::User(const std::string & userName, const std::string & passWord) { 
    this->userName = userName; 
    this->passWord = passWord; 
} 

std::string User::getUsername() { 
    return userName; 
} 

std::string User::getPassword() { 
    return passWord; 
} 

// etc... 

C++自動的に処理し、すべてのコピーや削除:C++はstd::stringと、それは仕方が容易になり、私が代わりにこれを使用してお勧めしますので、


これらのポインタの事を扱う言ったすべては迷惑ですロジックとあなたは迷惑なポインタのものに対処する必要はありません。

2

std::stringを使用したすべての議論を除いて、OPのコードの基本的な問題は、Userクラスのユーザー定義のコピーコンストラクタがないことです。デフォルトのものは、userNamepassWordフィールドの値をコピーするだけで、両方のベクトル(mainにあるものとverifyに作成されたもの)が同じ割り当てられたメモリアドレスを指すようにします。 verifyが返されると、そのメモリは削除され、mainのベクトルにUsersが残されたままになります(解放されたメモリを指す)。

参照を使用すると、この削除が回避され、元のベクターが元の状態に維持されます。あなたは、これらの日のコードで生のポインタを使用してはならない理由のひとつである

+0

ありがとう!これは役に立ちます。私はこれを初めて熟知しており、文字配列の代わりに文字列を使うようなことを完全に実験していないことは明らかです –

0

は、実際にコンパイルするので、私は、最小限の変更を加えた後、正常に動作するように見えます。 私はstd :: stringを使用して、Userクラスで推測する代わりに文字列を格納しました。

#include <vector> 
#include <string> 
#include <iostream> 
#include <cstdio> 
#include <cstring> 

struct User { 
    std::string name, game; 
    User(const char* nam, const char* gam) : name(nam), game(gam) {} 
    const char* getUsername() const { 
     return name.c_str(); 
    } 
}; 

bool verify(char * a, std::vector<User> b) { 
    for (int i = 0; i < b.size(); i++) { 
     if (std::strcmp(a, b[i].getUsername()) == 0) { 
      return false; 
     } 
    } 
    return true; 
} 

int main(){  
    std::vector<User> users; 

    User us1("foo", "bar"); 
    users.push_back(us1); 

    char username[100]; 

    do { 
     std::cout << "Enter Username: "; 
     std::scanf(" %50s", username); 
    } while(!verify(username, users)); 

    return 0; 
} 

私はこのon ideone、3回「foo」を入力して、「グレッグ」を実行すると、それはそれぞれの「foo」という後に促し続け、その後、「グレッグ」を受け入れます。

あなたの目に見えない「ユーザー」クラスの別のクラスを代入すると、それが動作しますので、問題はおそらく、そのコンストラクタに渡されるポインタのあなたの取扱いで、そのクラスでなければなりません。

いくつかの注意:

  • (char*)に文字列リテラル "foo" と "bar" をキャストする必要があってはなりません。彼らはすでにchar*です。 const -nessを取り除くためにこれをしているのであれば、読んでいないメモリに常駐している可能性があります。あなたがC++ 11を持っている場合は

  • は、verifyのループは、範囲のために置き換えることができます実際には

    for (auto u : b) { 
        if (strcmp(a, u.getUsername()) == 0) 
         return false; 
    } 
    
  • 、あなたは返す、関数全体verifyを排除し、std::any_of(users.begin(), users.end(), [username](const User& u){ return strcmp(u.getUsername(), username) == 0; })を使用することができますtrueusername場合は、ベクターusersに既にあります。

あなたはそれが間違ってやっているC++で `strcmp`を使用している場合はそう短く、同等の完全なプログラムは

#include <vector> 
#include <string> 
#include <iostream> 
#include <algorithm> 

struct User { 
    std::string name, game; 
    User(const char* nam, const char* gam) : name(nam), game(gam) {} 
    const std::string& getUsername() const { 
     return name; 
    } 
}; 

int main(){ 
    std::vector<User> users; 
    users.push_back({"foo","bar"}); 
    std::string username; 

    do { 
     std::cout << "Enter Username: "; 
     std::cin >> username; 
    } while(std::any_of(users.begin(), users.end(), 
      [username](const auto& u){ return u.getUsername() == username; })); 

    return 0; 
} 

on ideone

関連する問題