1

これはファイルauth.txt(ユーザー名パスワード)です
paolo 1234
luca 0000 marci1000
そして

これは私のコードです:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void onexit(char *u, char *p, char *l, FILE *f, int flag);

int main(int argc, char *argv[]){

    FILE *fp;
    char *tmp, *tmp2, *user, *pass, *line;

    printf("Inserire utente: ");
    if(scanf("%ms", &user) == EOF){
        perror("scanf");
        return EXIT_FAILURE;
    }

    printf("Inserire password: ");
    if(scanf("%ms", &pass) == EOF){
        perror("scanf");
        onexit(user, NULL, NULL, NULL, 1);
        return EXIT_FAILURE;
    }

    size_t max_length = strlen(user) + strlen(pass) + 3;
    line = malloc(max_length);
    if(line == NULL){
        perror("malloc");
        onexit(user, pass, NULL, NULL, 2);
        return EXIT_FAILURE;
    }

    fp = fopen("/home/pol/auth.txt", "r");
    if(fp == NULL){
        printf("Errore apertura file\n");
        onexit(user, pass, line, NULL, 3);
        return EXIT_FAILURE;
    }

    while(!feof(fp)){
        if(fgets(line, max_length , fp) == NULL){
            perror("fgets");
            onexit(user, pass, line, fp, 4);
            return EXIT_FAILURE;
        }
        tmp = strtok(line, " ");
        if(tmp == NULL){
            perror("strtok");
            onexit(user, pass, line, fp, 4);
            return EXIT_FAILURE;
        }

        tmp2 = strtok(NULL, "\n");
        if(tmp2 == NULL){
            perror("strtok");
            onexit(user, pass, line, fp, 4);
            return EXIT_FAILURE;
        }
        if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){
            printf("USER: %s - PASS: %s\n", tmp, tmp2);
            onexit(user, pass, line, fp, 4);
            return EXIT_SUCCESS;
        }
        else{
                 continue;
        }
    }
    printf("no such user or pwd into DB\n");
    onexit(user, pass, line, fp, 4);
    return EXIT_FAILURE;
}

void onexit(char *u, char *p, char *l, FILE *f, int flag){
    if(flag == 1){
        free(u);
    }
    if(flag == 2){
        free(u);
        free(p);
    }
    if(flag == 3){
        free(u);
        free(p);
        free(l);
    }
    if(flag == 4){
        free(u);
        free(p);
        free(l);
        fclose(f);
    }
}

編集:別の問題!テストし
たい場合は、次のようになります 。Inserire utente:luca Inserireパスワード:0000 strtok:成功 してプログラムが停止します。1番目と3番目の入力でのみ機能し、2番目の入力では機能しません。どうして??luca0000






4

2 に答える 2

3

whileループは1回の反復のみを通過するようです。

while(!feof(fp)){
  // ...
  if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){  // if match, exit
    printf("USER: %s - PASS: %s\n", tmp, tmp2);
    onexit(user, pass, line, fp, 4);
    return EXIT_SUCCESS;
  }
  else{                                                     // else exit
    printf("no such user or pwd into DB\n");
    onexit(user, pass, line, fp, 4);
    return EXIT_FAILURE;
  }
}

...少しおかしいようです。読んだ最初の行が一致しない場合、本当に終了しますか?


編集:

user別の問題:あなたはそれらを送る前にそしてpassあなたがそれらを送る前に スペースを割り当てる必要がありますscanf

char *user;
scanf("%ms", &user);  // error

その代わりに、次のようなことを試すことができます。

char user[100];
scanf("%ms", &user);  // now user actually has some space to store data

(お使いのバージョンでは、を指すscanf場所にデータを書き込もうとしますが、メモリ内のランダムな場所を指すだけなので、誰が何が起こるかを知っています。) useruser

おっと、@ MvGが指摘したように、これは問題ありません。私は「%ms」POSIX拡張機能に精通していませんでした。


編集2

ユーザー名uuとパスワードを入力するとしますpp。このため:

size_t max_length = strlen(user) + strlen(pass) + 3;

...、、またはに設定max_lengthします。 fgetsは、最大で文字または改行文字に遭遇するまでデータを読み取ります。つまり、ループ内に入ると、反復ごとに最大または1文字しか読み取ろうとしませんが、これは正しくないようです。2 + 2 + 37max_length-1while7-16

たとえば、パスワードファイルに次のものが含まれている場合:

paolo 1234
luca 0000
marci 1000

...次にline、次の値を取得します。

  1. "paolo "(末尾にスペースがあります)
  2. "1234"
  3. "luca 0"
  4. "000"
  5. "marci "(ここでも、末尾にスペースがあります)
  6. "1000"

max_length読み込んだ現在のユーザー名とパスワードに基づくのではなくmax_length、大きな固定値を作成します(のように100)。

于 2012-06-26T21:29:59.777 に答える
1

エラーハンドラはwhileループ内にあります。ユーザーがファイルの最初でない場合は、すぐに中止します。Beterは次のように書きます。

…
        if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){
            printf("USER: %s - PASS: %s\n", tmp, tmp2);
            onexit(user, pass, line, fp, 4);
            return EXIT_SUCCESS;
        }
    }
    printf("no such user or pwd into DB\n");
    onexit(user, pass, line, fp, 4);
    return EXIT_FAILURE;
}

編集:

strtok: Successデータベースにスペースを入れずにエントリがある場合、問題を再現できます。ループがここまで進んでいる場合、これはファイルの最後の空の行である可能性もあります。その場合、最初のstrtokは文字列全体を返し、2番目のstrtokはNULLを返すため、トークンがこれ以上ないことを示します。これはエラーメッセージではないため、errnoステータスはゼロであり、「エラーメッセージ」に対応しますSuccess

あなたの場合、問題はレコードの長さが異なることにあると思います。行読み取りバッファーの長さは入力の長さで測定しますが、一部のレコードはそれより長くなります。その場合、行の一部を読み取ってそれを正しく分割し、次の実行で行の残りを読み取って、上記の動作を含め、スペースのない行のように見えるようにします。

于 2012-06-26T21:35:25.857 に答える