尝试在C中释放3D数组时崩溃

时间:2018-02-05 15:49:00

标签: c arrays malloc free dynamic-memory-allocation

背景

我为char ***数组分配空间,该数组存储输入到我的shell程序中的已解析命令和参数。

以下是一些示例命令行输入:

ls -la
cd ..
/usr/bin/wc -l inputs/data/long

这里是char ***数组如何存储命令 - 它用空格分析:

{{"ls", "-la"}, {"cd", ".."}, {"/usr/bin/wc", "-l", "inputs/data/long"}}

这是我如何生成char ***数组:

/*
 * initializes history
 * returns array of pointers to arrays of pointers to char arrays
 */
char*** inithistory(){
    char*** history;
    history = (char***) calloc(HIST_SIZE, sizeof(char**));
    return history;
}

/*
 * adds a tokenized command and arguments to the history
 */
int addToHistory(char*** history, char** tokenized, int* argcnts, int argcnt, int cmdcnt) {
    if (cmdcnt >= HIST_SIZE) {
        cmdcnt = HIST_SIZE-1;

        // remove oldest element and shift others up
        for (int i = 0; i < HIST_SIZE-1; i++) {
            history[i] = history[i+1];
            argcnts[i] = argcnts[i+1];
        }
    }

    // add latest element
    history[cmdcnt] = tokenized;
    argcnts[cmdcnt] = argcnt;
    return 1;
}

/*
 * returns the length of a char array
 */
int lengthof(char* string) {
  int count = 0;
  char temp = string[0];
  while (temp) {
    temp = string[count];
    count++;
  }
  if (count==0) {
      return 0;
  }
  return count-1;
}

/*
 * returns array of pointers to char arrays containing parsed command and arguments e.g. {"ls", "-la"},
 * char* input is the command line input
 */
char** tokenize(char* input, int argc) {
  char* token;
  char** tokenized;
  tokenized = (char**) calloc(argc+1, sizeof(char*));
  token = strtok(input, " "); // tokenize user input
  int i = 0;
  while (token != NULL) {
    int length = lengthof(token);
    if (i == argc-1) {
      token[length-1] = '\0';
    }
    tokenized[i] = (char*) calloc(length, sizeof(char));
    tokenized[i] = token;
    token = strtok(NULL, " ");
    i++;
  }
  tokenized[argc] = NULL;
  return tokenized;
}

问题

当我尝试释放上面的char ***数组时,我收到以下错误:

*** glibc detected *** cs475sh: free(): invalid pointer: 0x000000000150f9b3 ***
======= Backtrace: =========
/lib64/libc.so.6[0x36bb075dee]
/lib64/libc.so.6[0x36bb078c3d]
cs475sh[0x4015e9]
cs475sh[0x400d37]
cs475sh[0x400bf0]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x36bb01ed1d]
cs475sh[0x400a59]
======= Memory map: ========
00400000-00402000 r-xp 00000000 00:14 12006791923606037921               /home/Documents/HW1/shell-handout/cs475sh
00601000-00602000 r--p 00001000 00:14 12006791923606037921               /home/Documents/HW1/shell-handout/cs475sh
00602000-00603000 rw-p 00002000 00:14 12006791923606037921               /home/Documents/HW1/shell-handout/cs475sh
0150f000-01530000 rw-p 00000000 00:00 0                                  [heap]
36bac00000-36bac20000 r-xp 00000000 fd:00 918063                         /lib64/ld-2.12.so
36bae20000-36bae21000 r--p 00020000 fd:00 918063                         /lib64/ld-2.12.so
36bae21000-36bae22000 rw-p 00021000 fd:00 918063                         /lib64/ld-2.12.so
36bae22000-36bae23000 rw-p 00000000 00:00 0
36bb000000-36bb18a000 r-xp 00000000 fd:00 918804                         /lib64/libc-2.12.so
36bb18a000-36bb38a000 ---p 0018a000 fd:00 918804                         /lib64/libc-2.12.so
36bb38a000-36bb38e000 r--p 0018a000 fd:00 918804                         /lib64/libc-2.12.so
36bb38e000-36bb390000 rw-p 0018e000 fd:00 918804                         /lib64/libc-2.12.so
36bb390000-36bb394000 rw-p 00000000 00:00 0
36bd800000-36bd816000 r-xp 00000000 fd:00 918982                         /lib64/libgcc_s-4.4.7-20120601.so.1
36bd816000-36bda15000 ---p 00016000 fd:00 918982                         /lib64/libgcc_s-4.4.7-20120601.so.1
36bda15000-36bda16000 rw-p 00015000 fd:00 918982                         /lib64/libgcc_s-4.4.7-20120601.so.1
7f1088000000-7f1088021000 rw-p 00000000 00:00 0
7f1088021000-7f108c000000 ---p 00000000 00:00 0
7f108c410000-7f108c413000 rw-p 00000000 00:00 0
7f108c42f000-7f108c433000 rw-p 00000000 00:00 0
7ffc6e541000-7ffc6e557000 rw-p 00000000 00:00 0                          [stack]
7ffc6e55b000-7ffc6e55c000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

这是我如何释放阵列:

/*
 * char*** history is the array that needs to be freed,
 * int cmd is the number of parsed commands in history (char** pointers),
 * int* argcnts holds the number of arguments per command (each argument is 
 * char* - count includes the command itself) 
 */
void exitProg(int code, char*** history, int* argcnts, int cmdcnt) {
    if (!code) {
        exit(code);
    }
    if (!cmdcnt) {
        exit(code);
    }
    for (int i = 0; i < cmdcnt; i++) {
        for (int j = 0; j < argcnts[i]; j++) {
            free(history[i][j]);
        }
        free(history[i]);
    }
    free(history);
    exit(code);
}

我知道在退出程序之前释放内存是多余的,但这是分配所必需的。

我注意到只有在尝试执行free(history[i][j]);后才会出现错误。

1 个答案:

答案 0 :(得分:0)

MikeCAT指出存在内存泄漏:

  

tokenized [i] =(char *)calloc(length,sizeof(char)); tokenized [i] =   令牌;哦,内存泄漏。

这个问题通过简单的strcpy解决,正如John Bollinger所说:

  

不仅是内存泄漏,它还可能导致段错误。   你可能想要第二个这样的陈述   strcpy(tokenized [i],token);

释放内存现在可以正常运行。