3

私は Linux を使用していますが、int現在のキーの種類のASCII を返すカスタム関数がありますgetch()。それに慣れようとして、パスワードを保存する方法が問題になったとき、私のコードは次のとおりです。

int main() {
    int c;
    char pass[20] = "";

    printf("Enter password: ");
    while(c != (int)'\n') {
        c = mygetch();
        strcat(pass, (char)c);
        printf("*");
    }

    printf("\nPass: %s\n", pass);

    return 0;
}

残念ながら、GCC から警告が表示されます。

pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’

パスにchar配列の代わりにポインターを使用しようとしましたが、2番目に文字を入力するとセグメンテーション違反が発生します。この関数は単独で動作しますが、ループ内では機能しません。少なくとも、Windows システムでの getch() とは異なります。

私の例で何が間違っていることがわかりますか? 私はこれを学ぶことを楽しんでいます。

編集:答えのおかげで、次のばかげたコードを思いつきました:

int c;
int i = 0;
char pass[PASS_SIZE] = "";

printf("Enter password: ");
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) {
    c = mygetch();
    if(c == BACKSPACE) {
        //ensure cannot backspace past prompt
        if(i != 0) {
            //simulate backspace by replacing with space
            printf("\b \b");
            //get rid of last character
            pass[i-1] = 0; i--;
        }
    } else {
        //passed a character
        pass[i] = (char)c; i++;
        printf("*");
    }
}
pass[i] = '\0';
printf("\nPass: %s\n", pass);
4

3 に答える 3

3

問題は、2 番目の引数としてa をstrcat期待することです (2 つの文字列を連結します)。char *2 つの文字列はありません。1 つの文字列と 1 つのchar.

cの最後に追加したい場合は、現在のサイズを格納passする int を保持してから、次のようにしますipass

pass[i] = (char) c.

pass完了したら、(最後の位置を 0 に設定して) null で終了するようにしてください。

于 2010-11-04T04:18:22.640 に答える
1

1 つの文字は、1 つの文字を含む文字列と同じではありません。

言い換えれば、「a」と「a」は非常に異なるものです。

C の文字列は、null で終わる文字の配列です。あなたの「パス」は20文字の配列です - 20文字のスペースを含むメモリのブロックです。

関数 mygetch() は char を返します。

あなたがする必要があるのは、スペースの 1 つに c を挿入することです。

"strcat(pass, c)" の代わりに、"pass[i] = c" を実行します。ここで、i は 0 から始まり、mygetch() を呼び出すたびに 1 ずつ増加します。

次に、ループが終了したら、pass[i] = '\0' を実行する必要があります。i は、mygetch() を呼び出した回数と等しくなり、ヌル ターミネータを追加します。

別の問題は、c の値を設定していないことです。最初に「\n」かどうかを確認します。比較を行う前に mygetch() を呼び出す必要があります。

int i = 0;
for (;;)
{
    c = mygetch();
    if (c == '\n')
        break;

    c = mygetch();
    pass[i++] = c;
}
pass[i] = '\0';
于 2010-11-04T04:25:54.907 に答える
0

正しく診断されたstrcat()2 つの文字列の問題に加えて、コンパイラの警告を無視したのはなぜですか。警告がなかったのに、警告をオンにしないのはなぜですか? 私が言ったように、その問題に加えて、EOF を取得した場合に何が起こるかを考慮する必要があり、'c' の初期値についても考慮する必要があります (誤って '\n' になる可能性がありますが、おそらくそうではありません)。 't)。

これは、次のようなコードにつながります。

int  c;
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;

while ((c = getchar()) != EOF && c != '\n' && dst < end)
    *dst++ = c;
*dst = '\0';  // Ensure null termination

「mygetch()」から「getchar()」に切り替えました。これは主に、私が言っていることがそれに当てはまり、「mygetch()」関数には当てはまらない可能性があるためです。その関数が EOF で何をするかについての仕様はありません。

または、 を使用するstrcat()必要がある場合でも、文字列の長さを追跡する必要がありますが、次のことができます。

char c[2] = "";
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;

while (c[0] !=  '\n' && dst < end)
{
    c[0] = mygetch();
    strcat(dst, c);
    dst++;
}

それほどエレガントではありません-strcat()コンテキストで使用するのはやり過ぎです。単純なカウントを行って を繰り返し使用することもできると思いますが、後続の反復で 0、1、2、3、... 文字をスキップする必要があるためstrcat(pass, c)、二次的な動作になります。strcat()対照的に、dst が文字列の末尾にある NUL を指すソリューションは、strcat()何もスキップする必要がないことを意味します。ただし、1 文字の固定サイズの追加では、おそらく最初のループの方が適しています。

于 2010-11-04T04:36:25.530 に答える