Char **数组第一个元素被神奇地修改

时间:2018-02-01 19:22:23

标签: c arrays

我很抱歉这个模糊的标题,但我很难弄清楚如何描述这个问题。我正在尝试将数据添加到数组中,不管怎么说,尽管我明确指出,但它都会被写入索引0。我创建了一个最小的样本。

预期行为

命令行参数为-u rwx -g rw -o r

  • bins [0] ==“111”
  • bins [1] ==“110”
  • bins [2] ==“100”

实际行为

指数0,1和2都以"100"结尾。如果您使用printf()检查各种case语句中的值,您会发现,例如,当case 'g':运行时,bins[1] == "110"bins[0] == "110" 。当case 'o':运行时,所有三个索引都将保留值"100"

最小功能样本

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void processPerms(char *targets, char **perms, char **bins, const size_t arrSize) {
    for(int i = 0; i < arrSize; i++) {
    //This string will be modified
    //so that the right bits will
    //be set.
        char binDig[] = "000";

    //We decide which, if any, bit
    //to set based upon the current
    //letter being considered.
        for(int k = 0; k < strlen(perms[i]); k++) {
            switch(perms[i][k]) {
                case 'r':
                    binDig[0] = '1';
                    break;
                case 'w':
                    binDig[1] = '1';
                    break;
                case 'x':
                    binDig[2] = '1';
                    break;
            }
        }
    //Here, we check the target
    //whose index corresponds to
    //the index of the permissions
    //string we just accessed.
    //They will always be in
    //an order where the related
    //target and perm str are in
    //the same array position.
        switch(targets[i]) {
            case 'u':
                bins[0] = binDig;
                //bins[0] == "111"
                break;
            case 'g':
                bins[1] = binDig;
                //bins[0] == "110"
                break;
            case 'o':
                bins[2] = binDig;
                //bins[0] == "100" && bins[1] == "100"
                break;
        }
    }
}

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

  const size_t arrSize = (argc-1)/2;

    char *targets = (char*)calloc(arrSize, sizeof(char));
    char **perms = (char**)calloc(arrSize, sizeof(char*));

  //Copying just the letters
  //of the args into these
  //arrays.

  for(int i = 0; i < arrSize; i++) {
        targets[i] = argv[i+(i+1)][1];
    }

  for(int i = 0; i < arrSize; i++) {
        perms[i] = argv[i*2+2];
    }

  //This array should hold three
  //strings which shall be binary
  //representations of the
  //permissions
    char **bins = (char**)calloc(3, sizeof(char*));

    processPerms(targets, perms, bins, arrSize);


  return 0;
}

2 个答案:

答案 0 :(得分:1)

 bins[2] = binDig;

这将使您指向具有自动存储持续时间的变量。当您从函数返回时,这是一个未定义行为的网关。变量的生命周期结束,就像在这种情况下一样,访问它是UB。(取消引用变量超出其生命周期的指针是Undefine d行为)。

一个简单的解决方案是使用(这是POSIX标准的一部分,但它很常见)(如果你没有这个,你可以分配内存并将数据的内容复制到它{{1} })。

binDig

(对bins[2] = strdup(binDig); bins[0]进行相同的更改。

如上所述进行此更改会使bins[1]的预期行为等于“111”,依此类推。唯一的一点是,你需要释放动态分配的内存(包括bins[0]返回的内存 当你完成它的时候)。同样,不要强制转换strdupmalloc等的返回值(因为callocvoid*是隐式转换)。并检查char*的返回值。

答案 1 :(得分:1)

binDig数组的生命周期受外部for周期的一次迭代的限制。这个binDig数组在每次迭代结束时被销毁,并在下一次迭代开始时重新创建。

这意味着当迭代结束时,在外循环的每次迭代期间执行的所有操作都将丢失。您在该迭代期间分配的bins[]的值开始指向内存中不再存在的某个不确定位置。任何通过相应bins[]条目访问数据的尝试都会导致未定义的行为。

在现实生活中,循环的每次迭代通常会在内存中完全相同的位置重新创建binDig,这会产生所有bins[]指针保持有效但指向相同值的错觉。但这只是一种幻觉。此时行为已经未定义。

当外部循环结束时,binDig数组将永远消失,并且所有bins[]指针都变得无可救药地无效。但那只是最后一根稻草。你的节目在那之前就已经很好了。