急求!重谢!C语言简单小问题!

D_CHRIS 2015-09-06 03:03:04
这是统计字母,空格,段落等的小程序,但是由于段落的标志是回车键也就是\n,现在情况是文本文件最后一段如果没有回车键的话就少一段,求优化方案。重谢!


#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp1, *fp2; /*定义两个指向FILE类型结构体的指针变量*/
char filename1[100],filename2[100],ch; /*定义数组变量为字符型*/
long character,word,sentence,paragraph; /*定义变量为长整型*/
character=word=sentence=paragraph=0; /*长整型变量的初值均为0*/
printf("Enter file name \n");
scanf("%s", filename1); /*输入要进行统计的文件的路径及名称*/
if((fp1=fopen(filename1, "r"))==NULL) /*以只读方式打开指定文件*/
{
printf("cannot open file.\n");
exit(1);
}
printf ( "Enter file name for write data:\n");
scanf("%s",filename2); /*输入文件名即将统计结果放到那个文件中*/
if((fp2=fopen(filename2, "w"))==NULL) /*已可写方式要存放统计结果的文件*/
{
printf("cannot open file \n");
exit(1);
}
while((ch=fgetc(fp1))!=EOF) /*知道文件内容结束处停止while循环*/
{
if(ch>='A' && ch<'Z'||ch>='a' && ch<='z')
{
character++;
} /*当遇到字母时字符个数+1*/
else if(ch==' ')
{
character++;
word++;
} /*当遇到空格时字符数+1*/
else if(ch>='0' && ch<='9')
{
character++;
} /*当遇到数字时数字个数+1*/
else if(ch=='.'||ch=='!'||ch=='?')
{
sentence++;
character++;
} /*当遇到.!?时句子数+1,字符数+1*/
else if ((ch=='\r')||(ch=='\n'))
{ paragraph++;
} /*当遇到换行符时段落数+1*/
else
{
character++;
word++;
} /*遇到其他字符时字符个数+1*/
ch++;
}

fclose(fp1); /*关闭fp1指向的文件*/
fprintf(fp2,"character:%ld word:%ld sentence:%ld paragraph:%ld\n", character, word, sentence,paragraph);/*将统计结果写入fp指向的磁盘文件中*/
fclose(fp2);
}
...全文
303 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
lkjasdf9909 2015-09-11
  • 打赏
  • 举报
回复
到达文件末尾的时候,可以让文件位置指针后退2位,去读取最后一个字符,这样你不就知道最后一个字符是不是‘\n’ 如果是'\n'的话,段落数+1,不是的话,就不用加1了
苏叔叔 2015-09-08
  • 打赏
  • 举报
回复
引用 18 楼 zhao4zhong1 的回复:
[quote=引用 17 楼 zhangxiangDavaid 的回复:] [quote=引用 7 楼 zhao4zhong1 的回复:] 仅供参考:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char ln[MAXLEN];
FILE *f;
int i,z;
int b,n,L;
int main(int argc,char **argv) {
    if (argc<2) {
        printf("Usage:%s fullpathfilename.ext\nget total blank/non-blank/total linenumbers.\n",argv[0]);
        return 1;
    }
    f=fopen(argv[1],"r");
    if (NULL==f) {
        printf("Can not open file [%s]!\n",argv[1]);
        return 2;
    }
    z=0;
    b=0;
    n=0;
    L=0;
    while (1) {
        if (NULL==fgets(ln,MAXLEN,f)) break;
        L=strlen(ln);
        if ('\n'==ln[L-1]) {
            if (0==z) {
                for (i=0;i<L-1;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L-1) z=1;//当前行不是空行
            }
            if (0==z) b++; else n++;
            z=0;
        } else {
            if (0==z) {
                for (i=0;i<L;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L) z=1;//当前行不是空行
            }
        }
    }
    fclose(f);
    if (L>0 && '\n'!=ln[L-1]) {
        if (0==z) b++; else n++;//最后一行末尾无'\n'也计算
    }
    printf("File:[%s] total blank/non-blank/total linenumbers is %d/%d/%d\n",argv[1],b,n,b+n);
    return 0;
}
变量z的含义是什么?[/quote] 你猜。[/quote] 我猜: z的含义表面上看是标记非空行,但在处理超长行时有特殊用途: 如果z为1,表明当前行非空,则只需读完改行剩下的内容即可。 否则,需要对当前读到的内容进行判断。
赵4老师 2015-09-08
  • 打赏
  • 举报
回复
引用 17 楼 zhangxiangDavaid 的回复:
[quote=引用 7 楼 zhao4zhong1 的回复:] 仅供参考:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char ln[MAXLEN];
FILE *f;
int i,z;
int b,n,L;
int main(int argc,char **argv) {
    if (argc<2) {
        printf("Usage:%s fullpathfilename.ext\nget total blank/non-blank/total linenumbers.\n",argv[0]);
        return 1;
    }
    f=fopen(argv[1],"r");
    if (NULL==f) {
        printf("Can not open file [%s]!\n",argv[1]);
        return 2;
    }
    z=0;
    b=0;
    n=0;
    L=0;
    while (1) {
        if (NULL==fgets(ln,MAXLEN,f)) break;
        L=strlen(ln);
        if ('\n'==ln[L-1]) {
            if (0==z) {
                for (i=0;i<L-1;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L-1) z=1;//当前行不是空行
            }
            if (0==z) b++; else n++;
            z=0;
        } else {
            if (0==z) {
                for (i=0;i<L;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L) z=1;//当前行不是空行
            }
        }
    }
    fclose(f);
    if (L>0 && '\n'!=ln[L-1]) {
        if (0==z) b++; else n++;//最后一行末尾无'\n'也计算
    }
    printf("File:[%s] total blank/non-blank/total linenumbers is %d/%d/%d\n",argv[1],b,n,b+n);
    return 0;
}
变量z的含义是什么?[/quote] 你猜。
苏叔叔 2015-09-08
  • 打赏
  • 举报
回复
引用 7 楼 zhao4zhong1 的回复:
仅供参考:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char ln[MAXLEN];
FILE *f;
int i,z;
int b,n,L;
int main(int argc,char **argv) {
    if (argc<2) {
        printf("Usage:%s fullpathfilename.ext\nget total blank/non-blank/total linenumbers.\n",argv[0]);
        return 1;
    }
    f=fopen(argv[1],"r");
    if (NULL==f) {
        printf("Can not open file [%s]!\n",argv[1]);
        return 2;
    }
    z=0;
    b=0;
    n=0;
    L=0;
    while (1) {
        if (NULL==fgets(ln,MAXLEN,f)) break;
        L=strlen(ln);
        if ('\n'==ln[L-1]) {
            if (0==z) {
                for (i=0;i<L-1;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L-1) z=1;//当前行不是空行
            }
            if (0==z) b++; else n++;
            z=0;
        } else {
            if (0==z) {
                for (i=0;i<L;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L) z=1;//当前行不是空行
            }
        }
    }
    fclose(f);
    if (L>0 && '\n'!=ln[L-1]) {
        if (0==z) b++; else n++;//最后一行末尾无'\n'也计算
    }
    printf("File:[%s] total blank/non-blank/total linenumbers is %d/%d/%d\n",argv[1],b,n,b+n);
    return 0;
}
变量z的含义是什么?
lm_whales 2015-09-08
  • 打赏
  • 举报
回复
这样理解是对的,你把错误的地方修改一下看看
D_CHRIS 2015-09-07
  • 打赏
  • 举报
回复
引用 14 楼 lm_whales的回复:
1)ch 必须改为 int 类型, 因为 (ch=fgetc(fp1)) 同样是 ch类型的 和 EOF 比较是有问题的 2)多定义一个 字符类型,不如直接计算最后一行的长度简单明了 3) ch++; //这个++ 是不对的 ch 是从文件读到的数据 不用++,这个++ 造成 ch,ch2 通常不会 ‘\n' ch2=ch; // 这是做什么用的?
首先谢谢指正前面的错误。ch2=ch是想保存跳出while之前的最后一个字符,我觉得是ch==EOF之前的字符也就是文本中最后一个字符。如果ch2是\n,那段落数就少加一个。不谈前面的错误,这样的理解哪里有问题?为什么实现不了段落数的正确获取?
lm_whales 2015-09-06
  • 打赏
  • 举报
回复
1)ch 必须改为 int 类型, 因为 (ch=fgetc(fp1)) 同样是 ch类型的 和 EOF 比较是有问题的 2)多定义一个 字符类型,不如直接计算最后一行的长度简单明了 3) ch++; //这个++ 是不对的 ch 是从文件读到的数据 不用++,这个++ 造成 ch,ch2 通常不会 ‘\n' ch2=ch; // 这是做什么用的?
D_CHRIS 2015-09-06
  • 打赏
  • 举报
回复
引用 11 楼 lm_whales 的回复:
这个 读到文件结束,在上一个段落和文件结束前,有文字那就添加一个段落 如果,换行后(段落后)紧接着就是文件结束了,那就不用添加这个段落。 这是个+1 ,-1 的问题,处理一下就好。
我试了一下,在程序上加了这么一小段,(printf单纯为了测试这个if语句能不能运行),可是当测试文本末尾有\n,if语句也没有运行,是不是EOF不能作为文件最后一个字符用?
		else
		{
			character++;
			word++;
		}          /*遇到其他字符时字符个数+1*/
		ch++;
		ch2=ch;
	}
	if(ch2=='\n')
	{
		printf("a");
		character++;
	}
lm_whales 2015-09-06
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *fp1, *fp2; /*定义两个指向FILE类型结构体的指针变量*/
   int ch;// 定义整型,用来读取字符
   long paraglen =0;//定义段长
    char filename1[100],filename2[100] ; /*定义数组变量为字符型*/
    long character,word,sentence,paragraph; /*定义变量为长整型*/
    character=word=sentence=paragraph=0; /*长整型变量的初值均为0*/
    printf("Enter file name \n");
    scanf("%s", filename1); /*输入要进行统计的文件的路径及名称*/
    if((fp1=fopen(filename1, "r"))==NULL) /*以只读方式打开指定文件*/
    {
        printf("cannot open file.\n");
        exit(1);
    }
    printf ( "Enter file name for write data:\n");
    scanf("%s",filename2); /*输入文件名即将统计结果放到那个文件中*/
    if((fp2=fopen(filename2, "w"))==NULL) /*已可写方式要存放统计结果的文件*/
    {
        printf("cannot open file \n");
        exit(1);
    }
    while((ch=fgetc(fp1))!=EOF) /*知道文件内容结束处停止while循环*/
    {
        paraglen++;//每读取一个字符,段长加一
        if(ch>='A' && ch<'Z'||ch>='a' && ch<='z')
        {
            character++;
        }          /*当遇到字母时字符个数+1*/
        else if(ch==' ')
        {
            character++;
            word++;
        }          /*当遇到空格时字符数+1*/
        else if(ch>='0' && ch<='9')
        {
        character++;
        }          /*当遇到数字时数字个数+1*/
        else if(ch=='.'||ch=='!'||ch=='?')
        {
            sentence++;
            character++;
        }          /*当遇到.!?时句子数+1,字符数+1*/
        else  if ((ch=='\r')||(ch=='\n'))
        {    paragraph++;
             paraglen = 0;//段长,实际上是行长,每当换行就清零
        }                /*当遇到换行符时段落数+1*/
        else
        {
            character++;
            word++;
        }          /*遇到其他字符时字符个数+1*/
        ch =0;
    }
        if(paraglen)
               paragraph++;  /*遇到段长非零,表示读到 文件结束,最后一个段(行),没有计算所以,段(行)数加一*/
               /* (或者读出错,这里不考虑读文件出错),需要的话,使用ferror 函数,读取文件错误码 */

        fclose(fp1);      /*关闭fp1指向的文件*/
        fprintf(fp2,"character:%ld word:%ld sentence:%ld paragraph:%ld\n", character, word, sentence,paragraph);/*将统计结果写入fp指向的磁盘文件中*/
        fclose(fp2);
        while(getchar()!='q');
}
这是修改后的代码 ch ++ 是不必要的,因为ch 是从文件里读出来的,需要的话,重置为 0
lm_whales 2015-09-06
  • 打赏
  • 举报
回复
这个 读到文件结束,在上一个段落和文件结束前,有文字那就添加一个段落 如果,换行后(段落后)紧接着就是文件结束了,那就不用添加这个段落。 这是个+1 ,-1 的问题,处理一下就好。
D_CHRIS 2015-09-06
  • 打赏
  • 举报
回复
引用 9 楼 lm_whales 的回复:
谢谢详解,我想再问个问题,我之前考虑的优化方案是再定义一个ch2,用来存放从文件读取的ch上一个值,大概想法是如果ch=EOF,ch2!=\n时,段落数++,请问把EOF作为从文件中读到的最后一个字符,这样的做法合理吗?可行吗?或者有什么能够定义文本文件最后一个字符的?(因为想在源程序的基础上进行较少的改动,对于之前楼层提出的建议会采纳再写一个程序)
不是合不合理的问题,而是取舍的问题, 当时这么定义的读写文件的函数,自然有他的考量。[/quote]那请问一下我可不可以做较小程度的修改来实现段落数的正确统计,因为段落数是以回车为标志的,如果最后一段没有回车就少统计一个。能不能帮忙看一下我对修改段落数统计的想法,谢谢。
lm_whales 2015-09-06
  • 打赏
  • 举报
回复
引用 8 楼 D_CHRIS 的回复:
[quote=引用 6 楼 赵4老师的回复:]char ch;//会导致无法区分到底是读到了0xFF字符还是到了文件末尾。
谢谢详解,我想再问个问题,我之前考虑的优化方案是再定义一个ch2,用来存放从文件读取的ch上一个值,大概想法是如果ch=EOF,ch2!=\n时,段落数++,请问把EOF作为从文件中读到的最后一个字符,这样的做法合理吗?可行吗?或者有什么能够定义文本文件最后一个字符的?(因为想在源程序的基础上进行较少的改动,对于之前楼层提出的建议会采纳再写一个程序)[/quote] 不是合不合理的问题,而是取舍的问题, 当时这么定义的读写文件的函数,自然有他的考量。
D_CHRIS 2015-09-06
  • 打赏
  • 举报
回复
引用 6 楼 赵4老师的回复:
char ch;//会导致无法区分到底是读到了0xFF字符还是到了文件末尾。
谢谢详解,我想再问个问题,我之前考虑的优化方案是再定义一个ch2,用来存放从文件读取的ch上一个值,大概想法是如果ch=EOF,ch2!=\n时,段落数++,请问把EOF作为从文件中读到的最后一个字符,这样的做法合理吗?可行吗?或者有什么能够定义文本文件最后一个字符的?(因为想在源程序的基础上进行较少的改动,对于之前楼层提出的建议会采纳再写一个程序)
赵4老师 2015-09-06
  • 打赏
  • 举报
回复
仅供参考:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char ln[MAXLEN];
FILE *f;
int i,z;
int b,n,L;
int main(int argc,char **argv) {
    if (argc<2) {
        printf("Usage:%s fullpathfilename.ext\nget total blank/non-blank/total linenumbers.\n",argv[0]);
        return 1;
    }
    f=fopen(argv[1],"r");
    if (NULL==f) {
        printf("Can not open file [%s]!\n",argv[1]);
        return 2;
    }
    z=0;
    b=0;
    n=0;
    L=0;
    while (1) {
        if (NULL==fgets(ln,MAXLEN,f)) break;
        L=strlen(ln);
        if ('\n'==ln[L-1]) {
            if (0==z) {
                for (i=0;i<L-1;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L-1) z=1;//当前行不是空行
            }
            if (0==z) b++; else n++;
            z=0;
        } else {
            if (0==z) {
                for (i=0;i<L;i++) {
                    if (!(' '==ln[i] || '\t'==ln[i])) break;
                }
                if (i<L) z=1;//当前行不是空行
            }
        }
    }
    fclose(f);
    if (L>0 && '\n'!=ln[L-1]) {
        if (0==z) b++; else n++;//最后一行末尾无'\n'也计算
    }
    printf("File:[%s] total blank/non-blank/total linenumbers is %d/%d/%d\n",argv[1],b,n,b+n);
    return 0;
}
赵4老师 2015-09-06
  • 打赏
  • 举报
回复
char ch;//会导致无法区分到底是读到了0xFF字符还是到了文件末尾。
D_CHRIS 2015-09-06
  • 打赏
  • 举报
回复
引用 3 楼 赵4老师的回复:
char ch; 应改为 int ch;
定义为char的目的就是为了读取文件中的字符,如果改为int类型是否也能实现同样的功能呢?
赵4老师 2015-09-06
  • 打赏
  • 举报
回复
将while语句中的条件判断挪到while循环的第一句或中间某句或最后一句视具体情况而定。
赵4老师 2015-09-06
  • 打赏
  • 举报
回复
char ch; 应改为 int ch;
D_CHRIS 2015-09-06
  • 打赏
  • 举报
回复
引用 1 楼 赵4老师的回复:
不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
 if (条件1) break;
 //...
 if (条件2) continue;
 //...
 if (条件3) return;
 //...
}
因为前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
while (!feof(f)) {
 a=fgetc(f);
 //...
 b=fgetc(f);//可能此时已经feof了!
 //...
}
而这样写就没有问题:
while (1) {
 a=fgetc(f);
 if (feof(f)) break;
 //...
 b=fgetc(f);
 if (feof(f)) break;
 //...
}
类似的例子还可以举很多。
不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
 if (条件1) break;
 //...
 if (条件2) continue;
 //...
 if (条件3) return;
 //...
}
因为前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
while (!feof(f)) {
 a=fgetc(f);
 //...
 b=fgetc(f);//可能此时已经feof了!
 //...
}
而这样写就没有问题:
while (1) {
 a=fgetc(f);
 if (feof(f)) break;
 //...
 b=fgetc(f);
 if (feof(f)) break;
 //...
}
类似的例子还可以举很多。
[/quote] 那请问基于我的程序怎么改呢
赵4老师 2015-09-06
  • 打赏
  • 举报
回复
不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
 if (条件1) break;
 //...
 if (条件2) continue;
 //...
 if (条件3) return;
 //...
}
因为前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
while (!feof(f)) {
 a=fgetc(f);
 //...
 b=fgetc(f);//可能此时已经feof了!
 //...
}
而这样写就没有问题:
while (1) {
 a=fgetc(f);
 if (feof(f)) break;
 //...
 b=fgetc(f);
 if (feof(f)) break;
 //...
}
类似的例子还可以举很多。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧