2016-12-13 2 views
0

Je pensais avoir compris la réponse à this question mais pas moi. Je comprends le premier résultat mais je ne sais toujours pas comment faire correctement la copie. J'ai essayé le code suivant:Copier une chaîne dans un tableau malloc'd de chaînes

// 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; 
} 

Le résultat je suis arrivé était:

inpbuf=TstFld0 sizeof= 4 strptrarr=Tst 
inpbuf=TstFld1 sizeof= 1 

et l'erreur suivante:

Exception thrown: write access violation. 
destination_it was 0xFFFFFFCD. 

Le résultat que je pensais que je me faisais était l'une des suivant:

inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1 
inpbuf=TstFld1 sizeof= 1 *strptrarr=T 

Je comprends le La première copie a copié le tampon d'entrée sur le pointeur de 4 octets qui était incorrect. Je pensais que la deuxième copie copierait le tampon d'entrée à la valeur du pointeur déréférencé d'une taille de 11 mais ce n'était pas le cas. Je devine que la copie était au premier caractère de la chaîne dans le tableau. Je ne comprends pas assez la mémoire pour connaître la signification de l'adresse 0xFFFFFFCD mais je suppose que c'est en mémoire morte causant ainsi l'erreur.

Quelle est la bonne façon de faire la copie?

(je ne pense pas que cela importe, mais je suis en utilisant VS 2015 Community Edition Update 3.)

+0

sizeof ne vous donner une longueur de chaîne. – koper89

+0

Merci.C'est vrai. Je crois que la deuxième version de MS de 'strncpy' doit être la taille de la variable de récepteur. –

+0

Qu'est-ce que '_TRUNCATE'? Il ne semble pas que vous utilisiez 'strncpy_s' correctement. Voir la [spécification] (http://port70.net/~nsz/c/c11/n1570.html#K.3.7.1.4) – Olaf

Répondre

1

Pourquoi

strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); 

?

*StrPtrArr[1] devrait être StrPtrArr[1] parce StrPtrArr est de type char** et vous avez besoin char* ici.

et sizeof (* StrPtrArr [1]) - est assez étrange .... effectivement sizeof(StrPtrArr[1]) ne peut pas non plus fournir une valeur correcte.

Vous devez vous rappeler la taille de la mémoire allouée, puis l'utiliser comme:

size_t arrSize = 10 + 1; 
StrPtrArr[1] = (char *)malloc(arrSize); 
. . . 
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE); 
+0

Merci. J'ai essayé le changement, mais j'ai eu la même erreur sur la copie. J'espérais que le sizeof (* StrPtrArr) serait 11. –

+0

Essayez strlen au lieu de sizeof. – koper89

+0

@ koper89 Bonne suggestion, mais il vaut mieux utiliser 'strlen (StrPtrArr [1]) + 1' pour copier' '\ 0'' aussi – VolAnd

1

Le problème est que vous utilisez sizeof au moment de décider combien de caractères à copier. Cependant, vous avez alloué un nombre fixe de caractères qui n'est pas connu sizeof opérateur: sizeof StrPtrArr[0] est égal à la taille de char pointeur sur votre système (quatre octets, à en juger par la sortie), pas 10 + 1. Par conséquent, vous devez spécifier ce même numéro à nouveau dans l'appel pour sécuriser la copie de la chaîne.

+0

Merci. Est-ce ce que vous voulez dire: 'strncpy_s (* StrPtrArr [1], 8, InpBuf1, _TRUNCATE);'? J'ai toujours la même erreur que ci-dessus. –

+0

@ J.Toran 8 devrait être 11, et il n'y a pas d'astérisque devant StrPtrArr [1]. – dasblinkenlight

+0

Merci @dasblinkenlight. Je crois que c'est la même correction que VolAnd montré ci-dessus. Malheureusement, je ne pouvais spécifier qu'une seule réponse correcte. –

1

Ce n'est pas aussi compliqué que les gens semblent le penser.

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

J'ai utilisé intentionnellement calloc lors de l'attribution, car qui définit tous les pointeurs NULL. Cela donne l'avantage que vous pouvez appeler sans risque free() sur le pointeur, avant même qu'il soit assigné pour pointer sur une chaîne.

Cela signifie que vous pouvez facilement (re) assigner une nouvelle chaîne à un indice à tout moment, de la manière suivante:

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

Merci @Lundin. C'est aussi une bonne réponse. Je suis encore un peu débutant et je n'avais pas utilisé 'memcpy' avant, mais je vais le garder à l'esprit. –

+0

@ J.Toran 'memcpy' est une fonction de copie générale pour tout type de mémoire. Il fait la même chose que 'strcpy_s', bien que' strcpy_s' vérifie également si la chaîne source a atteint la fin. Comme ce code connaissait déjà la longueur de la chaîne source par l'appel de 'strlen', je pouvais utiliser' memcpy' au lieu de 'strcpy_s' -' memcpy' est toujours un peu plus rapide. – Lundin

+0

si 'n' est connu, disons 1024, cela serait-il équivalent à votre calloc? 'char * array [1024] = {NULL};' – nmz787