1

这是文件auth.txt (用户名密码)
paolo 1234
luca 0000
marci 1000

这是我的代码:

#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);
    }
}

编辑:另一个问题!
如果我想测试我得到:lucaInserire utente:luca Inserire 密码:0000 strtok:成功 并且程序停止。它仅适用于第一个和第三个输入,但不适用于第二个!为什么??0000






4

2 回答 2

3

看起来你的while循环只会经历一次迭代:

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;
  }
}

……这似乎有点好笑。如果您阅读的第一行不匹配,您真的要退出吗?


编辑:

另一个问题:您需要在将它们发送userpass之前分配空间scanf

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

取而代之的是,您可以尝试以下操作:

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

(在您的版本中,scanf将尝试将数据写入指向的位置user,但user只是指向内存中的随机位置,所以谁知道会发生什么。)

哎呀,正如@MvG 指出的那样,这很好。我不熟悉“%ms”POSIX 扩展。


编辑 2

假设您输入用户名uu和密码pp。因为这:

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

...您将设置max_length2 + 2 + 3, 或7. fgets将读取数据,直到它遇到最多max_length-1字符或换行符。这意味着当您进入while循环时,您只会尝试每次迭代最多读取7-1或读取6字符,这似乎不正确。

例如,如果您的密码文件包含:

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 循环内。如果用户不是文件中的第一个用户,则立即中止。最好这样写:

…
        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 将返回整个字符串,第二个 strtok 将返回 NULL,从而表明没有更多的标记。由于这不是错误消息,因此 errno 状态为零,对应于“错误消息” Success

我想在你的情况下,问题在于记录的长度不同。您通过输入的长度来测量行读取缓冲区的长度,但有些记录更长。在这种情况下,您读取了一行的一部分并将其正确拆分,然后在下一次运行时,您读取了该行的其余部分,并最终得到一个看起来像没有空格的行,包括我上面描述的行为。

于 2012-06-26T21:35:25.857 回答