0

I thought I understood the answer to this question but I don't. I understand the first result but I still don't know how to do the copy correctly. I tried the following code:

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

The result I got was:

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

and the following error:

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

The result I thought I'd get was either of the following:

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

I understand the first copy copied the input buffer to the 4 byte pointer which was incorrect. I thought the second copy would copy the input buffer to the value of the dereferenced pointer of a size of 11 but it didn't. I'm guessing the copy was to the first character of the string in the array. I don't understand memory enough to know the significance of the address 0xFFFFFFCD but I guess it's in read-only memory thus causing the error.

What is the correct way to do the copy?

(I don't think it matters, but I'm using VS 2015 Community Edition Update 3.)

4
  • sizeof will not give you string length. Commented Dec 13, 2016 at 12:02
  • Thank you. That's true. I believe the second parm of MS version of strncpy needs to be the sizeof the receiver variable. Commented Dec 13, 2016 at 12:06
  • What is _TRUNCATE? It does not look like you use strncpy_s correctly. See the specification Commented Dec 13, 2016 at 12:24
  • Thank you, Olaf. I checked the specification and _truncate is used when the number of characters to copy is greater than the sizeof the receiver variable. When I specified the strlen(of the input buffer) I got a "buffer too small" error. Commented Dec 13, 2016 at 12:29

3 Answers 3

1

Why

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

?

*StrPtrArr[1] should be StrPtrArr[1] because StrPtrArr is of type char** and you need char* here.

and sizeof(*StrPtrArr[1]) - is quite strange.... actually sizeof(StrPtrArr[1]) also cannot provide correct value.

You should remember size of allocated memory and then use it like:

 size_t arrSize = 10 + 1;
 StrPtrArr[1] = (char *)malloc(arrSize);
 . . .
 strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);  
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you. I tried the change, but got the same error on the copy. I was hoping the sizeof(*StrPtrArr) would be 11.
Try strlen instead of sizeof.
@koper89 Good suggestion, but it is better to use strlen(StrPtrArr[1]) + 1 to copy '\0' also
I tried the following code with the hard-coded length of 11: strncpy_s(*StrPtrArr[1], 11, InpBuf1, _TRUNCATE);. I hate to say but I still get the error on that line, too.
Command should be strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE); : *StrPtrArr[1] -> StrPtrArr[1] (no * needed)
|
1

The problem is that you are using sizeof when deciding how many characters to copy. However, you allocated a fixed number of characters which is not known to sizeof operator: sizeof StrPtrArr[0] is equal to the size of char pointer on your system (four bytes, judging from the output), not 10 + 1. Hence, you need to specify that same number again in the call to secure string copy.

3 Comments

Thank you. Is this what you mean: strncpy_s(*StrPtrArr[1], 8, InpBuf1, _TRUNCATE);? I still got the same error as above.
@J.Toran 8 should be 11, and there is no asterisk in front of StrPtrArr[1].
Thank you @dasblinkenlight. I believe this is the same correction that VolAnd showed above. Unfortunately I could only specifiy one correct answer.
1

It isn't as complicated as people seem to think.

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

I intentionally used calloc during allocation, since that sets all pointers to NULL. This gives the advantage that you can harmlessly call free() on the pointer, even before it is assigned to point at a string.

This in turn means that you can easily (re)assign a new string to an index at any time, in the following way:

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

3 Comments

Thank you @Lundin. This is also a correct answer. I'm still somewhat of a beginner and hadn't used memcpy before, but I will keep it in mind.
@J.Toran memcpy is a general copy function for any kind of memory. It does the same thing as strcpy_s, although strcpy_s also checks if the source string has reached the end. Since this code already knew how long the source string was by the call to strlen, I could use memcpy instead of strcpy_s - memcpy is ever so slightly faster.
if 'n' is known, say 1024, would this be equivalent to your calloc? char* array[1024] = {NULL};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.