C 使用fgets()从文件中读取多行并存储到指针数组

C 使用fgets()从文件中读取多行并存储到指针数组,c,bash,shell,pointers,fgets,C,Bash,Shell,Pointers,Fgets,我正在尝试在“批处理文件模式”上实现一个自定义shell。假设我有一个名为“batchfile”的文件,其中包含: ls –l pwd ps touch hello ls -l ; cat file ; grep foo file2 ls -l && cat file quit 调用/myShell batchfile,我想分别执行这些命令。但是,当我尝试使用fgets()读取文件中的行,然后将它们存储到数组(char*batch\u cmds[512])时,我得到: 分段故障

我正在尝试在“批处理文件模式”上实现一个自定义shell。假设我有一个名为“batchfile”的文件,其中包含:

ls –l
pwd
ps
touch hello
ls -l ; cat file ; grep foo file2
ls -l && cat file
quit
调用
/myShell batchfile
,我想分别执行这些命令。但是,当我尝试使用
fgets()
读取文件中的行,然后将它们存储到数组(
char*batch\u cmds[512]
)时,我得到:

分段故障(堆芯转储)

这是我目前的代码:

int main(int argc, char *argv[]){
    if (argc >=2){
        char str[512];
        char *batch_cmds[512];
        int i=0; 
        FILE *fp;

        fp = fopen(argv[1], "r");

        while(fgets(str,512, fp)!=NULL){
            strcpy(batch_cmds[i], str);
            i++;
        }
    fclose(fp);

我无法理解为什么会弹出此错误。

您为指针本身保留了空间,但不是为每个指针指向的每个字符串保留空间。每个
batch\u cmds[i]
都指向“某处”,至少不指向您分配的对象;然后调用
strcpy(批处理cmds[i],str)
,您将
str
的内容写入“某处”,并产生未定义的行为(例如,崩溃;实际上语句
batch\u cmds[i]
访问未初始化的数组,并且本身已经是未定义的行为;但仅此一项就很少导致崩溃)

而不是

strcpy(batch_cmds[i], str);

命令
strdup
执行两项操作:(1)保留足够大的内存以容纳
str
的内容;(2)然后复制
str
的内容。这相当于
batch_cmds[i]=malloc(strlen(str)+1);strcpy(批处理cmds[i],str))

此外,检查
i
是否为
行:

char *batch_cmds[512];
声明一个包含512个指向
char
的指针的数组,但这些指针未初始化(野生、悬空、随意选择)

您的选择:

  • 在堆栈上声明二维数组:

    char batch_cmds[512][512];
    
  • 使用动态内存管理在堆上分配字符串:

    char *batch_cmds[512];
    int i;
    for(i = 0; i < 512; i++)
    {
        batch_cmds[i] = malloc(string_length);
        if(batch_cmds[i] == NULL)
        {
             // handle alloc error
        }
    }
    
    // Code that uses batch_cmds...
    
    for(i = 0; i < 512; i++)
    {
        free(batch_cmds[i]);
        batch_cmds[i] = NULL;
    }
    
    char*batch_cmds[512];
    int i;
    对于(i=0;i<512;i++)
    {
    批处理cmds[i]=malloc(字符串长度);
    if(批处理cmds[i]==NULL)
    {
    //句柄分配错误
    }
    }
    //使用batch_cmds的代码。。。
    对于(i=0;i<512;i++)
    {
    免费(批处理单元cmds[i]);
    batch_cmds[i]=NULL;
    }
    
  • 使用
    strdup
    batch_cmds
    中的
    char
    指针赋值(如Stephan Lechner的回答所示)。请注意,
    strdup
    也在后台使用堆内存,因此在使用完返回的指针后,还必须将其传递给
    free
    ,以避免内存泄漏


  • 您没有为
    batch\u cmds
    分配任何内存,因此(例如)
    batch\u cmds[0]
    没有指向内存中存储字符串的有效位置。C使用旧式堆栈/堆内存管理,因此您需要了解指针和malloc的工作方式。@ChrisTurner是正确的,batch\u cmds是一个不指向任何内容的指针,您需要管理内存或静态分配内存,我建议您在成功读取一行时使用链表并分配每个节点。非常感谢。无法更好地解释它。它工作得很好。
    char *batch_cmds[512];
    int i;
    for(i = 0; i < 512; i++)
    {
        batch_cmds[i] = malloc(string_length);
        if(batch_cmds[i] == NULL)
        {
             // handle alloc error
        }
    }
    
    // Code that uses batch_cmds...
    
    for(i = 0; i < 512; i++)
    {
        free(batch_cmds[i]);
        batch_cmds[i] = NULL;
    }