0

我将 C 用于自定义 IOS 库。现在我已将我的 XCode 升级到 5.0 开发者预览版。现在strcpy对我不起作用,此时应用程序崩溃。任何人都可以解释我是什么问题?

更新

这是我的代码:

char global[] = " ";
printf("Error opening %s for constants input\n", lang); 
strcpy(global, lang); 

In printflang 正在工作,但 strcpy 不工作。

4

4 回答 4

5

当您声明global

char global[] = " ";

只有两个字符足够的空间。空格和字符串终止符。设置一个足够大的大小以包含您尝试复制到它的整个字符串,或者使其成为指针并动态分配它(在这种情况下,您不应该忘记为字符串终止符分配空间)。

于 2013-09-04T09:47:58.193 回答
1

避免使用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'

snprintf和的手册页供参考strncat


为了解决空间问题,如果您知道限制并且它相当小,您可能应该足够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它,因为在这种情况下,您确实知道它适合安全。尽管如此,使用安全版本可能会更有效地应对未来引入新错误的修改。

于 2013-09-04T10:48:14.340 回答
0

作为原始 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 中表现出来。

于 2013-09-05T07:50:10.753 回答
0

错误的最可能原因是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是源字符串不是以空值结尾的,这也会导致缓冲区溢出。

于 2013-09-04T09:45:20.300 回答