2017-02-13 180 views
0

ポインタを使用して2次元配列の文字列から母音を削除しようとしています。私はそのASCII値で母音を検出することができますが、文字列は更新されません。Cでポインタを使用して母音を文字列から削除

コードのこの部分に変更できません。

void remove_vowel(char strings[NUM_STRINGS][STRING_LENGTH]) 

私のコードはどこが間違っていますか?

更新コード:

void remove_vowel(char strings[NUM_STRINGS][STRING_LENGTH]) 
    { 
     // loop through each row, starting intitally points to last element 
     for (char(*p)[STRING_LENGTH] = strings; p != strings + NUM_STRINGS; ++p) { 
      // variable q points to the first element  
      for (char *q = *p; q != *p + STRING_LENGTH; ++q) { 

       if (*q != 'a' && *q != 'e' && *q != 'i' && *q != 'o' && *q != 'u') { 
        //printf("%c",*q);   
        *q = *q; 
       } 
      }  
     } 
    } 

私は、下記の溶液を使用して再書き込みコードすることができました。誰も助けてくれてありがとう!

あなたは(少なくとも)別々の機能の中に、既存のremove_vowel()ルーチンを分離する必要があり手始めに

void remove_vowel(char strings[NUM_STRINGS][STRING_LENGTH]) 
    { 
     // store the array in a pointer 
     char(*wordHolder)[STRING_LENGTH] = strings; 

     // loop through each row 
     for (int i = 0; i < NUM_STRINGS; i++) 
     { 
      // assign worl 
      char *letter = *wordHolder; 
      char *dest = *wordHolder; 

      // check if null character 
      while (*letter != '\0') { 
       // check for vowels 
       if (*letter != 'a' && *letter != 'e' && *letter != 'i' && *letter != 'o' && *letter != 'u') { 
        // assign non-vowel letter to destination 
        *dest++ = *letter; 
       } 
       // move to next letter 
       letter++; 

      } 
      // add null pointer to end of destination 
      *dest = '\0'; 

      // increment pointer position to next word 
      wordHolder++; 
     } 
    } 
+2

'* Q = * Q;' essentialy NOPです。あなたは '* q = * p;'を意味しましたか?またこれは奇妙に見えます: 'char * q = * p'。 –

+4

マジックナンバーを使用しないでください。文字を指定する場合は、代わりに '' a''のような文字を使用します。 – NathanOliver

+1

文字列の配列があります。 (これは文字配列です)。なぜあなたは問題を分割しないのですか? 1つの文字列に対してこれを行う関数を作成し、それをメイン配列をループする別の関数で使用しますか? – Dan

答えて

2

C言語に相当するものを考えてみましょう。

C言語では、テキストを配列として扱う必要があります。アレイの場合、スロットをで消去した場合は、残りの項目を移動して消去済みのスロットを上書きする必要があります。

ここから始めましょう。

void dont_copy_vowels(char text_array[STRING_LENGTH]) 
{ 
    char * p_source = &text_array[0]; 
    char * p_destination = &text_array[0]; 
    const unsigned int length = strlen(text_array); 
    while (*p_source != '\0') 
    { 
     static const char vowels[] = "aeiou"; 
     if (strchr(vowels, *p_source) != NULL) 
     { 
     ++p_source; 
     continue; // don't copy vowels. 
     } 
     // Copy the letter or symbol. 
     *p_destination++ = *p_source++; 
    } 
    *p_destination = '\0'; 
} 

あなたはCスタイルの文字列の配列を使用しているので、あなたは、ループ内で上記のコードを配置する必要があります。

for (unsigned int string_index = 0; 
    string_index < NUMBER_OF_STRINGS; 
    ++string_index) 
{ 
    dont_copy_vowels(strings[string_index]); 
} 
+0

これは実際に問題を解決するのに役立ちました。ありがとう! – cosmoonot

2

、ソリューション:(

void remove_vowel(std::string& s) 
{ 
... 
} 

void remove_vowel(std::vector<std::string>& strings) 
{ 
    for(auto&& s : strings) 
     remove_vowel(s); 
} 
void remove_vowel(char strings[NUM_STRINGS][STRING_LENGTH]) // can't change this signature 
{ 
    ... 
} 

今、あなたの問題は2に減少していますまたは3つ)ほとんど無関係な部分:

  • C++
  • にCスタイルの配列から変換する単一std::string
  • から母音を削除する(多分:Cからの変換++ Cスタイルの配列に戻っ)
+0

私は提案を理解していますが、これは機能しません。この場合、関数メソッドは変更できません。 – cosmoonot

+1

@cosmoo関数のシグネチャ*は変更されていません! –

2

私は「あなたがより多くのを書い示唆C++のような "コード。

#include <string> // needed for string container 
#include <vector> // needed for vector container 

// This function removes all vowels from a std::string 
std::string removeVowels(std::string input) { 
    std::vector<std::string> vowels = {"a", "e", "i", "o", "u", "A", "E", "I", "O", "U"}; // create and initilise a dynamic array with all vowels, that should be filtered 
    // Iterate over all vowels 
    for(const std::string vowel : vowels) { 
     // Get first position of the appearance of the vowel, 
     // exit if none are found 
     while(auto pos = input.find(vowel) != std::string::npos) { 
      // replace vowel with empty string 
      input.erase(pos, vowel.size()); 
     } 
    } 
    // return our result 
    return input; 
}; 

この例をコンパイルしてテストしました。

文字列の2次元配列を取り、この関数を使用する関数を記述できます。 Cスタイルの配列に対してstd :: vectorを使用することを検討してください。

+1

'replace'を使うのではなく、' erase'を使いたいかもしれません。私は '消去'がもっと読みやすいと思う。 –

+0

情報ありがとうございます。私はこの機能が存在するのか分からなかった。 – OutOfBound

3

この質問は時間の経過とともに変更され、元々はに対して尋ねられました。私は歴史的な目的のためにここでそれを残しているが、ここで、あなたの問題を解決する必要があり、新たに対象と


remove_ifには適用されません。

除去することにより、(シフトさせることにより行われます削除されない要素が範囲の先頭に現れるような方法で範囲内の要素を移動することができます。残っている要素の相対的な順序は保持され、コンテナの物理的なサイズは変更されません。

あなたはこのようremove_ifを活用することができます:

void removeVowel(char strings[][STRING_LENGTH]) { 
    for (auto p = strings; p != next(strings, NUM_STRINGS); ++p) { 
     remove_if(begin(*p), end(*p), [vowels = "aeiouAEIOU"s](const auto& i){return vowels.find(i) != string::npos;}); 
    } 
} 

Live Example

この非常に簡単な解決策は、あなたがchar[]要素が'\0'を終了させて​​いることが必要です。 remove_ifは、すべての母音を無視して'\0'文字を通過させるだけです。場合、これは実行可能なソリューションではないかもしれない:あなたは終了していない'\0'されchar[]を使用している

  1. 、これは非常に悪いデザインの決定ですが、あなたがしている場合のコメントで回避策を話し合うありましょう
  2. STRING_LENGTHは非常に大きいです。 remove_if検索STRING_LENGTH要素ごとに、あなたが文字列なら、あなたの入った配列ではなく、C++関数のパラメータのためのstringsパラメータのend(*p)

コメントのnext(*p, strlen(*p) + 1)を使用することを検討してよりはるかに短いですので:

タイプが「Tの配列」または「Tの未知の境界の配列」である場合、それはタイプ「Tへのポインタ」に置き換えられます[source]

だからあなたの配列の主要寸法の任意の値の値は破棄され、パラメータがポインタとして扱われるように変換されるものとして扱われます。したがって、配列関数のパラメータの主な次元は、渡された配列の実際のサイズを必要としないため、混乱を招く可能性があるため、コードには別のコードがあります。警告なしで受け入れられる。

これで雄弁になりましたが、私のコードと他のコードの重要でないすべての寸法はになります。これは事実のためである。

多次元配列は、従来の配列と非常によく似ている。多次元配列は、配列と同じように、同じ型のオブジェクトの連続したシーケンスとして格納されます。注目すべき重要な点は、各次元を作成するための大きさを定義する数値です。このため、それはまた、その寸法の長さを設けることなく、多次元配列を渡すことはできません[source]

したがって、あなたはわかりますその我々できるコールbegin(*p)end(*p)決して begin(strings) または end(strings)

+0

あなたの応答は本当に解決策に役立ちました。ありがとう!上記の私の改訂コードを掲載しました。 – cosmoonot

+0

解決策を見つけられたらうれしいです...しかし、私はあなたがそこに行っているものを見て、自分の解決策を使っていないことを望みません。それにもかかわらず、あなたが行く必要があると感じたら、それを答えとして加えてそれを受け入れます。 –

関連する問題