Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我们怎么能这样说;int i";是定义也是声明_C_Declaration_Definition - Fatal编程技术网

C 我们怎么能这样说;int i";是定义也是声明

C 我们怎么能这样说;int i";是定义也是声明,c,declaration,definition,C,Declaration,Definition,以下是Dennis Ritchie C编程书中的直接内容: 声明是指声明变量性质但未分配存储的位置。定义是指在存储中创建或分配变量的位置 问题 “创建变量”和“声明变量”之间的区别到底是什么 在下面的程序中,变量j刚刚声明,没有定义,所以为什么没有编译错误,因为我们正在将j的地址值分配给I,而变量j尚未分配存储(编译期间) int*I,j是声明还是定义?我得到的是,这是一个定义。但在这本书中,它既是宣言又是定义 我对林克和里奇书中给出的两个截然不同的概念感到困惑 请说明我错在哪里?是否值分配

以下是Dennis Ritchie C编程书中的直接内容:

声明是指声明变量性质但未分配存储的位置。定义是指在存储中创建或分配变量的位置


问题

“创建变量”和“声明变量”之间的区别到底是什么

在下面的程序中,变量
j
刚刚声明,没有定义,所以为什么没有编译错误,因为我们正在将
j
的地址值分配给
I
,而变量
j
尚未分配存储(编译期间)


int*I,j
是声明还是定义?我得到的是,这是一个定义。但在这本书中,它既是宣言又是定义

我对林克和里奇书中给出的两个截然不同的概念感到困惑


请说明我错在哪里?是否值分配被推迟到运行时,并且在运行时变量
j
被分配为垃圾值,因此没有错误?

声明声明变量的类型(这也有助于确定它需要多少空间)

定义说明变量的类型,并为变量分配空间


是的,每个定义都是一个声明

这是一项声明:

extern int j;
在这个声明之后,编译器知道
j
的类型是
int
。在这个声明之后,我们可以说

printf("%d\n", j);
我们可以这样说,编译器不会抱怨(至少,它不会马上抱怨),因为至少目前,编译器拥有它所需要的所有信息

但是,如果我们试图编译这个完整的程序:

#include <stdio.h>

extern int j;

int main()
{
    printf("%d\n", j);
}
该错误意味着,尽管编译器知道
j
是什么,但最终构建过程(
ld
)没有在任何地方找到
j
的实际定义

你说

在上面的程序变量
j
中,刚刚声明,未定义

否,在您的程序中定义了
j

int*i,j
是声明还是定义

这是两个变量的定义。它定义类型为
int
j
,类型为
int*
i
,或指向-
int
的指针

看起来您已经开始使用指针了,当您使用指针时,您必须更仔细地考虑内存分配。(您可能还需要考虑静态和动态分配之间的区别。)

首先要了解的是,编译器完全能够分配内存。编译器始终为变量分配内存。只有当您开始使用指针时,您才需要开始担心内存分配,并自行分配内存

正如我们所说,这条线

int *i;
这是一个定义。它说明指针指向-
int
类型的名为
i
的变量的类型,并为其分配空间

但在本例中,我们分配的空间是指针。我们没有为指针指向的内容分配任何空间。事实上,这个指针还没有指向任何地方:它还未初始化

如果我们说

int j;
int *i = &j;
int *i = malloc(sizeof(int));
现在指针
i
确实指向某个地方:它指向变量
j
。现在,我们不仅为指针
i
分配了内存,还为指针指向分配了内存

为指向的指针分配内存的另一种方法是动态内存分配,通常通过调用
malloc
。如果我们说

int *i = malloc(sizeof(int));
我们再次为
i
和它所指向的内容分配了内存。我们让编译器为
i
分配内存,并调用
malloc
i
动态分配内存

一些图片可能会有帮助。以下是第一段代码后的情况:

   +-----------+
j: |           |
   +-----------+
         ^
         |
   +-----|-----+
i: |     *     |
   +-----------+
   +-----------+         +-----------+
i: |     *-------------> |           |
   +-----------+         +-----------+
这两个框都是由编译器分配给我们的

下面是第二段代码后的情况:

   +-----------+
j: |           |
   +-----------+
         ^
         |
   +-----|-----+
i: |     *     |
   +-----------+
   +-----------+         +-----------+
i: |     *-------------> |           |
   +-----------+         +-----------+
左边的
i
框是编译器分配给我们的,右边的未命名框是我们从
malloc
获得的

申报怎么样?什么是

extern int j;
看起来像?我想我会这样画:

j:
有一个符号(一个名称)
j
,但旁边还没有一个方框(尽管如果有方框,它的大小和形状应该适合容纳
int


在你询问的评论中

给定
intj;int*i=&j
我们不知道
j
的内存位置,因此如何将其地址分配给
i

我不知道你说的“我们不知道
j
的内存位置”是什么意思。我们可能不知道地址,但编译器知道。编译器会尽一切努力确保在已知位置为
j
分配空间。表达式
&j
字面意思是“获取变量
j
的已知位置”。自从

int j;
是一个定义,它意味着
j
将在已知位置分配空间


在所有这一切中,我一直在说“编译器为…分配内存”,但实际上它比这要复杂一点。实际内存的实际分配可能会在以后进行

对于局部变量,编译器在堆栈上“分配”变量。它实际上(通常)做的是在函数的堆栈框架中留出空间。从某种意义上说,局部变量的“地址”是它与堆栈帧底部的偏移量。在程序运行、调用函数并在堆栈上的特定地址创建其堆栈帧之前,变量的实际地址是未知的

int *i = &j;