我正在寻找一种将多维char数组复制到新目的地的明智方法。我想复制char数组,因为我想编辑内容而不更改源数组。
我可以构建嵌套循环来手工复制每个字符,但我希望有更好的方法。
更新:
我没有2.水平尺寸的尺寸。仅给出长度(行)。
代码看起来像这样:
char **tmp;
char **realDest;
int length = someFunctionThatFillsTmp(&tmp);
//now I want to copy tmp to realDest
我正在寻找一种将tmp的所有内存复制到可用内存并将realDest指向它的方法。
更新2:
someFunctionThatFillsTmp()是来自Redis C lib credis.c的函数credis_lrange()。
在lib 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
但是我得到一个:程序接收到的信号:EXC_BAD_ACCESS
您可以使用memcpy
。
如果多维数组的大小是在编译时给出的,即memcpy
,则只需要一个memcpy调用
mytype myarray[1][2]
如果您像指示数组是动态分配的那样,则需要知道两个维度的大小,因为动态分配时,数组中使用的内存不会位于连续的位置,这意味着memcpy将必须多次使用。
给出一个二维数组,复制它的方法如下:
memcpy(dest, src, sizeof (mytype) * rows * columns);
鉴于您的问题似乎是您正在处理字符串数组,因此可以使用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);
}
查找字符串的长度(必须为null终止)。
在这种情况下,循环将变为
strlen
当您有一个指向C中指针的指针时,您必须知道如何使用数据并将其布置在内存中。现在,第一点很明显,并且通常对于任何变量都适用:如果您不知道某个变量在程序中将如何使用,为什么要使用它呢? :-)。第二点更有趣。
在最基本的级别上,指向类型为for ( int i = 0; i < length; ++i ){
int width = strlen(src[i]) + 1;
dest[i] = malloc(width);
memcpy(dest[i], src[i], width);
}
的指针指向类型为T
的one对象。例如:
T
现在,int i = 42;
int *pi = &i;
指向一个pi
。如果愿意,可以将指针指向许多此类对象中的第一个:
int
int arr[10];
int *pa = arr;
int *pb = malloc(10 * sizeof *pb);
现在指向10个(连续)pa
值的序列中的第一个,并且假设int
成功,malloc()
指向另一个10个(再次,连续)pb
的集合中的第一个] s。
如果有指向指针的指针,则同样适用:
int
假设int **ppa = malloc(10 * sizeof *ppa);
成功,现在malloc()
指向10个连续ppa
值序列的第一个。
所以,当您这样做:
int *
char **tmp = malloc(sizeof(char *)*CR_MULTIBULK_SIZE);
指向tmp
这样的对象序列中的第一个char *
对象。上面的每个指针均未初始化,因此CR_MULTIBULK_SIZE
至tmp[0]
都包含垃圾。初始化它们的一种方法是将它们tmp[CR_MULTIBULK_SIZE-1]
:
malloc()
上面的size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i)
tmp[i] = malloc(...);
是我们想要的第...
个数据的大小。它可以是常数,也可以是变量,取决于i
,月球的相位或随机数或其他任何东西。要注意的主要点是,您在循环中有对i
的CR_MULTIBULK_SIZE
调用,并且尽管每个malloc()
将返回给您连续的内存块,但无法保证malloc()
调用之间的连续性。换句话说,不能保证第二个malloc()
调用返回一个从上一个malloc()
的数据结束处开始的指针。
为了使事情更具体,让我们假设malloc()
为3。在图片中,您的数据可能看起来像这样:
CR_MULTIBULK_SIZE
+------+ +---+---+
tmp: | |--------+ +----->| a | 0 |
+------+ | | +---+---+
| |
| |
| +------+------+------+
+-------->| 0 | 1 | 2 |
+------+------+------+
| |
| | +---+---+---+---+---+
| +--->| t | e | s | t | 0 |
+------+ +---+---+---+---+---+
|
|
| +---+---+---+
+--->| h | i | 0 |
+---+---+---+
指向3个tmp
值的连续块。指针的第一个指针char *
指向3个tmp[0]
值的连续块。同样,char
和tmp[1]
分别指向5和2tmp[2]
s。但是char
到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);
}
,因此您的代码中不需要嵌套循环。 (memcpy()
最有可能是通过循环实现的,所以效果就好像您有嵌套循环一样。)
现在,如果您有类似的代码:
memcpy()
即,您在一个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;
调用中为所有指针分配了连续空间,然后可以在代码中无循环的情况下复制所有数据:
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;
来为malloc()
分配内存,那么您将需要一个循环来复制所有数据。
让我们探索这里发生的情况的可能性:
int cb = sizeof(char) * rows * columns;
memcpy (toArray, fromArray, cb);
故事的寓意是:您必须知道指针另一侧的内容。否则。
该故事的second的寓意是:仅因为您可以使用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;
}
表示法访问一个双指针,并不使它与二维数组相同。真的。
让我稍微澄清一下第二种道德。
一个数组(无论是一维,二维,无论是什么)都是分配的内存,编译器知道内存有多大(但不会为您进行任何范围检查),以及如何寻址开始。您可以使用
声明数组[][]
和类似的事物;
A pointer是可以保存内存地址的变量。您可以使用
声明指针char string1[32];
unsigned int histo2[10][20];
它们是两种不同的东西。
但是:
char *sting_ptr1;
double *matrix_ptr = NULL;
语法与指针一起使用,则编译器将为您执行指针算术。所以,我可以做
[]
因为规则2认为string1(数组)被视为 strcpy(string1,"dmckee");
)。同样,我可以使用:
char*
最后,
char *string_ptr2 = string1;
由于规则1,将打印“ OK”。
您为什么不使用C ++?
if (string_ptr[3] == 'k') {
prinf("OK\n");
}
或类似的东西?另外,您需要使用C字符串吗?我对此表示怀疑。
请注意以下示例:
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);
}
char **a;
是a[i]
。因此,如果您将char*
设为memcpy()
,则表示该指针的浅表副本。
我将放弃多维方面,并使用大小为a
的平面缓冲区。您可以用nn
模拟A[i][j]
。然后您可以A[i + jwidth]
。
正如其他人所建议的,看起来这是一个指针数组,而不是多义数组。
所以而不是它
char mdArray [10] [10];
它是:
char * pArray [10];
如果是这种情况,您唯一可以做的就是用您获得的一个长度值循环遍历,如果要使用字符串(看起来像这样),则在这种情况下使用strlen:] >
memcpy(newBuffer, oldBuffer, width * height * sizeof(*NewBuffer))