4

我想编写一个 C 代码来查找 C 文件中的所有函数并打印相应的函数名称。

我的代码是:

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

#define SIZE 1024
void ffname(char *line)
{
    int i=1,j=0;
    char *dt; 
    char *name;
    strtok(line,"("); 
    dt = strchr(line,' '); 
    if(dt[i] == '*')
        i++;
    while(dt[i] != '\0')
    {
        name[j]=dt[i];
        i++;
        j++;
    }
    name[j] ='\0';
    printf("Function name is: %s\n", name);
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {
        printf("Give the filename \n");
        printf("Usage: %s filename\n", argv[0]);
        return -1;
    }
    int i, lines =0, funlines =0,count =0, fn =0, flag =0;
    char c[100],b[100];
    FILE *fd;
    fd = fopen(argv[1],"r");
    while(fgets(c,SIZE,fd))
    {   
        lines++;
        i=0;
        for(i=0;i<strlen(c);i++)
        {
            while( c[i] =='\t' || c[i] == ' ')
            {
                i++;
            }
            if( c[i] == '{')
            {
                count++;
                if(flag)
                {
                    funlines++;
                }
                if(count == 1)
                {
                    fn++;
                    printf("Function %d is Started..............\n", fn); 
                    flag = 1;
                    ffname(b);
                }
                break;
            }
            else if( c[i] == '}')
            {
                count--;
                if(!count)
                { 
                    flag = 0;
                    printf("No of lines in the function %d is: %d\n", fn, funlines);
                    printf("Function %d is finished..........\n", fn);
                    funlines = 0;
                }
                else
                {
                    funlines++;
                }
                break;
            }
            else if(flag)
            {
                funlines++;
                break;
            }
        }
        strcpy(b,c);
    }
    printf("Total no of fucnion%d\n",fn);
    printf("Total no of lines%d\n",lines);
    return 0;
}

当我将以下 C 文件作为输入时,

#include<stdio.h>
void add()
{
    int a=5,b=7;
    printf("Addition is:%d\n", a+b);
}
void sub()
{
    int a=20,b=8;
    printf("Subtraction is:%d\n", a-b);
}
void main()
{   
    char *name="dhahira dhasneem";
    char *line;
    line=strchr(name,' ');
    printf("Line:%s\n",line);
    printf("Name:%s\n",name);
    add();
    sub();
}

我得到以下输出。

Function 1 is Started..............
Segmentation fault (core dumped)

我使用valgrind,但我不知道如何识别错误。请指导我。谢谢你。

更新:

当我使用建议的答案时,我得到了输出。之后,我想扩展我之前的代码,将函数的详细信息(函数名称和函数深度)存储到一个结构中。当我用来存储简单程序的功能详细信息时,我得到了输出。但是当我在gdb.

(gdb) b 87
Breakpoint 1 at 0x804885e: file fun_printstruct.c, line 87.
(gdb) r dat.c
Starting program: /home/dhahira/dhas/Project/a.out dat.c
Function 1 is Started..............

Program received signal SIGSEGV, Segmentation fault.
0x080485d4 in ffname (line=0xbfffe71c "/*struct *dhahira", name=0x0)
    at fun_printstruct.c:21
21          name[j]=dt[i];
(gdb) s

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

我的代码是:(扩展用于将功能细节存储到结构中)

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

#define SIZE 1024
void ffname(char *line)
{
    int i=1,j=0;
    char *dt; 
    char name[SIZE];
    strtok(line,"("); 
    dt = strchr(line,' '); 
    if(dt[i] == '*')
        i++;
    while(dt[i] != '\0')
    {
        name[j]=dt[i];
        i++;
        j++;
    }
    name[j] ='\0';
    printf("Function name is: %s\n", name);
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {
        printf("Give the filename \n");
        printf("Usage: %s filename\n", argv[0]);
        return -1;
    }
    int i, lines =0, funlines =0,count =0, fn =0, flag =0, fg=0,size=0,emptyflag=0,commandflag=0;
    char c[SIZE],b[SIZE],st[SIZE],d[SIZE];
    int command[]={};
    FILE *fd;
    fd = fopen(argv[1],"r");
    while(fgets(c,SIZE,fd))
    {
        emptyflag=0;    
        lines++;
        for(i=0;i<(sizeof(command)/4);i++)
        {
            if(lines == command[i])
            {
                commandflag=1;
                break;
            }   
        }
        strcpy(st,c);
        strtok(st," ");
        size = strlen(c);
        if(size == 1 && (strcmp(c,"\n"))== 0)
            emptyflag=1;
        if( !strcmp(st,"struct")) 
            fg=1;
        for(i=0;i<size;i++)
        {
            if(commandflag)
            {
                break;
            }   
            while( c[i] =='\t' || c[i] == ' ')
            {
                i++;
            }
            if( c[i] == '{')
            {
                count++;
                if(flag)
                {
                    if(!emptyflag)
                        funlines++;
                    else
                        emptyflag=0;
                }
                if(count ==1 && fg ==1)
                {
                    if(b[strlen(b)-2] == ')')
                    {
                        fn++;
                        printf("Function %d is Started..............\n", fn); 
                        flag = 1;
                        ffname(b);
                    }   
                    else
                    {
                        count--;
                    }   
                }
                else if(count == 1)
                {
                    fn++;
                    printf("Function %d is Started..............\n", fn); 
                    flag = 1;
                    ffname(b);
                }
                break;
            }
            else if( c[i] == '}')
            {
                count--;
                if(count ==0 && fg ==1)
                { 
                    flag = 0;
                    printf("No of lines in the function %d is: %d\n", fn, funlines);
                    printf("Function %d is finished..........\n", fn);
                    funlines = 0;
                    fg=0;
                }
                else if(count ==0)
                {
                    flag = 0;
                    printf("No of lines in the function %d is: %d\n", fn, funlines);
                    printf("Function %d is finished..........\n", fn);
                    funlines = 0;
                }
                else if(count == -1)
                {
                    count=0;
                    fg=0;
                }
                else 
                {
                    if(!emptyflag)
                        funlines++;
                    else
                        emptyflag=0;
                }
                break;
            }
            else if(flag ==1 && fg==1)
            {
                if(!emptyflag)
                    funlines++;
                else
                    emptyflag=0;
                break;
            }
            else if(flag)
            {
                if(!emptyflag)
                    funlines++;
                else
                    emptyflag=0;
                break;
            }
            break;
        }
        if(commandflag == 1)
            commandflag = 0;
        else
            strcpy(b,c);
    }
    printf("Total no of fucnion%d\n",fn);
    printf("Total no of lines%d\n",lines);
    return 0;
}

请指导我克服这个问题。

这个问题是因为扩展代码而出现的吗?(我可以单独得到正确的输出。)

4

1 回答 1

4

您声明SIZE为 1024,然后读入长度为 100 的数组:

#define SIZE 1024
// ... snip ....
    char c[100],b[100];
    FILE *fd;
    fd = fopen(argv[1],"r");
    while(fgets(c,SIZE,fd))

这意味着您的写入远远超出了数组的范围,写入了堆栈的其余部分,并导致了损坏。在这种情况下,这可能实际上不会发生,因为您输入文件中的行都在 100 个字符以下,但如果有人传入一个长行的文件,它可能会发生。

这应该是

    char c[SIZE],b[SIZE];

sizof()fgets()通话中使用:

fgets(c,sizeof(c),fd)

正如其他人所指出的,最好打开所有可用的警告;这将帮助您更快地发现错误。在 GCC 或 Clang 中,我会推荐-Wall -Wextra -Werror;这将启用所有常见警告,并导致警告被视为错误,因此您不能忽略它们。如果我在您的代码上运行它,我还会收到以下警告:

sf.c:16:9: error: variable 'name' is uninitialized when used here
      [-Werror,-Wuninitialized]
        name[j]=dt[i];
        ^~~~
sf.c:9:15: note: initialize the variable 'name' to silence this warning
    char *name;
              ^
               = NULL
sf.c:40:18: error: comparison of integers of different signs: 'int' and 'size_t'
      (aka 'unsigned long') [-Werror,-Wsign-compare]
        for(i=0;i<strlen(c);i++)
                ~^~~~~~~~~~

第二个不是什么严重的问题,只需强制转换或声明i无符号即可;第一个你应该修复。您需要在堆栈上(char name[SIZE];或类似的)或动态的(或类似的char *name = malloc(strlen(line));东西)为 name 分配一个缓冲区。实际上,name是一个未初始化的指针;它可以指向内存中的任何位置,一旦您尝试通过在 中存储某些内容来取消引用它name[j],您正在写入无效的内存区域并获得段错误。

最后,一旦你解决了这些问题,如果你还有其他问题,我建议你在调试器下运行它,看看问题出现在哪里。如果您使用的是 IDE,它可能内置了调试器接口;如果没有,用 编译-g,然后运行gdb executable arguments

于 2012-12-19T06:24:46.427 回答