下面的C代码编译并运行,但它是未定义的吗?

下面的C代码编译并运行,但它是未定义的吗?,c,pointers,undefined-behavior,C,Pointers,Undefined Behavior,我发布了一个关于我之前在这个问题中遇到的一些指针问题的问题: 从一些评论中,我相信: #include <stdlib.h> #include <stdio.h> int main(){ int *p; *p = 1; printf("%d\n", *p); return 0; } int i; int *p; p = &i; #包括 #包括 int main(){ int*p; *p=1; printf(“%d\

我发布了一个关于我之前在这个问题中遇到的一些指针问题的问题:

从一些评论中,我相信:

#include <stdlib.h>
#include <stdio.h>
int main(){
   int *p;
   *p = 1;
   printf("%d\n", *p);
   return 0;
}
int i;
int *p;
p = &i;
#包括
#包括
int main(){
int*p;
*p=1;
printf(“%d\n”,*p);
返回0;
}
这是一种未定义的行为。这是真的吗?我一直都这样做,甚至在我的C课程中也看到过。 然而,当我

#include <stdlib.h>
#include <stdio.h>
int main(){
   int *p=NULL;
   *p = 1;
   printf("%d\n", *p);
   return 0;
}
#包括
#包括
int main(){
int*p=NULL;
*p=1;
printf(“%d\n”,*p);
返回0;
}
在打印
p
的内容之前(在
*p=1;
行之后),我遇到了seg故障。这是否意味着我应该一直
malloc
在任何时候为指向的指针赋值

如果是这样,那么为什么
char*string=“这是一个字符串”
总是有效


我很困惑,请帮帮我

是,执行
int*p*p=1是未定义的行为。您正在解除对未初始化指针的引用(访问它所指向的内存)。如果它能工作,那只是因为
p
中的垃圾恰好是某个内存区域的地址,该区域是可写的,并且其内容不够关键,当您重写它们时不会立即导致崩溃。(但您仍然可能损坏了一些重要的程序数据,导致了稍后才会注意到的问题…)

如此明显的例子应该会触发编译器警告。如果没有,请找出如何调整编译器选项。(在gcc上,请尝试
-Wall-O

指针必须指向有效内存才能解除引用。这可能是由
malloc
分配的内存,也可能是现有有效对象的地址(
p=&x;

char*string=“这是一个字符串”非常好,因为这个指针不是未初始化的;你初始化了它!(字符字符串
中的
*
是其声明的一部分;您没有取消对它的引用。)具体来说,您使用一些内存的地址初始化了它,您要求编译器保留这些内存并用字符
填充这是一个字符串\0
。这样做之后,您就可以安全地取消对该指针的引用(尽管只用于读取,因为写入字符串文本是未定义的行为)

这是一种未定义的行为。这是真的吗

当然是。它看起来就像是在你的系统上用你尝试过的东西工作,但是你正在执行一个无效的写操作。由于写入无效,您首先将
p
设置为
NULL
的版本是segfaulting,但在技术上它仍然是未定义的行为

您只能写入已分配的内存。如果您不需要指针,最简单的解决方案是只使用常规的
int

int p = 1;
一般来说,尽量避免使用指针,因为使用自动变量要容易得多

您的
char*
示例之所以有效,是因为C语言中字符串的工作方式——内存中的某个地方有一块带有序列“thisastring\0”的内存块,您的指针指向该块。但这将是只读内存,尝试更改它(即,
string[0]='T';
)是未定义的行为。

这是:

int *p;
*p = 1;
是未定义的行为,因为
p
没有指向任何地方。它未初始化。因此,当你试图去引用
p
时,你实际上是在向一个随机地址写入数据

这意味着,无法保证该计划将起到什么作用。它可能会崩溃,可能会输出奇怪的结果,或者看起来工作正常

这也是未定义的行为:

int *p=NULL;
*p = 1;
因为您正在尝试取消对空指针的引用

这项工作:

char *string = "this is a string" ;
因为您正在使用字符串常量的地址初始化
string
。这和另外两个案子不一样。实际上与此相同:

char *string;
string = "this is a string";
请注意,此处未取消对
字符串的引用。指针变量本身被赋值。

带行

char *string = "this is a string";
您正在使指针
字符串
指向只读内存中包含字符串
“这是一个字符串”
的位置。编译器/链接器将确保此字符串将被放置在适合您的位置,并且指针
string
将指向正确的位置。因此,可以保证指针
字符串
指向有效的内存位置,而无需您采取任何进一步的操作

然而,在代码中

int *p;
*p = 1;
p
未初始化,这意味着它未指向有效的内存位置。因此,取消引用
p
将导致未定义的行为

不必总是使用
malloc
使
p
指向有效的内存位置。这是一种可能的方法,但还有许多其他可能的方法,例如:

#include <stdlib.h>
#include <stdio.h>
int main(){
   int *p;
   *p = 1;
   printf("%d\n", *p);
   return 0;
}
int i;
int *p;
p = &i;
现在
p
也指向一个有效的内存位置,并且可以安全地解除引用。

请考虑以下代码:

#include <stdio.h>
int main(void)
{
  int i=1, j=2;
  int *p;
  ... some code goes here
  *p = 3;
  printf("%d %d\n", i, j);
}
#包括
内部主(空)
{
int i=1,j=2;
int*p;
…这里有一些代码
*p=3;
printf(“%d%d\n”,i,j);
}
将语句
*p=2写入
i
j
,还是两者都不写入?如果
p
指向该对象,它将写入
i
j
,但如果
p
指向其他地方,则不会写入。如果代码的
..
部分与
p
没有任何关系,那么
p
可能指向
i
,或
j
,或
stdout
对象中的某个对象,或任何东西。如果恰好指向
i
j
,则写入
*p=3可能会影响该对象而不会产生任何副作用,但如果它指向
stdout
控件中的信息