论坛: 编程破解 标题: grep-v#<filename> 复制本贴地址    
作者: kert_t8 [kert_t8]    论坛用户   登录
代码:

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

#define TXT_LENGTH 1024

int main(int argc, char *argv[]) {
if (argc!=2) {
printf("Command Usage: %s <filename>\n", argv[0]);
exit(-1);
}

FILE *fileName;
char *txtLine;

if ((fileName=fopen(argv[1], "r"))==NULL) {
printf("Open file %s failed.\n Exit program\n",argv[2]);
exit(-1);
}

txtLine=malloc(TXT_LENGTH);
char *head;
head=txtLine;

while (fgets(head, TXT_LENGTH, fileName)!=NULL) {
txtLine=head;
while (*txtLine++!='#')
if (*txtLine=='\0') {
printf("%s",head);
break;
}
}
free(head);
exit (0);
}



Syshunter 你厉害!我本来以为很简单,结果被耍了
当一行长度超过TXT_LENGTH的时候这个程序就无法输出正确结果.然而要命的是我又想不出一个方法能够比较高效的处理这种单行长度过长的情况

我花了半个小时写这个程序,然后花了将近一个小时研究怎么修改,结果还是没改出来
有没有标准答案?

你帮我看看, 一是程序效率上(C语言这个东西,我实在是), 还有就是正确性

地主 发表时间: 05-02-14 14:21

回复: jhkdiy [jhkdiy]   版主   登录
我想可以先测试一行文本的长度, 然后再动态分配内存,再处理。

B1层 发表时间: 05-02-14 17:54

回复: lida1818 [lida1818]   论坛用户   登录
while (*txtLine++!='#')//如遇#号准备如何处理?
if (*txtLine=='\0') //如果超过1024是原样打还是加"\n"?
{
    printf("%s",head);
    break;
}

B2层 发表时间: 05-02-14 22:14

回复: kert_t8 [kert_t8]   论坛用户   登录
如果是'#'就跳过此行,直接读下一行
如果存在一行的长度超过TXT_LENGTH就无法在此行输出正确的结果,会把前TXT_LENGTH个字符当作一整行读去,后面的当作一个新行,当然新行的长度也有可能仍然大于TXT_LENGT....

整个程序的目的本来是要模仿unix中的命令: grep -v '#' <filename>
无奈当一行的长度超过定长时我就没招了

[此贴被 月之御者(kert_t8) 在 02月15日08时55分 编辑过]

B3层 发表时间: 05-02-15 01:00

回复: SysHu0teR [syshunter]   版主   登录
还有个东西你没考虑到,有的行#前面是带空格的。

B4层 发表时间: 05-02-15 18:23

回复: SysHu0teR [syshunter]   版主   登录
我写了个,不过效率肯估计不行:
代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc,char *argv[])
{
        int flen;
        FILE    *fp1,*fp2;
        struct stat *f_stat=(struct stat *)malloc(sizeof(struct stat));

        char *buf;
        int i;
       
        if(argc!=3) {
                printf("usage: %s sourcefile destfile\n",argv[0]);
                exit(0);
        }
        if((fp1=fopen(argv[1],"r"))==NULL)
        {
                perror("fopen");
                exit(0);
        }

        if((fp2=fopen(argv[2],"w"))==NULL)
        {
                perror("fopen");
                exit(0);
        }
        if(lstat(argv[1],f_stat)!=0 )
        {
                perror("fstat");
                exit(0);
        }

        flen=f_stat->st_size;
        buf=(char *)malloc(flen);

        while(fgets(buf,flen,fp1)!=NULL)
        {
                for(i=0;i<flen-1&&buf[i]==' ';i++) ;
                if(i!=flen-1 && buf[i]!='#' )
                {
                        fputs(buf,fp2);
                }
        }


        printf("Write succeed!\n");
        fclose(fp1);
        fclose(fp2);
        return 1;
}



测试结果:
SysHu0teR_BSD# ./file data out
Write succeed!
SysHu0teR_BSD# cat data
#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
  ccccccc
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd#dddddddddddddddddddddddddddddddddd
SysHu0teR_BSD# cat out
  ccccccc
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd#dddddddddddddddddddddddddddddddddd
SysHu0teR_BSD#


B5层 发表时间: 05-02-15 20:03

回复: lida1818 [lida1818]   论坛用户   登录
fgets一般与fputs配合使用,这是因为对于"\0","\n"的处理与gets,puts,printf不同,所以我问你是不是要加"\n",还有一个,我看SysHu0teR的意思是"#"打头的行不要,而你的是含有“#”的行不要.unix不熟,如有错误莫怪.

B6层 发表时间: 05-02-15 20:17

回复: kert_t8 [kert_t8]   论坛用户   登录
引用:

[macavity@Macavity grep]$ ./a.out test.txt
1alskgd;alsdfkje;likajsldfkjelkjskdfjdkd
12
123
1234
123456
1234567
12345678
123456789
1234567890
123456789[macavity@Macavity grep]$ grep -v '#' test.txt
1alskgd;alsdfkje;likajsldfkjelkjskdfjdkd
12
123
1234
123456
1234567
12345678
123456789
1234567890
[macavity@Macavity grep]$
[macavity@Macavity grep]$ cat test.txt
#slkjdfe
1alskgd;alsdfkje;likajsldfkjelkjskdfjdkd
12
123
1234
123 #45
123456
1234567
12345678
123456789
1234567890
12345678901#
[macavity@Macavity grep]$






[此贴被 月之御者(kert_t8) 在 02月16日01时10分 编辑过]

B7层 发表时间: 05-02-16 01:00

回复: kert_t8 [kert_t8]   论坛用户   登录
这个,我也看糊涂了。
按照SysHuOteR的写法确实是如果#开头就不要,其余照收,但是这头当时让我写的时候我记得是写 grep -v '#' <filename> > outputfille 这么一个程序,所以我就....
他老早就跟我说了,我现在才写,所以也不记得他到底是说的什么了

倒不是需要加'\n'的问题,而是fgets所读的内容是文件的一行,但是内容的大小必须小于所提供的buf的大小,所以我无法保证一次真正的读入的是一整行。然而我的程序对读入内容的处理是按照一整行处理的,所以就.......................~~~

不过!!!!!!
SysHuOteR的程序一次就分配了整个文件的大小作为一行的buffer,我觉得这个方法很不经济啊。

B8层 发表时间: 05-02-16 01:19

回复: NetDemon [netdemon]   ADMIN   登录
下面是我的一个读取配置文件的函数,每次读入一行来处理。你可以参考一下。我是用fgetln()函数,这是bsd上标准库中的函数,linux没有,要改用gcc的readline()来完成。

代码:

void ReadConfigFile (const char* fileName)
{
int c;
char *buf;
size_t len;
char *ptr, *p;
char* option;
FILE *fp;
fp = fopen(fileName,"r");
if(fp == NULL){
MakeConfigFile(fileName);
/*perror("Read ConfigFile");*/
exit (1);
}
while ((buf = fgetln(fp, &len)) != NULL) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
else{
perror("config file format error: "
"last line should end with newline");
exit(1);
}
/*
* Check for comments, strip off trailing spaces.
*/
if ((ptr = strchr(buf, '#')))
*ptr = '\0';
for (ptr = buf; isspace(*ptr); ++ptr)
continue;
if (*ptr == '\0')
continue;
for (p = strchr(buf, '\0'); isspace(*--p);)
continue;
*++p = '\0';

/*
* Extract option name.
*/
option = ptr;
while (*ptr && !isspace (*ptr))
++ptr;

if (*ptr != '\0') {

*ptr = '\0';
++ptr;
}
/*
* Skip white space between name and parms.
*/
while (*ptr && isspace (*ptr))
++ptr;

ParseOption (option, *ptr ? ptr : NULL);
}
fclose(fp);
}




B9层 发表时间: 05-02-16 04:01

回复: kert_t8 [kert_t8]   论坛用户   登录
看到
代码:

if ((ptr = strchr(buf, '#')))
*ptr = '\0';]}


我就对要过滤掉'#'这个问题觉得有意义了(开始一直在想为什么要写一个这么诡异的程序),过滤掉文件中被注释掉的部分。我反应是不是比较慢

问题:
for (ptr = buf; isspace(*ptr); ++ptr)
        continue;

for (ptr = buf; isspace(*ptr); ++ptr);
完全一样的吗?功能当然是一样的,我问得是执行的时候....you know


还有就是,一个char *,比如叫strPtr。那么
while(*++strPtr);
是个什么意思?一直不太明白。我觉得就是和下面这个是一样的:
while(*++strPtr!='\0');
但是我经常看见不一样的写法同时存在于一个程序里面,我就糊涂了


另外就是,fgetln真是个好东西,你并没有给buf分配空间,fgetln帮你分配好,这个就比较厉害,完了还给你return一个length。不过问题是前一次循环完成以后,接下来又要buf = fgetln(fp, &len)。那么上一次buf的那些空间由谁来处理呢?在readline()里面说的是“the caller must free it when finished”,不知道fgetln怎么处理。我没有看到free(buf);

又,readline是从终端(terminal)读数据,跟从文件不一样啊

to SysHu0teR:
我的前面有空格也不怕





受益匪浅啊!

B10层 发表时间: 05-02-17 11:41

回复: SysHu0teR [syshunter]   版主   登录
引用:
问题:
for (ptr = buf; isspace(*ptr); ++ptr)
        continue;

for (ptr = buf; isspace(*ptr); ++ptr);
是完全一样的吗?功能当然是一样的,我问得是执行的时候....you know


这个要老大来回答,我在想是不是他为了增加可读性加上的。

引用:
还有就是,一个char *,比如叫strPtr。那么
while(*++strPtr);
是个什么意思?一直不太明白。我觉得就是和下面这个是一样的:
while(*++strPtr!='\0');
但是我经常看见不一样的写法同时存在于一个程序里面,我就糊涂了

\0在ASCII是0,可是有的编译器把NULL定义成0,有的定义成(void *)0。而且while对-1也是做true处理。

那个readline将读终端改成对文件读应该可以用dup2(fd,0)实现。不知道老大是不是这个意思。

一起学习


[此贴被 SysHu0teR(syshunter) 在 02月18日10时12分 编辑过]

B11层 发表时间: 05-02-18 10:04

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号