请考虑以下C语言
int arr[]= {1,2,3,4,5};
Run Code Online (Sandbox Code Playgroud)
我的系统使用4个字节来存储int数据.现在&arr[0] => 0022FEB0
和&arr[1]=>0022FEB4运行的那一刻
现在
int diff=&arr[1]-&arr[0];
Run Code Online (Sandbox Code Playgroud)
存储在DIFF值1而不是4.
为什么?
这是下面的代码来说明问题:
#include <stdio.h>
void func(int arr[]);
int main() {
int arr[10];
int n = *(&arr + 1) - arr;
printf("%d\n", n);
func(arr);
return 0;
}
void func(int arr[]) {
int n = *(&arr + 1) - arr;
printf("%d\n", n);
}
Run Code Online (Sandbox Code Playgroud)
上述代码的输出是:
10
268435906
Run Code Online (Sandbox Code Playgroud) 考虑作业,a := b*-c + b*-c.
图 1 上述语句的四元组
以下是红龙书的摘录。
如果多次使用相同的临时值,则间接三元组与四元组相比可以节省一些空间。原因是语句数组中的两个或多个条目可以指向结构的同一行
op-arg1-arg2。例如,下图中的行(14)和(16)可以组合,然后我们可以组合(15)和(17)。图2 三地址语句的间接三重表示
我的问题是摘录中关于使用间接三元组节省空间的内容,我们也可以对四元组说同样的话,如下:
我们可以将语句的三地址代码写为右侧的代码,而不是上图中左侧的代码...然后我们将得到下面的四元组:
这正是摘录中关于间接三元组相对于四元组的优势的内容。
那么我们可以得出什么结论呢?
我听到很多人说,当我们想要将一维数组传递给函数时,fun以下原型是等效的:
1.
\n int fun(int a[]);\nRun Code Online (Sandbox Code Playgroud)\n int fun(int a[10]);\nRun Code Online (Sandbox Code Playgroud)\n int fun(int *a);\nRun Code Online (Sandbox Code Playgroud)\n我什至听到人们说第一个和第二个在 C 中内部转换为第三个。我猜这是真的,因为sizeof(a)在 2 中声明的函数的定义中执行某些操作会给出指针的大小(以字节为单位)(而不是 10*sizeof(int))。
话虽这么说,我已经看到一些文本声称将 2D 数组传递给函数,以下内容是等效的:
\n1.
\nint fun(int a[][10]);\nRun Code Online (Sandbox Code Playgroud)\nint fun(int (*a)[10]);\nRun Code Online (Sandbox Code Playgroud)\n在这里我再次听到人们说在 C 中第一个在内部转换为第二个。如果这是真的,那么下面的内容应该是等价的,对吗?
\n1.
\nint fun(int a[][]);\nRun Code Online (Sandbox Code Playgroud)\nint fun(int (*a)[]);\nRun Code Online (Sandbox Code Playgroud)\n但不幸的是,第一个提出了编译错误,但第二个没有:
\n 1 | int fun(int a[][]);\n | ^\nt.c:2:13: note: declaration of \xe2\x80\x98a\xe2\x80\x99 …Run Code Online (Sandbox Code Playgroud) 自从我被介绍到 以来C,我就被告知C动态内存分配是使用家族中的函数完成的malloc。我还了解到,动态分配的内存malloc是在进程的堆部分分配的。
各种操作系统教科书都说这malloc涉及系统调用(虽然并不总是但有时)来将堆上的结构分配给进程。现在假设malloc返回指向堆上分配的字节块的指针,为什么它需要系统调用。函数的激活记录放置在进程的堆栈部分中,并且由于“堆栈部分”已经是进程虚拟地址空间的一部分,所以激活记录的压入和弹出、堆栈指针的操作,只需从虚拟地址空间的最高可能地址。它甚至不需要系统调用。
现在基于同样的理由,由于“堆部分”也是进程虚拟地址空间的一部分,为什么需要系统调用来在该部分中分配字节块。像这样的例程malloc可以自行处理“空闲”列表和“已分配”列表。它需要知道的只是“数据部分”的结尾。某些文本说系统调用对于“将内存附加到进程以进行动态内存分配”是必要的,但是如果malloc在“堆部分”上分配内存,为什么需要在 期间将内存附加到进程malloc?可以简单地取自过程中已经一部分的部分。
在阅读 Kernighan 和 Ritchie 的《C 编程语言》[2e] 文本时,我发现了他们对该malloc函数的实现 [第 8.7 节第 185-189 页]。作者说:
malloc根据需要调用操作系统获取更多内存。
这就是操作系统文本所说的,但与我上面的想法相反(如果malloc在堆上分配空间)。
由于向系统请求内存是一项相对昂贵的操作,因此作者不会在每次调用 时都这样做,因此他们创建了一个至少请求单位的malloc函数;这个较大的块根据需要被切碎。而基本的空闲列表管理是由.morecoreNALLOCfree
但问题是作者使用sbrk()向操作系统请求内存morecore。现在维基百科说:
brk和是 Unix 和类 Unix 操作系统中使用的基本内存管理系统调用,用于控制分配给进程数据段sbrk的内存量。
在哪里
数据段(通常表示为.data)是目标文件或程序的相应地址空间的一部分,其中包含初始化的静态变量,即全局变量和静态局部变量。
我猜这不是“堆部分”。[数据部分是上图中从下数第二部分,而堆是从下数第三部分。]
我完全困惑了。我想知道到底发生了什么以及这两个概念如何正确?请通过将分散的碎片连接在一起来帮助我理解这个概念......
看下面的代码......我收到了行号的错误.6 ...请任何人解释为什么会发生这种情况?
#include<stdio.h>
struct test{
int data;
};
typedef struct test* Test;
Test obj=(Test) calloc(1,sizeof(struct test));
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在《龙书》中提到“词汇错误包括标识符的拼写错误。例如,拼写错误ellispeSize为elipseSize”
我无法理解这是怎么回事(词法分析器可以识别拼写错误的标识符并导致错误)。和ellipseSize都是elipseSize有效的标识符词位。所以词法分析阶段应该没有问题。可能在编译的后期阶段,我们将了解到elipseSize尚未定义......