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

时间:2019-01-24 14:33:48

标签: c bash shell pointers fgets

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

ls –l
pwd
ps
touch hello
ls -l ; cat file ; grep foo file2
ls -l && cat file
quit

调用./myShell batchfile,我想分别执行命令。但是,当我尝试使用fgets()从文件中读取行,然后将它们存储到数组(char * batch_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);

我不明白为什么会弹出此错误。

2 个答案:

答案 0 :(得分:4)

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

代替

strcpy(batch_cmds[i], str);

batch_cmds[i] = strdup(str);

命令strdup既执行以下操作-(1)保留足够大的内存以容纳str的内容,以及(2)然后复制str的内容。这等效于batch_cmds[i] = malloc(strlen(str)+1); strcpy(batch_cmds[i], str));

另外,检查i是否为<512,以使batch_cmds[i]不会超出数组范围。

答案 1 :(得分:1)

该行:

char *batch_cmds[512];

声明一个指向char的512个指针的数组,但是这些指针尚未初始化(野生,晃晃,任您选择)。

您的选择:

  1. 在堆栈上声明2D数组:

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

    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;
    }
    
  3. 使用strdup分配给charbatch_cmds的指针(在斯蒂芬·莱希纳的答案中演示)。请注意,strdup还在后台使用堆内存,因此在完成处理操作后,还必须将返回的指针传递给free,以避免内存泄漏。