将字符串复制到 malloc 的字符串数组
Copy a string to a malloc'd array of strings
我以为我理解 this question 的答案,但我不理解。我了解第一个结果,但我仍然不知道如何正确复制。我尝试了以下代码:
// TstStrArr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <malloc.h>
int main()
{
char ** StrPtrArr;
char InpBuf0[] = "TstFld0";
char InpBuf1[] = "TstFld1";
StrPtrArr = (char **)malloc(2 * sizeof(char *));
StrPtrArr[0] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf0, sizeof(StrPtrArr[0]));
strncpy_s(StrPtrArr[0], sizeof(StrPtrArr[0]), InpBuf0, _TRUNCATE);
printf("strptrarr=%s\n", StrPtrArr[0]);
StrPtrArr[1] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf1, sizeof(*StrPtrArr[1]));
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); // error here
printf("*strptrarr=%s\n", StrPtrArr[1]);
free(StrPtrArr[0]);
free(StrPtrArr[1]);
free(StrPtrArr);
return 0;
}
我得到的结果是:
inpbuf=TstFld0 sizeof= 4 strptrarr=Tst
inpbuf=TstFld1 sizeof= 1
和以下错误:
Exception thrown: write access violation.
destination_it was 0xFFFFFFCD.
我认为我会得到的结果是以下之一:
inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1
inpbuf=TstFld1 sizeof= 1 *strptrarr=T
我知道第一个副本将输入缓冲区复制到不正确的 4 字节指针。我以为第二个副本会将输入缓冲区复制到大小为 11 的取消引用指针的值,但事实并非如此。我猜副本是数组中字符串的第一个字符。我对内存的了解不足以了解地址 0xFFFFFFCD 的重要性,但我猜它在只读内存中,因此导致错误。
复制的正确方法是什么?
(我认为这不重要,但我使用的是 VS 2015 Community Edition Update 3。)
为什么
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE);
?
*StrPtrArr[1]
应该是 StrPtrArr[1]
因为 StrPtrArr
是类型 char**
并且你在这里需要 char*
.
和 sizeof(*StrPtrArr[1]) - 很奇怪....
实际上sizeof(StrPtrArr[1])
也无法提供正确的值。
你应该记住分配内存的大小,然后像这样使用它:
size_t arrSize = 10 + 1;
StrPtrArr[1] = (char *)malloc(arrSize);
. . .
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);
问题是您在决定要复制多少个字符时使用了 sizeof
。但是,您分配了 sizeof
运算符不知道的固定数量的字符:sizeof StrPtrArr[0]
等于系统上 char
指针的大小(四个字节,从输出判断) ,而不是 10 + 1。因此,您需要在调用安全字符串复制时再次指定相同的数字。
它并不像人们想象的那么复杂。
char* array = calloc( n, sizeof(array[0]) ); // allocate array of pointers
// assign a dynamically allocated pointer:
size_t size = strlen(str) + 1;
array[i] = malloc(size);
memcpy(array[i], str, size);
我在分配期间故意使用 calloc
,因为这会将所有指针设置为 NULL。这样做的好处是您可以在指针上无害地调用 free()
,甚至在它被分配为指向一个字符串之前也是如此。
这反过来意味着您可以随时通过以下方式轻松地(重新)将新字符串分配给索引:
void str_assign (char** dst, const char* src)
{
size_t size = strlen(src) + 1;
free(*dst);
*dst = malloc(size);
if(*dst != NULL)
{
memcpy(*dst, src, size);
}
}
...
str_assign(&array[i], "something");
我以为我理解 this question 的答案,但我不理解。我了解第一个结果,但我仍然不知道如何正确复制。我尝试了以下代码:
// TstStrArr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <malloc.h>
int main()
{
char ** StrPtrArr;
char InpBuf0[] = "TstFld0";
char InpBuf1[] = "TstFld1";
StrPtrArr = (char **)malloc(2 * sizeof(char *));
StrPtrArr[0] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf0, sizeof(StrPtrArr[0]));
strncpy_s(StrPtrArr[0], sizeof(StrPtrArr[0]), InpBuf0, _TRUNCATE);
printf("strptrarr=%s\n", StrPtrArr[0]);
StrPtrArr[1] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf1, sizeof(*StrPtrArr[1]));
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); // error here
printf("*strptrarr=%s\n", StrPtrArr[1]);
free(StrPtrArr[0]);
free(StrPtrArr[1]);
free(StrPtrArr);
return 0;
}
我得到的结果是:
inpbuf=TstFld0 sizeof= 4 strptrarr=Tst
inpbuf=TstFld1 sizeof= 1
和以下错误:
Exception thrown: write access violation.
destination_it was 0xFFFFFFCD.
我认为我会得到的结果是以下之一:
inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1
inpbuf=TstFld1 sizeof= 1 *strptrarr=T
我知道第一个副本将输入缓冲区复制到不正确的 4 字节指针。我以为第二个副本会将输入缓冲区复制到大小为 11 的取消引用指针的值,但事实并非如此。我猜副本是数组中字符串的第一个字符。我对内存的了解不足以了解地址 0xFFFFFFCD 的重要性,但我猜它在只读内存中,因此导致错误。
复制的正确方法是什么?
(我认为这不重要,但我使用的是 VS 2015 Community Edition Update 3。)
为什么
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE);
?
*StrPtrArr[1]
应该是 StrPtrArr[1]
因为 StrPtrArr
是类型 char**
并且你在这里需要 char*
.
和 sizeof(*StrPtrArr[1]) - 很奇怪....
实际上sizeof(StrPtrArr[1])
也无法提供正确的值。
你应该记住分配内存的大小,然后像这样使用它:
size_t arrSize = 10 + 1;
StrPtrArr[1] = (char *)malloc(arrSize);
. . .
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);
问题是您在决定要复制多少个字符时使用了 sizeof
。但是,您分配了 sizeof
运算符不知道的固定数量的字符:sizeof StrPtrArr[0]
等于系统上 char
指针的大小(四个字节,从输出判断) ,而不是 10 + 1。因此,您需要在调用安全字符串复制时再次指定相同的数字。
它并不像人们想象的那么复杂。
char* array = calloc( n, sizeof(array[0]) ); // allocate array of pointers
// assign a dynamically allocated pointer:
size_t size = strlen(str) + 1;
array[i] = malloc(size);
memcpy(array[i], str, size);
我在分配期间故意使用 calloc
,因为这会将所有指针设置为 NULL。这样做的好处是您可以在指针上无害地调用 free()
,甚至在它被分配为指向一个字符串之前也是如此。
这反过来意味着您可以随时通过以下方式轻松地(重新)将新字符串分配给索引:
void str_assign (char** dst, const char* src)
{
size_t size = strlen(src) + 1;
free(*dst);
*dst = malloc(size);
if(*dst != NULL)
{
memcpy(*dst, src, size);
}
}
...
str_assign(&array[i], "something");