我将 C 用于自定义 IOS 库。现在我已将我的 XCode 升级到 5.0 开发者预览版。现在strcpy对我不起作用,此时应用程序崩溃。任何人都可以解释我是什么问题?
更新
这是我的代码:
char global[] = " ";
printf("Error opening %s for constants input\n", lang);
strcpy(global, lang);
In printf
lang 正在工作,但 strcpy 不工作。
当您声明global
为
char global[] = " ";
只有两个字符足够的空间。空格和字符串终止符。设置一个足够大的大小以包含您尝试复制到它的整个字符串,或者使其成为指针并动态分配它(在这种情况下,您不应该忘记为字符串终止符分配空间)。
避免使用strcpy
,除非您绝对确定目标数组中有足够的空间。
试试这个以获得安全版本。它仍然很糟糕,因为lang
可能不适合,但它是安全的。
char global[] = " ";
// alternative 1
snprintf(global, sizeof global, "%s", lang);
// alternative 2, more lines but also slightly more efficient
global[0] = 0;
strncat(global, lang, (sizeof global) - 1); // -1 needed to allow room for '\0'
为了解决空间问题,如果您知道限制并且它相当小,您可能应该足够global
大以容纳所有可能的lang
字符串:
char global[16] = ""; // room for 15 characters, contents initialized to all 0
snprintf(global, sizeof global, "%s", lang);
另一种方法是使用动态内存:
int bufsize = strlen(lang) + 1;
char *global = malloc(bufsize); // contents uninitialized
// can't use sizeof, it would give size of pointer, not allocated buffer
snprintf (global, bufsize, "%s", lang);
...
free(global); global = NULL;
对于使用动态内存,还请查看asprintf
,记录在与(上面的链接)相同的手册页中snprintf
。
您也可以考虑使用 C99 的可变长度数组,但如果变量名称为global
,它可能不适用于您的情况:
char global[strlen(lang) + 1] = ""; // +1 for '\0', contents initialized to all 0
snprintf (global, sizeof global, "%s", lang); // now sizeof works again
// global is unallocated when it goes out of scope
请注意,对于动态内存,您为 的当前内容分配了足够的内存lang
,您也可以使用strcpy
它,因为在这种情况下,您确实知道它适合安全。尽管如此,使用安全版本可能会更有效地应对未来引入新错误的修改。
作为原始 C 代码的作者,我认为这是为了让我解释。
一段更完整、更准确的代码:
char predictLanguage[] = " ";
void openPredictionConstants(char* language){
strcpy(predictLanguage, language);
if ((file = fopen(strcat(DATFILEPATH, predictLanguage), "_constants"), ".dat"), "rb")) == NULL){
printf("Error opening %s for constants input\n", filename);
exit(EXIT_FAILURE);
}
// Code for processing if file is opened successfully
}
该language
参数始终是一个 5 字符的语言环境,即“en-GB”、“en-US”等,因此静态分配的 char 数组很适合这项工作。
但是,该predictLanguage
参数只有 4 个字符长 + 0 终止符,总共 5 个字符。language
是 5 个字符 + 0 终止符,总共 6 个字符。换句话说 - 正如一些人已经指出的那样 -predictLanguage
不足以包含传入的语言环境language
。
在正常情况下,我会用定义的长度初始化 char 数组,比如char predictLanguage[6]
,但因为我想确保predictLanguage
不包含垃圾,所以我用空字符串初始化它。
原来我在计算空格并想出不正确的长度时脑子里放了个屁。错误只是没有在 iOS6 中表现出来。
错误的最可能原因是global
数组不够长,无法包含lang
. 在不知道 的值的情况下lang
,我们不能肯定地说。就目前而言,如果lang
包含多个字符和空终止符,则调用会strcpy
导致缓冲区溢出。
您需要确保它global
足够大以包含lang
. 您在注释中声明它lang
是形式的 iso 语言代码"**-**"
。你举的例子是"ad-dv"
。如果您确定lang
长度不超过 6 个字符(包括空终止符),那么您可以这样编写代码:
char global[6];
strcpy(global, lang);
另一个明显的选择是动态分配字符串:
char *global = malloc(strlen(lang)+1);
strcpy(global, lang);
请记住在free(global)
完成变量后调用。
另一种常见的故障模式strcpy
是源字符串不是以空值结尾的,这也会导致缓冲区溢出。