2016-12-13 51 views
0

我想我理解了this question的答案,但我不知道。我理解第一个结果,但我仍然不知道如何正确地复制副本。我尝试下面的代码:将一个字符串复制到一个malloc'd数组字符串

// 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年社区版更新3)

+0

的sizeof不会给你字符串的长度。 – koper89

+0

谢谢。确实如此。我相信'strncpy'的MS版本的第二个参数需要是接收器变量的sizeof。 –

+0

什么是_TRUNCATE?它看起来不像正确使用'strncpy_s'。请参阅[规范](http://port70.net/~nsz/c/c11/n1570.html#K.3.7.1.4) – Olaf

回答

1

为什么

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); 
+0

谢谢。我尝试了更改,但在副本上出现了相同的错误。我希望sizeof(* StrPtrArr)将是11. –

+0

尝试strlen而不是sizeof。 – koper89

+0

@ koper89好的建议,但最好使用'strlen(StrPtrArr [1])+ 1'复制''\ 0''也 – VolAnd

1

的问题是,你是在决定多少个字符复制时使用sizeof。但是,您为sizeof运算符分配了固定数量的字符,而运算符:sizeof StrPtrArr[0]等于您的系统上指针的大小(4个字节,从输出判断),而不是10 + 1。因此,您需要指定在保证字符串复制的调用中再次使用相同的数字。

+0

谢谢。这是你的意思:'strncpy_s(* StrPtrArr [1],8,InpBuf1,_TRUNCATE);'?我仍然得到了与上面相同的错误。 –

+0

@ J.Toran 8应该是11,并且StrPtrArr [1]前面没有星号。 – dasblinkenlight

+0

谢谢@dasblinkenlight。我相信这是VolAnd在上面显示的同样的修正。不幸的是,我只能指定一个正确的答案。 –

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"); 
+0

谢谢@Lundin。这也是一个正确的答案。我还是一个初学者,之前没有使用过'memcpy',但我会牢记它。 –

+0

@ J.Toran'memcpy'是任何一种内存的通用复制函数。它和'strcpy_s'完全相同,尽管'strcpy_s'也检查源字符串是否到达末尾。由于这段代码已经知道源字符串通过调用'strlen'有多长时间了,我可以使用'memcpy'而不是'strcpy_s' - 'memcpy'的速度稍快一些。 – Lundin

+0

如果已知'n',例如1024,这是否等同于您的calloc? 'char * array [1024] = {NULL};' – nmz787

相关问题