memcpy会正确复制一个字符串吗?

时间:2013-02-18 22:47:54

标签: objective-c c nsstring memcpy strcpy

我正在努力实现一些低级文件写入,其中文件格式特定于每个位。我需要将一个字符串从NSString复制到以空值终止的字符串,长度为16(根据Xcode,这是不可分配的)。对于c,我总是 n00b ,并且我想确保我理解正确。这就是我目前正在做的事情:

//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string
memcpy(&profile.friendly_name, &string, 16);

这还没有经过测试,但我想确定这会有效。这会提供我期待的行为吗?或者我应该以不同的方式复制字符串(例如strcpy)?

4 个答案:

答案 0 :(得分:4)

您可以使用memcpy()strcpy(),但您必须自行检查边界,并且代码中还有其他错误。

所以,我认为你想要将NSString复制到char[16]数组中。您可以使用NSString内置方法执行此操作,而不必自己使用memcpy()

NSString *src;
char dest[16];
NSUinteger destlen;
[src getBytes:dest
    maxLength:sizeof(dest) - 1
    usedLength:&destlen
    encoding:NSUTF8StringEncoding
    options:0
    range:NSMakeRange(0, [src length])
    remainingRange:NULL];
dest[destlen] = '\0';

如果您想使用memcpy(),那么您必须这样做:

NSString *src;
char dest[16], *srcUtf8;
size_t len;

srcUtf8 = [src UTF8String];
len = strlen(srcUtf8);
if (len >= sizeof(dest))
    len = sizeof(dest) - 1;
memcpy(dest, srcUtf8, len);
dest[len] = '\0';

代码中的错误

此代码中有两个错误!

memcpy(&profile.friendly_name, &string, 16); // Wrong!

首先,&string是错误的。它应该是string,因为string是指向要复制的字符串数据的指针。如果复制&string,您将获得一个指针,并且会复制一些随机的堆栈数据。换句话说,你会得到垃圾。

其次,16是错误的。如果您知道string指向至少16个字节的数据,则只能复制16个字节。如果string小于16个字节,则会导致分段错误(程序崩溃),内存中的后续数据无法读取。它今天可能不会崩溃,但也许它会在下周崩溃,你会忘记它的全部内容吗?

这是错误的,除非你知道源至少有16个字节,否则不要传递16。

答案 1 :(得分:3)

memcpy()应该可以正常工作,但strcpy()也可以正常工作。您只需要确保profile.friendly_name足够大,可以保存您正在复制的内容。

答案 2 :(得分:2)

你读过这份文件吗? memcpy可以工作,但你传入要复制的字节数。它将复制您指定的字节数,与NULL无关。 strcpy你没有传递长度,它会将字节复制到包括第一个NULL。

http://www.cplusplus.com/reference/cstring/memcpy/

http://www.cplusplus.com/reference/cstring/strcpy/

答案 3 :(得分:0)

//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string  : char [17] ??
memcpy(profile.friendly_name, string, 16);
profile.friendly_name[16]='\0';

编辑: 对,就是这样。添加NULL。实际上,在复制之前初始化为所有0可能更好。如果strcpy在位置16之前没有_friendly_name,则'\0'将无效。strncpy会没问题。

EDIT2:

出现了一些问题,为什么我们没有所有需要的信息:

1-您需要一个以NULL结尾的长度为16的字符串(16个字符+ 0,如char var[17];中所示),或者您需要一个16字节的字段终止为NULL,如char var[16];中那样?

2-什么是desred“错误”管理:如果原始字符串大于“16”我们只是截断它,或者我们输入错误?

假设您需要一个16字节的字段和一个截断字符串,您可以使用:

strncpy(profile.friendly_name, string, 15);
profile.friendly_name[15]='\0';

EDIT3:

另外......必须小心截断:我们不想截断多字节字符......