C++ C/C++;如何在没有嵌套循环的情况下复制多维字符数组?

C++ C/C++;如何在没有嵌套循环的情况下复制多维字符数组?,c++,c,arrays,multidimensional-array,char,C++,C,Arrays,Multidimensional Array,Char,我正在寻找一种将多维字符数组复制到新目标的智能方法。我想复制char数组,因为我想编辑内容而不更改源数组 我可以构建嵌套循环来手动复制每个字符,但我希望有更好的方法 更新: 我没有2号的尺寸。水平维度。给定的只是长度(行) 代码如下所示: char **tmp; char **realDest; int length = someFunctionThatFillsTmp(&tmp); //now I want to copy tmp to realDest +------

我正在寻找一种将多维字符数组复制到新目标的智能方法。我想复制char数组,因为我想编辑内容而不更改源数组

我可以构建嵌套循环来手动复制每个字符,但我希望有更好的方法

更新:

我没有2号的尺寸。水平维度。给定的只是长度(行)

代码如下所示:

char **tmp;
char **realDest;

int length = someFunctionThatFillsTmp(&tmp);

//now I want to copy tmp to realDest
     +------+                                          +---+---+
tmp: |      |--------+                          +----->| a | 0 |
     +------+        |                          |      +---+---+
                     |                          |
                     |                          |
                     |         +------+------+------+
                     +-------->|  0   |  1   |  2   |
                               +------+------+------+
                                   |      |
                                   |      |    +---+---+---+---+---+
                                   |      +--->| t | e | s | t | 0 |
                            +------+           +---+---+---+---+---+
                            |
                            |
                            |    +---+---+---+
                            +--->| h | i | 0 |
                                 +---+---+---+
我正在寻找一种方法,将tmp的所有内存复制到空闲内存中,并指向realDest

更新2:

someFunctionThatFillsTmp()是Redis C库中的函数credis_lrange()

在库内部,tmp是通过以下方式创建的:

rhnd->reply.multibulk.bulks = malloc(sizeof(char *)*CR_MULTIBULK_SIZE)
更新3:

我尝试将memcpy用于以下几行:

int cb = sizeof(char) * size * 8; //string inside 2. level has 8 chars
memcpy(realDest,tmp,cb);
cout << realDest[0] << endl;

prints: mystring
int cb=sizeof(char)*大小*8//字符串在2内。等级有8个字符
memcpy(realDest、tmp、cb);
你可以用

如果多维数组大小在编译时给定,即
mytype myarray[1][2]
,则只需要一个memcpy调用

memcpy(dest, src, sizeof (mytype) * rows * columns);
如果像您指出的那样,数组是动态分配的,那么您需要知道这两个维度的大小,因为动态分配时,数组中使用的内存将不在连续位置,这意味着memcpy必须多次使用

给定二维数组,复制该数组的方法如下:

char** src;
char** dest;

int length = someFunctionThatFillsTmp(src);
dest = malloc(length*sizeof(char*));

for ( int i = 0; i < length; ++i ){
    //width must be known (see below)
    dest[i] = malloc(width);

    memcpy(dest[i], src[i], width);
}
char**src;
字符**dest;
int length=someFunctionThatFillsTmp(src);
dest=malloc(长度*sizeof(字符*);
对于(int i=0;i
鉴于您的问题看起来像是在处理字符串数组,您可以使用查找字符串的长度(它必须以null结尾)

在这种情况下,循环将变为

for ( int i = 0; i < length; ++i ){
    int width = strlen(src[i]) + 1;
    dest[i] = malloc(width);    
    memcpy(dest[i], src[i], width);
}
for(int i=0;i
您只需计算阵列的总体大小,然后使用复制即可

int cb = sizeof(char) * rows * columns;
memcpy (toArray, fromArray, cb);

编辑:问题中的新信息表明数组的行数和列数未知,并且数组可能不规则,因此memcpy可能不是解决方案

让我们探讨一下这里发生的事情的一些可能性:

int main(int argc; char **argv){
  char **tmp1;         // Could point any where
  char **tmp2 = NULL;
  char **tmp3 = NULL;
  char **tmp4 = NULL;
  char **tmp5 = NULL;
  char **realDest;

  int size = SIZE_MACRO; // Well, you never said
  int cb = sizeof(char) * size * 8; //string inside 2. level has 8 chars

  /* Case 1: did nothing with tmp */
  memcpy(realDest,tmp,cb);  // copies 8*size bytes from WHEREEVER tmp happens to be
                          // pointing. This is undefined behavior and might crash.
  printf("%p\n",tmp[0]);    // Accesses WHEREEVER tmp points+1, undefined behavior, 
                            // might crash.
  printf("%c\n",tmp[0][0]); // Accesses WHEREEVER tmp points, undefined behavior, 
                            // might crash. IF it hasn't crashed yet, derefernces THAT
                            // memory location, ALSO undefined behavior and 
                            // might crash


  /* Case 2: NULL pointer */
  memcpy(realDest,tmp2,cb);  // Dereferences a NULL pointer. Crashes with SIGSEGV
  printf("%p\n",tmp2[0]);    // Dereferences a NULL pointer. Crashes with SIGSEGV
  printf("%c\n",tmp2[0][0]); // Dereferences a NULL pointer. Crashes with SIGSEGV


  /* Case 3: Small allocation at the other end */
  tmp3 = calloc(sizeof(char*),1); // Allocates space for ONE char*'s 
                                  // (4 bytes on most 32 bit machines), and 
                                  // initializes it to 0 (NULL on most machines)
  memcpy(realDest,tmp3,cb);  // Accesses at least 8 bytes of the 4 byte block: 
                             // undefined behavior, might crash
  printf("%p\n",tmp3[0]);    // FINALLY one that works. 
                             // Prints a representation of a 0 pointer   
  printf("%c\n",tmp3[0][0]); // Derefereces a 0 (i.e. NULL) pointer. 
                             // Crashed with SIGSEGV


  /* Case 4: Adequate allocation at the other end */
  tmp4 = calloc(sizeof(char*),32); // Allocates space for 32 char*'s 
                                  // (4*32 bytes on most 32 bit machines), and 
                                  // initializes it to 0 (NULL on most machines)
  memcpy(realDest,tmp4,cb);  // Accesses at least 8 bytes of large block. Works.
  printf("%p\n",tmp3[0]);    // Works again. 
                             // Prints a representation of a 0 pointer   
  printf("%c\n",tmp3[0][0]); // Derefereces a 0 (i.e. NULL) pointer. 
                             // Crashed with SIGSEGV


  /* Case 5: Full ragged array */
  tmp5 = calloc(sizeof(char*),8); // Allocates space for 8 char*'s
  for (int i=0; i<8; ++i){
    tmp5[i] = calloc(sizeof(char),2*i); // Allocates space for 2i characters
    tmp5[i][0] = '0' + i;               // Assigns the first character a digit for ID
  }
  // At this point we have finally allocated 8 strings of sizes ranging 
  // from 2 to 16 characters.
  memcpy(realDest,tmp5,cb);  // Accesses at least 8 bytes of large block. Works.
                             // BUT what works means is that 2*size elements of 
                             // realDist now contain pointer to the character 
                             // arrays allocated in the for block above/
                             //
                             // There are still only 8 strings allocated
  printf("%p\n",tmp5[0]);    // Works again. 
                             // Prints a representation of a non-zero pointer   
  printf("%c\n",tmp5[0][0]); // This is the first time this has worked. Prints "0\n"
  tmp5[0][0] = '*';
  printf("%c\n",realDest[0][0]); // Prints "*\n", because realDest[0] == tmp5[0],
                                 // So the change to tmp5[0][0] affects realDest[0][0]

  return 0;
}
和类似的事情,

指针是一个可以保存内存地址的变量。您可以使用

char *sting_ptr1;
double *matrix_ptr = NULL;
它们是两种不同的东西

但是:

  • 如果将
    []
    语法与指针一起使用,编译器将为您执行指针算术
  • 在几乎任何没有取消引用的情况下使用数组的地方,编译器都会将其视为指向数组起始位置的指针
  • 所以,我能做到

        strcpy(string1,"dmckee");
    
    因为规则2说string1(数组)被视为
    char*
    )。同样,我可以用以下方法来表达:

        char *string_ptr2 = string1;
    
    最后,

        if (string_ptr[3] == 'k') {
          prinf("OK\n");
        }
    

    由于规则1,将打印“确定”。

    请注意,在以下示例中:

    char **a;
    
    a[i]
    char*
    。因此,如果您对
    a
    执行
    memcpy()
    ,您就是在执行该指针的浅拷贝


    我会抛弃多维方面,使用大小为
    nn
    的扁平缓冲区。您可以使用
    A[i+jwidth]
    模拟
    A[i][j]
    。然后你可以
    memcpy(newBuffer,oldBuffer,width*height*sizeof(*newBuffer))

    当你有一个指向C中指针的指针时,你必须知道数据将如何在内存中使用和布局。现在,第一点是显而易见的,对任何变量来说都是如此:如果你不知道某个变量将如何在程序中使用,为什么要使用它?:-)。第二点更有趣

    在最基本的级别上,指向类型
    T
    的指针指向类型
    T
    的一个对象。例如:

    int i = 42;
    int *pi = &i;
    
    现在,
    pi
    指向一个
    int
    。如果愿意,可以将指针指向许多此类对象中的第一个:

    int arr[10];
    int *pa = arr;
    int *pb = malloc(10 * sizeof *pb);
    
    pa
    现在指向10个(连续的)
    int
    值序列的第一个,假设
    malloc()
    成功,
    pb
    指向另一组10个(连续的)
    int
    值序列的第一个

    如果您有指向指针的指针,则同样适用:

    int **ppa = malloc(10 * sizeof *ppa);
    
    假设
    malloc()
    成功,现在您有
    ppa
    指向10个连续
    int*
    值序列的第一个

    因此,当您这样做时:

    char **tmp = malloc(sizeof(char *)*CR_MULTIBULK_SIZE);
    
    tmp
    指向
    CR\u MULTIBULK\u SIZE
    这类对象序列中的第一个
    char*
    对象。上面的每个指针都没有初始化,因此
    tmp[0]
    tmp[CR\u MULTIBULK\u SIZE-1]
    都包含垃圾。初始化它们的一种方法是
    malloc()

    size_t i;
    for (i=0; i < CR_MULTIBULK_SIZE; ++i)
        tmp[i] = malloc(...);
    
    tmp
    指向由3个
    char*
    值组成的连续块。第一个指针,
    tmp[0]
    ,指向一个由3个
    char
    值组成的连续块。类似地,
    tmp[1]
    tmp[2]
    分别指向5和2
    char
    s。但是
    tmp[0]
    指向
    tmp[2]
    的内存作为一个整体是不连续的

    由于
    memcpy()
    复制连续内存,因此您想做的事情不能由一个
    memcpy()
    完成。此外,您需要知道每个
    tmp[i]
    是如何分配的。因此,一般来说,您想要做的事情需要一个循环:

    char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
    /* assume malloc succeeded */
    size_t i;
    for (i=0; i < CR_MULTIBULK_SIZE; ++i) {
        realDest[i] = malloc(size * sizeof *realDest[i]);
        /* again, no error checking */
        memcpy(realDest[i], tmp[i], size);
    }
    
    也就是说,您为一个
    malloc()
    调用中的所有指针分配了连续空间,然后您可以复制所有数据,而不在代码中创建循环:

    size_t i;
    char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
    *realDest = malloc(size * CR_MULTIBULK_SIZE * sizeof **realDest);
    memcpy(*realDest, tmp[0], size*CR_MULTIBULK_SIZE);
    
    /* Now set realDest[1]...realDest[CR_MULTIBULK_SIZE-1] to "proper" values */
    for (i=1; i < CR_MULTIBULK_SIZE; ++i)
        realDest[i] = realDest[0] + i * CR_MULTIBULK_SIZE;
    
    size\u ti;
    char**realDest=malloc(CR\u多块体大小*大小*realDest);
    *realDest=malloc(大小*CR\u多块大小*sizeof**realDest);
    memcpy(*realDest,tmp[0],size*CR\u MULTIBULK\u size);
    /
    
    char *s = malloc(size * CR_MULTIBULK_SIZE * sizeof *s);
    size_t i;
    for (i=0; i < CR_MULTIBULK_SIZE; ++i)
        tmp[i] = s + i*CR_MULTIBULK_SIZE;
    
    size_t i;
    char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
    *realDest = malloc(size * CR_MULTIBULK_SIZE * sizeof **realDest);
    memcpy(*realDest, tmp[0], size*CR_MULTIBULK_SIZE);
    
    /* Now set realDest[1]...realDest[CR_MULTIBULK_SIZE-1] to "proper" values */
    for (i=1; i < CR_MULTIBULK_SIZE; ++i)
        realDest[i] = realDest[0] + i * CR_MULTIBULK_SIZE;
    
    char **tmp;
    
    int length = getlengthfromwhereever;
    
    char** copy = new char*[length];
    
    for(int i=0; i<length; i++)
    {
        int slen = strlen(tmp[i]);
        copy[i] = new char[slen+1]; //+1 for null terminator
        memcpy(copy[i],tmp[i],slen);
        copy[i][slen] = 0; // you could just copy slen+1 to copy the null terminator, but there might not be one...
    }
    
    class C
    {
        std::vector<std::string> data;
    public:
        char** cpy();
    };
    
    char** C::cpy()
    {
        std::string *psz = new std::string [data.size()];
        copy(data.begin(), data.end(), psz);
        char **ppsz = new char* [data.size()];
        for(size_t i = 0; i < data.size(); ++i)
        {
            ppsz[i] = new char [psz[i].length() + 1];
            ppsz[i] = psz[i].c_str();
        }
        delete [] psz;
        return(ppsz);
    }