将字符串复制到malloc的字符串数组

时间:2016-12-13 11:59:06

标签: c arrays visual-studio malloc strncpy

我以为我明白了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.)

3 个答案:

答案 0 :(得分: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);  

答案 1 :(得分:1)

问题是您在决定要复制的字符数时使用sizeof。但是,您分配了sizeof运算符不知道的固定数量的字符:sizeof StrPtrArr[0]等于系统上char指针的大小(四个字节,从输出判断) ,而不是10 + 1.因此,您需要在对安全字符串副本的调用中再次指定相同的数字。

答案 2 :(得分: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");