【问题标题】:Segmentation Fault when trying to implement cat command functionality尝试实现 cat 命令功能时出现分段错误
【发布时间】:2022-10-19 05:07:37
【问题描述】:

我正在尝试以“lolcat”的名称在 C 中创建自己的 cat 命令。它将读取命令行参数,例如文件名,打开该文件并以相反的顺序打印其内容。当我运行以下命令时,程序运行良好:

./lolcat 文件1.txt 它以相反的顺序打印文件内容。

但是当我尝试实现 -n 功能来计算总行数时。 如 ./lolcat -n 文件1.txt 它显示分段错误(核心转储)。

我附上了以下代码:

#include <stdio.h>

int main(int argc , char *argv[])
{

    printf("%s" , argv[1]);

    int command = 0;
    if(argv[1] == "-n")
    {
        command = 2;
    }
    else{
        command = 1;
    }





    for(int i = command ; i < argc ; i++)

    {

        FILE *myFile = NULL;
        myFile = fopen(argv[i] , "r");
        char word[255];
        char c;
        int  c_count = 0;
        int w_count = 0;
        int l_count = 0;
        int prev_c_count = 0;
        int x = 0;
        int out = 0;


        while((c = fgetc(myFile)) != EOF)
        {
            word[x] = c;
            c_count++;
            if(c == '\n' || c == '\0')
            {
                l_count++;

                    if(command == 1)
                    {
                        for(int j = c_count - 1 ; j>=prev_c_count ; j--)
                        {
                            printf("%c" , word[j]);
                        }

                    }

                prev_c_count = c_count;
            }

            x++;

        }

        printf("\n");

            l_count++;

                    if(command == 1)
                    {
                        for(int j = c_count - 1 ; j>=prev_c_count ; j--)
                        {
                            printf("%c" , word[j]);
                        }
                    }


            

            prev_c_count = c_count;

        printf("\n");



    }

    return 0;
}

【问题讨论】:

  • if(argv[1] == "-n") 不是您比较 C 字符串的方式...尝试strcmp()...因此,程序尝试打开一个名为“-n”的文件,但失败了,并且代码继续吸在那个干燥的管道上...当您不检查 fopen() 等系统调用的返回码时,您希望系统做什么?
  • argv[1] == "-n" 不是在 c 中进行字符串比较的定义方法。你的编译器应该警告你。
  • @possum:语法上 argv[1] 和 "-n" 都是指向 char 的指针,所以我猜编译器对此很满意。 (当然它们总是指向不同的内存区域,所以它们总是不同的)

标签: c linux


【解决方案1】:

分段错误的原因是您的代码试图在行中的空 FILE 流指针上运行 fgetc()

while((c = fgetc(myFile)) != EOF)

这会导致 libc 在尝试读取文件内容时尝试取消引用空指针。

正如 cmets 中所述,根本原因是因为您正在比较两个 char 指针 (char *):

if(argv[1] == "-n")

然后根据该比较设置command 变量,然后将i 设置为此命令值。由于代码将始终进入else 块,因此命令将从 1 开始。

然后你有这些行:

FILE *myFile = NULL;
myFile = fopen(argv[i], "r");

如果command1,因此i 以1 开头,则fopen() 调用的第一个参数将是argv[1],即,如果您运行$ ./lolcat -n file1.txt,则为“-n”字符串。因为(可能)没有“-n”文件。 (有趣的事实:我努力创建了一个名为“-n”的文件,如果该文件存在,您的代码可以很好地读取文件)

如何修复它

最简单(也是最快)的代码修复方法是将您的 if 行(我提到的根本原因)替换为:

if(strcmp(argv[1], "-n") == 0)

请记住,虽然 C 支持字符串,但它没有字符串类型。您的编译器在内存的某个区域构建具有字符串的二进制文件,并且它具有处理字符串的函数。但是,char * 不是字符串,而是指向 char(字符串的第一个字符)的指针。由于字符串以 null 结尾,因此 strcmp() 之类的函数会迭代到从指向的字符开始的内存区域指针,直到它找到一个空字符;那里的字符串函数知道字符串结束了。

因此,虽然它适用于“学习项目”,但在生产中使用并不安全,因为攻击者可能很容易使您的程序陷入(几乎)无限循环。

其他问题

我可以在您的代码中看到其他一些可能的问题:

  1. 由于您将word 静态分配为一个 255 个字符的数组,如果您得到的行包含超过 255 个字符,您的代码将出现缓冲区溢出。
  2. 如果没有传递任何参数,当您检查它以定义command 的值时,argv[1] 将是一个空指针。因此,strcmp() 将取消引用空指针,您将遇到分段错误。每次取消引用指针或运行执行此操作的函数时,都必须检查指针的值(检查函数文档/规范;但如果函数接收指针参数,它可能会这样做。

    提示:为了让你的生活更轻松,你可能想看看 getopt 库来解析命令行参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 2015-08-27
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多