我有一个模拟shell,具有运行bash文件的能力,需要shell支持!!,echo和exit,这就是我到目前为止所做的:

void run_file(char* file){
    int i;
    char* echo = "echo";
    char* ex = "exit";
    char* prev_f = (char*)malloc(sizeof(char)*MAX_CMD_BUFFER);
    char* nline = "\n";
    char* bang = "!!";
    char check[5];
    char c_bang[3];
    char c_nline[2];
    
    c_nline[1] = '\0';
    FILE *fp = fopen(file, "r");
    char line[MAX_CMD_BUFFER];
    size_t len = 0;
    ssize_t read;
    if (fp == NULL)
        exit(EXIT_FAILURE);
    while((read = getline(&line, &len, fp)) != -1){
        for(i = 0; i < 4; i++){
            check[i] = line[i];
            if(i < 2){
                c_bang[i] = line[i];
            }
        }
        c_nline[0]=line[0];
        check[4] = '\0';
        c_bang[3] = '\0';
        if(strcmp(c_nline, nline) == 0){continue;}
        else if(strcmp(check, echo) == 0){
            i = 5;
            if (line[5] =='\n')
            {
                continue;
            }
            while(line[i] != '\n'){
                printf("%c", line[i]);
                i++;
            }
            strcpy(prev_f, line);
        }
        else if(strcmp(c_bang, bang) == 0){
            if(*prev_f == NULL){continue;}
            i = 0;
            for(i = 0; i < 4; i++){
                check[i] = prev_f[i];
            }
            check[4] = '\0';
            if(strcmp(check, echo) == 0){
                i = 5;
                if (prev_f[5] == '\n'){
                    continue;
                }
                while(prev_f[i] != '\n'){
                    printf("%c", prev_f[i]);
                    i++;
                }
            }
            else if(strcmp(check, ex) == 0){
                char val[3];
                for(i = 5; i < 8; i++){
                    val[i - 5] = prev_f[i];
                }
                int v = atoi(val);
                if(v > 255){v = 255;}
                printf("bye!\n");
                exit(v);
            }
            else{
                printf("invalid previous command");
            }
        }
        else if(strcmp(check, ex) == 0){
            char val[3];
            for(i = 5; i < 8; i++){
                val[i - 5] = line[i];
            }
            int v = atoi(val);
            if(v > 255){v = 255;}
            printf("$ echo $?\n");
            printf("%d\n$", v);
            strcpy(prev_f, line);
            exit(v);
        }
    }
    fclose(fp);
    free(prev_f);
}

然而,getline()没有正确存储该行的数据,因此我无法正确运行命令.有什么方法可以克服这个问题吗?或者我需要手动将文件读取到缓冲区,然后查看缓冲区中有什么命令? 我不知道有什么简单的替代办法/解决办法

谢谢

推荐答案

基本问题是,对于getline调用,您没有使用适当的第一个参数,或者没有为第二个参数使用正确的值.正如在getline() manual page中所解释的,

如果*lineptr在调用前设置为空,则getline()将分配一个缓冲区来存储该行.即使getline()失败,该缓冲区也应该由用户程序释放.

或者,在调用getline()之前,*lineptr可以包含一个指针,指向一个大小为malloc(3) *n字节的缓冲区. 如果缓冲区不够大,无法容纳该行,getline()将其调整为realloc(3),并根据需要更新 *lineptr和 *n.

在任何一种情况下,在成功调用时,*lineptr和*n都将被更新,以分别反映缓冲区地址和分配的大小.

具体地说,该函数期望获得空指针或指向malloc分配的缓冲区的指针.但是,您向它传递了一个指向堆栈上分配的缓冲区的指针.因此,getline假定您的len值就是缓冲区的大小.由于您已将其设置为0,这意味着缓冲区不够大,因此getline将需要重新分配缓冲区,并且如上所述,它将更新值以反映缓冲区地址.但是,因为这实际上不是一个变量,所以它不会正常工作.因此,您至少需要将len初始化为MAX_CMD_BUFFER.

请注意,"C for Dummies Blog"The getline() Function页解释了使用此函数的适当方法,例如,使用malloc作为行指针.尽管如此,为了像您那样使用堆栈缓冲区,它还展示了如何在页面后面执行此操作,即使用指向缓冲区的字符指针.它的示例有这两行

   char buffer[32];
   char *b = buffer;

其中&b被传递到getline而不是&buffer.尽管如此,只有当缓冲区大小总是足够时,这才能正常工作,因此getline不需要try 进行任何重新分配.这是因为,正如realloc(3)中所解释的,

除非ptr为空,否则它一定是由先前对malloc或相关函数的调用返回的.

在您的例子中,我们得到了UB(未定义行为),其中任何内容都可能正常工作,返回错误代码,甚至导致分段错误.尽管如此,假设它工作正常,那么代码的其余部分实际上应该始终使用字符指针,例如b,而不是buffer,这与后来的"Dummies"页面示例不同,后者有printf("You typed: '%s'\n",buffer);行(另外,如果已经调用了realloc并分配了新的内存,当代码使用完该缓冲区时,它还应该从技术上判断该值是否不同,如果不同,则对其调用free).

因此,我建议您不要使用您的方法,特别是当您不能确定缓冲区大小永远不会被超过时.相反,你应该使用推荐的方法,让getline为你完成初始分配,或者你自己使用malloc.

你的代码还有其他一些问题.例如,如Some programmer dude's comment中所述,c_bang[3] = '\0';将写出边界.此外,为了更健壮,您应该在对读缓冲区执行某些操作之前,再添加一些关于读缓冲区中有多少文本的判断.

C++相关问答推荐

rSP堆栈指针在返回函数调用的值时有任何用途吗?

Zig将std.os.argv转换为C类型argv

返回一个包含数组的 struct

当多个线程在C中写入相同的文件描述符时,如何防止争用情况?

测量ARM MCU中断延迟的问题

Can函数指针指向C++中具有不同参数连续性的函数

在c++中使用堆栈的有效括号

从纯C中访问通用项对话框

可以将C变量限制为特定的读/写速度吗?

C中的指针增量和减量(*--*++p)

为什么我的Hello World EFI程序构建不正确?

强制转换变量以在 struct 中蚕食

C I/O:在Windows控制台上处理键盘输入

添加函数会 destruct 嵌入式C代码(无IDE)

如何对现有的双向循环链表进行排序?

为什么二进制文件的大小不会随着静态数据的大小而增加?

即使客户端不发送数据,也会发生UNIX套接字读取

使用 c 中的 write() 函数将非 ASCII 字符写入标准输出

C 中 struct 体自赋值是否安全?特别是如果一侧是指向 struct 的指针?

如何确保 gcc + libc 对于多字节字符串使用 UTF-8,对于 wchar_t 使用 UTF-32?