C++ C/C++;如何在没有嵌套循环的情况下复制多维字符数组?
我正在寻找一种将多维字符数组复制到新目标的智能方法。我想复制char数组,因为我想编辑内容而不更改源数组 我可以构建嵌套循环来手动复制每个字符,但我希望有更好的方法 更新: 我没有2号的尺寸。水平维度。给定的只是长度(行) 代码如下所示: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 **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和2char
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);
}