【问题标题】:Why can't I input a filename for opening in c?为什么我不能输入要在 c 中打开的文件名?
【发布时间】:2011-05-23 17:30:32
【问题描述】:

我一直在尝试以我有限的知识调试这个程序,并将它与其他程序进行了比较,在这些程序中我使用相同的方法来检索要打开的文件名。但是,由于某些奇怪的原因,该程序似乎没有收到用户输入的文件名,有时会陷入某种难以捉摸的循环。

我两个都用过: scanf("%s\n", 文件名);

和: 获取(文件名);

(我知道 get 是“危险的”,但这是一个不会分发的程序,它是大学水平课程的作业)

这里是 main() 函数和 getssn() 函数(成功获取用户输入):

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

#define MAXS 19
#define MAXR 999

//structure defining a given client
typedef struct person {
unsigned int ssn, age, height, weight, income;
char name[MAXS+1], job[MAXS+1], religion[MAXS+1], major[MAXS+1], minor[MAXS+1], gender;
}PERSON;


//get and check for ssn validity
int getssn(){
int num;

printf("\nSSN: ");
scanf("%d", &num);

if(num<=99999999 || num>999999999){
    printf("\nPlease input a valid SSN.\n");
    return 0;
}
else
    return num;
}

//read the specified file and check for the input ssn
int readfile(FILE *fptr, PERSON **rptr, int *count){
int v=0, i, j;
char n2[MAXS+1], b[2]=" ";

for(i=0; i<MAXR; i++){
    j=i;

    //read the file in chunks
    if(fscanf(fptr, "%c\n%d\n%19s %19s\n%d\n%19s\n%d\n%19s\n%19s\n%d\n%d\n%19s\n\n",
              &rptr[j]->gender, &rptr[j]->ssn, rptr[j]->name, n2, &rptr[j]->age, 
              rptr[j]->job, &rptr[j]->income, rptr[j]->major, rptr[j]->minor,
              &rptr[j]->height, &rptr[j]->weight, rptr[j]->religion)==EOF)
        i=MAXR;

    //make first and last name one element
    strcat(rptr[j]->name, b);
    strcat(rptr[j]->name, n2);

    //if we find a match, tell main the id
    if(rptr[MAXR]->ssn==rptr[j]->ssn)
        v=j;
}

//count how many clients we have
*count=j;

return v;
}

//commpare age and income
int cmpai(PERSON rec1, PERSON rec2){
int a=0, inc=0;

if(rec1.age<=(rec2.age+10) && rec1.age>=(rec2.age-10))
    a=1;
if(rec1.income<=(rec2.income+10000) && rec1.income>=(rec2.income-10000))
    inc=1;

if(a==1 && inc==1)
    return 1;
else 
    return 0;


}

//compare hobbies
int cmph(PERSON rec1, PERSON rec2){
if(strcmp(rec1.major,rec2.major)==0 && strcmp(rec1.minor, rec2.minor)==0)
    return 1;
else
    return 0;
}

//compare weight, height, and religion
int cmpwhr(PERSON rec1, PERSON rec2){
int w=0, h=0, r=0;
double n1, n2;

n1=rec1.height;
n2=rec2.height;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
    h=1;

n1=rec1.weight;
n2=rec2.weight;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
    w=1;

if(strcmp(rec1.religion, rec2.religion)==0)
    r=1;

if(r==1 && h==1 && w==1)
    return 1;
else 
    return 0;
}

//sort the ids in ascending order by ssn for proper output
void sort(int *A, int count){
int i, j, temp;

for(i=0; i<count; i++)
    for(j=0; j<count; j++)
        if(A[i+1]<A[i]){
            temp=A[i];
            A[i]=A[i+1];
            A[i+1]=temp;
        }
}

//display the possible matches in ascending ssn order
void display(int matches[], PERSON rec[], int count){
int i;

for(i=0; i<count; i++){
    if(matches[i]==rec[i].ssn)
        printf("%s\n", rec[i].name);
}
 }



int main(){
int valid=-1, i, counter=0, *c=&counter, id[MAXR-1], totalmatches;
char filename[MAXS];
FILE *fp;
PERSON record[MAXR+1], *rp[MAXR+1];

//get a ssn from the user
do{
    record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);

//get a filename
printf("Name of file of records: ");
scanf("%s", filename);
printf("%s", filename);

//open the file, if possible
if((fp=fopen(filename, "r"))==NULL)
    perror(filename);
else{
    printf("test");
    for(i=0; i<=MAXR; i++){
        rp[i]=&record[i];
        id[i]=0;
    }

    //read the file, find the matching ssn
    valid=readfile(fp, rp, c);

    //check if the ssn is in the file, if not tell the user
    if(valid<0){
        printf("\nSSN %d is not found in file %s.\n", record[MAXR].ssn, filename);
        return EXIT_FAILURE;
    }
    else {
        //check for matches and count how many we have
        for(i=0; i<counter; i++){
            if(i!=valid)
                if(record[valid].gender!= record[i].gender)
                    if(cmpai(record[valid], record[i])==1 || cmph(record[valid], record[i])==1 || cmpwhr(record[valid], record[i])==1){
                        id[i]=record[i].ssn;
                        totalmatches+=1;                        
                    }
        }
        //if we have matches sort them and display them, otherwise tell the user he has no match in this group
        if(totalmatches>0){
            sort(id, counter);
            display(id, record, counter);
        }
        else 
            printf("\nNo matches.\n");
        fclose(fp);
        return EXIT_SUCCESS;
    }
}
}

这是当前的输入(单引号)/输出:

run
[Switching to process 6956]
Running…

SSN: '111223333'
Name of file of records: 'clients.txt'
clients.txttest
Debugger stopped.
Program exited with status value:0.

【问题讨论】:

  • 如果您认为问题在于从用户那里获取文件名,那么与打开和读取文件有关的所有代码都无关紧要!尝试从您的 sn-p 中删除所有这些代码。
  • @Kabir,请对症状进行更多描述。我的理解如下,请直接确认或拒绝这些事实:你运行有scanf("%s\n", filename)的程序,然后你输入clients.txt,然后你按回车键,然后什么都没有发生?然后你耐心地坐着,直到你按下 Ctrl+D?当你按下 Ctrl+D 时会发生什么?如果是这样,我敦促您立即删除“\n”。
  • 按 ctrl+D 后它会打印“clients.txt”,这意味着它确实收到了输入,只是从未决定停止接收输入。我会尝试不使用 \n 并告诉你会发生什么
  • 优秀。 scanf ("%s\n", s) 表示“将一些非空白字符扫描到 s 中,然后等到用户输入 more 空白。”\n“(以及“\t”和“”)表示“等到用户输入了更多空白”。这就是为什么最好只使用scanf("%s")
  • 嗨@Kabir,我没有时间进一步考虑这个问题。我想恭敬地提出一些建议。首先,你的程序是一个非常大的程序,你不应该试图一次性构建一个巨大的程序并希望它能够工作。您应该构建一个小型工作程序并从那里开始构建。其次,您应该将printfs 放在整个代码中,在每一行代码之间——我认为我们不知道您的代码在哪里。这是基本的编程建议;即使当我对编程很陌生时,我也知道我应该做一些基本的事情(比如printfs)。

标签: c debugging file-io user-input scanf


【解决方案1】:

你应该使用你的 getssn() 函数。你需要输入一个return语句。

int getssn(){
   int num;

   printf("\nSSN: ");
   scanf("%d", &num);
   return num;  // You MUST put this in.
}

这将改进此代码:

do{
  record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);

如果忘记返回,getssn() 可能永远返回 0。

您还应该告诉我们您看到的确切输出。您还应该将所有输出复制到您的问题中。

【讨论】:

    【解决方案2】:

    永远不要使用任何scanf 系列函数;它们无法让您对无效输入发生的情况进行足够的控制,scanf("%s")gets 一样危险。

    但这可能不是您的直接问题。当文件不在当前工作目录中时,这更有可能是尝试通过部分路径名打开文件的情况。尝试输入完整的路径名(/home/kabir/filenameC:\users\kabir\filename 之类的)。还有,改变

    printf("\nCould not open file\n");
    

    perror(filename);
    

    会在出现问题时为您提供更多信息。

    【讨论】:

    • 我从来没有遇到过“无法打开文件”的情况,如果我通过按 ctrl-d 输入输入结束字符,程序会进入“else”语句......但是当我不要输入 ctrl-d 程序挂起,就好像它在等待输入一样。当我一步一步走时,它会无限期地说“步入……”
    • ...这很奇怪。这是什么环境?你是如何运行程序的?
    • 我已经尝试过 xcode 和 gcc,并且我已经使用相同的输入法在两种环境中测试了我以前的程序(以前的两个程序都使用 gets(filename) 而不是 scanf 但我怀疑那是问题)
    • 通过 gcc 我的意思是我使用终端和 ssh'd 到校园计算机中心使用 gcc 进行编译
    • @Kabir:如果您的代码正在输入该语句的“else”部分,那么那就是您需要向我们展示的代码,否则我们只能猜测发生了什么。
    【解决方案3】:

    应该是

    scanf("%s", filename)
    

    即删除\n

    无关,但你似乎忘记了getssn()末尾的return num

    查看您当前的代码(都柏林/伦敦时间晚上 8:10),您应该改用它:

    //get a filename
    printf("Name of file of records: ");
    //scanf("%s", filename);
    printf("scanned file: <%s>\n", filename);
    
    //open the file, if possible
    if((fp=fopen(filename, "r"))==NULL)
        perror(filename);
    else{
        printf("test\n");
        ...
    

    【讨论】:

    • 我试过 scanf("%s", filename) 产生相同的结果
    • 您可以尝试在 scanf 之后立即输入printf("scanned file: &lt;%s&gt;", filename); 吗?这是确保正确读取字符串的自然方法。 else {...} 内部会发生什么?这可能是您的代码中最重要的部分。
    • else 中的第一个语句是 printf 语句,除非我在初始化 'filename' 时定义文件(例如 char filename[MAXS]="clients.txt";),否则它永远不会到达那里。 ..当我这样做时,程序会立即完美执行
    • 只有当我尝试让用户输入任何内容时它才会挂起
    • 这就是为什么我需要你在 scanf() 之后 立即 放置一个 printf,以确保扫描正确。如果您在键入“clients.txt”后可以验证“clients.txt”在 file_name 中,那么我们有一些证据可以讨论。 scanf("%s", filename); printf("scanned file: &lt;%s&gt;", filename);
    猜你喜欢
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多