我正在努力实现一些低级文件写入,其中文件格式特定于每个位。我需要将一个字符串从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
)?
答案 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。
答案 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:
另外......必须小心截断:我们不想截断多字节字符......