【问题标题】:C compilation error for basic function基本函数的 C 编译错误
【发布时间】:2015-04-24 20:48:11
【问题描述】:

我正在尝试编写自己的 strcat 版本(我称之为“附加”)。这是我所拥有的:

#include <stdio.h>

int main() {

  char *start = "start";
  char *add = "add";
  append(start, add);
  printf(start);

}

void append(char *start, char *add) {
  //get to end of start word
  char *temp = &start;
  while (*temp != '\0') {
    temp++;
  }
  *temp = *add;
  while (*temp != '\0') {
     *temp = *add; 
  }
}

当我编译时,我收到 3 个警告和一个错误:

1) 警告:函数 'append' 的隐式声明在 C99 中无效

2) 警告:格式字符串不是字符串文字(可能不安全)

3) 错误:'append' 的类型冲突

我看不到我在 main 中传递给 append 函数的参数如何与它下面的函数定义冲突。

4) 警告:使用 'char **' 类型的表达式初始化 'char *' 的指针类型不兼容;删除 &

我为什么要在这里删除&amp;?我想我可以一次声明并初始化我的 char 指针到正确的内存地址。

非常感谢任何帮助。

【问题讨论】:

  • 你不能那样做。一方面,字符串文字可能位于只读内存中。另一方面,start 中不会有任何备用内存来附加add。更多 - char *temp = &amp;start; 应该是 char *temp = start;,因为你已经获得了一个指针。
  • @hacks 先生,您击败了 my 26 line answer just 1 line。 :-)

标签: c string pointers c99 implicit-declaration


【解决方案1】:

1) 警告:函数 'append' 的隐式声明在 C99 中无效

3) 错误:'append' 的类型冲突

因为,您在使用之前没有提供append() 的原型。您需要在使用之前添加函数的前向声明。添加

void append(char *start, char *add);

main()之前或将函数定义放在main()之前

接下来,以防万一

 char *start = "start";
 char *add = "add";

startadd 是指向字符串字面量 的指针。它们通常放置在只读存储器中,这意味着您无法更改内容。任何这样做的尝试都会导致undefined behavior

那么,关于

2) 警告:格式字符串不是字符串文字(可能不安全)

printf(start);

在这种情况下是错误的用法。你需要像这样使用它

printf("%s\n", start);

查看printf()man page 了解更多详情。

最后,

4) 警告:使用 'char **' 类型的表达式初始化 'char *' 的指针类型不兼容;删除 &

是因为

char *temp = &start;

你需要使用类似的东西

char *temp = start;   //start is a char *, no need for & here

注意:main() 的推荐签名是int main(void)

【讨论】:

  • Minor: "printf(start); 使用错误。"嗯也许对新人不好,但肯定是合法的代码。这只是一个警告。
  • @chux 对,先生,我的意思是在这种情况下。将相应更新以澄清。感谢您的评论。 :-)
【解决方案2】:

这个短代码有多个问题。首先你有

警告:函数 'append' 的隐式声明在 C99 中无效

这个警告的意思是你需要在使用它们之前声明函数。如果你没有在使用函数之前声明它,编译器将不得不猜测它的参数和返回类型,而且它经常猜测得很糟糕。

继续下一个警告:

警告:格式字符串不是字符串文字(可能不安全)

这是因为您向printf 提供了一个字符串变量,就像警告告诉您的那样,这是不安全的。例如,考虑一下您从用户那里读取输入并将该输入用作printf 的格式字符串的情况。什么会阻止用户在输入字符串中添加格式代码?而且由于您不传递参数,这些格式的参数从何而来?

现在是错误:

错误:“附加”的类型冲突

这是因为第一个问题,编译器猜错了函数的参数或返回类型。


现在讨论另一个未显示为编译器错误或警告的主要问题,即undefined behavior

问题是您的 startadd 变量指向字符串文字。字符串文字是只读的(实际上,字符串文字是指向不可修改字符数组的指针)。第一个问题是您尝试修改这些数组的内容,第二个问题是这些数组只有需要的大小,并且您在该内存之外进行写入。这两个问题都是未定义行为的原因。

【讨论】:

  • 注意:我认为这是未定义的行为,当代码尝试修改字符串文字时会发生什么?并不是字符串文字是只读的——它们可以是只读的——它们可能不是。当然同意代码不应该尝试修改它们。
  • @JoachimPileborg 所以即使我有一个足够大的字符数组,我也无法修改它。那么 C 人将如何编写附加函数。只需在方法中创建一个全新的(更大的)字符数组并复制到起始字符数组中,添加添加字符数组,然后返回这个新创建的字符数组?
  • @bclayman 如果你有一个 array 你可以修改它,例如char start[256] = "start";
【解决方案3】:

但这是最简单的部分,编译器可以检测到。

更糟糕的是,当您将 start 声明为 char *start = "start" 时,它只指向一个由 6 个字符组成的数组(5 个字母 + 终止 null)。

因此,当您尝试在其末尾添加 add 时,您会得到未定义的行为(用于写入数组之外)!在这种情况下,您正在编写内存,而其他内存可能是 => 您的程序可能会中断或出现段错误。

【讨论】:

    【解决方案4】:

    C99 对声明事物的方式非常严格。

    正如苏拉夫所说, 1 & 3 是由您的 append() 函数在文件中声明之前使用引起的,这会导致编译器为您生成隐式声明。将 append() 函数移到 main() 上方以修复该问题(或添加函数原型)。

    4 是由这一行引起的:char *temp = &amp;start;

    temp 这里实际上是一个char**,因为你取的是char* 的地址

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-21
      • 1970-01-01
      • 1970-01-01
      • 2020-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多