2016-12-13 90 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

相關問題