C语言中传递指针

 2024-01-29 00:02:26  阅读 0

C语言中传递指针

传递指针允许多个函数访问指针引用的对象,而无需将该对象声明为全局可访问。 要修改函数中的数据,需要使用指针传递数据。 当数据是需要修改的指针时, 要将指针传递给指针,传递参数(包括指针)时,传递的是它们的值。 也就是说,传递给函数的是参数值的副本。 本文将讨论 C 语言中传递给函数和从函数传递的指针。 返回指针的内容。

使用指针传递数据

使用指针传递数据的主要原因之一是函数可以修改数据

下面的代码实现了一个通用的交换功能:

#

无效交换(int * a,int * b)

int tmp;

tmp = *a;

*a = *b;

*b = tmp;

int main()

整数 m,n;

米 = 5;

n = 10;

(“m=%d,n=%d”,m,n);

交换(&m,&n);

(“m=%d,n=%d”,m,n);

0;

如果参数不通过指针传递,则不会发生交换。 具体原理可以参考任何C语言教材。

将指针传递给常量

将指针传递给常量是C中常用的技术。它非常有效,因为它避免了在某些情况下复制大量内存。 如果您不想修改数据,则必须传递指向常量的指针。

我们无法修改通过指向常量的指针传入的值:

#

void (const int* num1, int*num2)

*num2 = *num1;

int main()

常量 int a = 100;

整数 b = 5;

(“a=%d,b=%d”,a,b);

(&a,&b);

(“a=%d,b=%d”,a,b);

0;

下面的代码会产生错误(第二个形参和实参的类型不匹配,试图修改第一个形参引用的常量):

#

void (const int* num1, int* num2)

*num1 = 100;

*数字2 = 200;

int main()

常量 int 限制 = 100;

(&限制,&限制);

0;}

C语言中堆和栈的区别

预备知识——程序的内存分配

C编译的程序所占用的内存分为以下几部分:

1、栈区(stack)——由编译器自动分配和释放,存储函数参数值、局部变量值等。它的操作就像数据结构中的栈一样。

2.堆区(heap)——一般由程序员分配和释放。 如果程序员不释放它,当程序结束时它可能会被操作系统回收。 注意,它与数据结构中的堆不同,分配方式类似于链表。

3.全局区(静态区)(),全局变量和静态变量存放在一起。 已初始化的全局变量和静态变量位于一个区域,未初始化的全局变量和未初始化的静态变量位于相邻的区域。 另一个区域。 程序结束后由系统释放。

指针函数作用_c语言函数指针与指针函数_c语言结构体函数指针

4、文字常量区——常量字符串放置于此,程序结束后由系统释放。

5. 程序代码区——存放函数体的二进制代码。

我们先来说说C语言程序内存分配中的堆和栈。 通常,内存分配程序存储在ROM或Flash中。 运行时需要将其复制到内存中执行。 内存会分别存储不同的信息,如下图所示:

内存中的堆栈区域处于相对较高的地址。 如果地址增长方向向上,则堆栈地址向下增长。 局部变量空间在栈中分配,堆区域向上增长以分配程序员请求的内存空间。 。 另外还有静态区,分配静态变量和全局变量空间; 分配常量和程序代码空间的只读区域; 以及其他一些分区。

栈之间的区别,我们看一个经典的例子:

#

#

整数a = 0; //全局初始化区域

字符*p1; //全局未初始化区域

int main()

整数b; //堆

char s[] = "abc"; //堆

字符*p2; //堆

字符 *p3 = ""; //常量区中,p3在栈上。

int c = 0; //全局(静态)初始化区域

p1 = (字符*)(10); //堆

p2 = (字符*)(10);

0;

不知道你是否明白一点点。 堆和栈的第一个区别就是申请方式不同:栈(英文名称为stack)是由系统自动分配的。 例如,如果我们定义一个 char a; 系统会自动在栈上为其分配空间。 打开

空间。 堆(英文名称为heap)是程序员根据需要申请的空间,如(10); 由于栈上的空间是自动分配和自动回收的,所以栈上数据的生命周期只在函数运行过程中。 ,运行后会被释放,无法再次访问。 只要程序员不释放空间,堆上的数据总是可以被访问的。 但缺点是如果程序员忘记释放,就会造成内存泄漏。 还有一些其他差异在网上得到了很好的总结,并在此处解释:

1.申请后系统响应

栈:只要栈的剩余空间大于申请的空间,系统就会为程序提供内存,否则会报异常提示栈溢出。

堆:首先你应该知道操作系统有一个记录空闲内存地址的链表。 当系统收到程序的请求时,会遍历链表,寻找第一个空间大于请求空间的堆节点,然后将该节点从链表中删除空闲节点并分配空间程序的节点。 另外,对于大多数系统来说,本次分配的大小会被记录在这块内存空间的首地址处,以便代码中的语句能够正确释放这块内存空间。 另外,由于找到的堆节点的大小不一定正好等于请求的大小,系统会自动将多余的部分放回到空闲链表中,这意味着堆还要做一些后续工作申请后。 这就会带来应用效率的问题。

2、应用效率对比

堆栈:由系统自动分配,速度更快。 但程序员无法控制。

堆:是new分配的内存。 一般情况下速度较慢且容易产生内存碎片,但使用起来最方便。

3. 应用程序大小的限制

栈:下面,栈是一种向低地址延伸的数据结构,是一块连续的内存区域。 这句话的意思是,栈顶的地址和栈的最大容量是系统预先确定的。 下面,栈的大小为2M(有的说是1M,总之是编译时确定的常量)。 如果你申请的空间超过了堆栈的剩余空间,就会有提示。 因此,堆栈的可用空间较小。

堆:堆是一种向高地址扩展的数据结构,是一个不连续的内存区域。 这是因为系统使用链表来存储空闲内存地址,这些地址天然是不连续的,而链表的遍历方向是从低地址到高地址。 堆的大小受到计算机系统中可用的虚拟内存的限制。 可见堆获得的空间更加灵活、更大。

4.堆和栈中存储内容

栈:函数调用时,首先压入栈的是主函数中函数调用后的下一条指令的地址(函数调用语句的下一条可执行语句),然后是函数的各种参数。 在大多数 C 编译器中,参数是从右向左压入堆栈的,后面是函数中的局部变量。 请注意,静态变量不会压入堆栈。 当这个函数调用结束时,局部变量先出栈,然后是参数,最后栈顶指针指向原来存放的地址,也就是main函数中的下一条指令。 程序从此时开始继续运行。

堆:一般在堆的头部用一个字节来存储堆的大小。 堆的具体内容由程序员安排。

引用一位前辈的比喻可以看出堆和栈的区别:

使用堆栈就像我们去餐馆吃饭一样。 我们只是点餐(发出申请)、付款、吃饭(使用)。 当我们吃饱了,我们就离开。 切菜、洗菜、洗碗、洗锅等准备工作我们不用操心,收尾工作的好处是速度快,但自由度不大。 使用 Dui 就像制作自己喜欢的菜肴一样。 比较麻烦,但是更符合自己的口味,自由度更大。

局部变量指针

如果不了解程序堆栈的工作原理,很容易犯返回指向本地数据的指针的错误。 请参见以下示例:

#

#

int*(int 大小,int 值)

int arr[大小];

for(int i = 0; i < 大小; i++) {

arr[i] = 值;

到达;

int main()

整数* = (5, 45);

for(int i = 0; i < 5; i++) {

(“%d”,[i]);

c语言结构体函数指针_指针函数作用_c语言函数指针与指针函数

0;

一旦函数返回,返回的数组地址就无效,因为函数的堆栈帧已从堆栈中弹出。

一种方法是将 arr 变量声明为,这会将变量的作用域放在函数内部,但将其分配在堆栈帧之外,以防止其他函数覆盖变量值。

#

#

int*(int 大小,int 值)

int arr[10];

for(int i = 0; i < 大小; i++) {

arr[i] = 值;

到达;

int main()

整数* = (5, 45);

for(int i = 0; i < 5; i++) {

(“%d”,[i]);

0;

返回指针

从函数返回对象通常使用以下两种技术:

在函数内部使用分配内存并返回其地址,调用者负责释放返回的内存

将对象传递给函数并让函数修改它。 这样,分配和释放对象的内存就是调用者的责任。

#

#

int*(int 大小,int 值)

int* arr = (int*)(大小 * (int));

for(int i = 0; i < 大小; i++) {

arr[i] = 值;

到达;

int main()

整数* = (5, 45);

for(int i = 0; i < 5; i++) {

(“%d”,[i]);

自由的();

0;

该函数的以下版本传递一个数组指针、数组的长度以及用于初始化数组元素的值。 返回指针只是为了方便。

#

#

int* (int *arr, int 大小, int 值)

if(arr != NULL) {

for(int i = 0; i < 大小; i++) {

arr[i] = 值;

到达;

int main()

int* = (int*)(5 * (int));

(, 5, 45);

for(int i = 0; i < 5; i++) {

(“%d”,[i]);

自由的();

0;

将指针传递给指针

将指针传递给函数时,您传递了一个值。 如果要修改原始指针而不是指针的副本,则需要传递指针的指针。

#

#

void (int **arr, int 大小, int 值)

*arr = (int*)(大小 * (int));

if(arr != NULL) {

for(int i = 0; i < 大小; i++) {

*(*arr + i) = 值;

int main()

int* = NULL;

(&, 5, 45);

for(int i = 0; i < 5; i++) {

(“%d”,[i]);

自由的();

0;

二叉树递归实现和双指针

二叉树的很多操作往往是通过递归调用来实现的,这就决定了整个过程不能只通过main函数来实现,需要调用main之外定义的函数。 因此,对main调用之外定义的函数的参数传递有严格的要求。 在网上搜了很多构建二叉树的程序,但是当我直接复制到自己的电脑上运行时,发现很多错误,无法编译。 以下代码编译通过,不涉及二叉树的所有操作。 重点通过C语言创建二叉树的过程来说明递归实现和双指针的相关问题。

1.二叉树的定义

二叉树的定义结构通常采用以下形式:

节点

字符ch;

节点*,*;

}节点,*BTree;

Node一般可以用来定义二叉树节点,*BTree可以用来定义指向二叉树(根节点)的指针。

2.动态内存分配

使用动态内存分配需要使用函数。 值得注意的是,该函数成功开辟新内存时,默认返回一个void*指针,因此需要强制转换为Node*形式,其调用形式如(Node*)((Node))

3. 递归调用

由于需要递归调用,二叉树上的一些操作需要作为函数独立执行。 不过这些函数都是在main中调用的,所以对传递参数和返回值的处理非常重要。 另外要注意的是,要操作二叉树,首先要知道二叉树的入口,即指向二叉树的指针,即指向二叉树根节点的指针。 因此,传递的参数是一个指向根节点的指针。 并且由于操作涉及分配内存,因此必须传递辅助指针。 在下面的程序中,函数可能有也可能没有返回值(因为传递了地址)。 在main函数中测试,返回值是二叉树根节点的值。

void (节点** pTree)

字符ch;

scanf("%c",&ch);

if(chr == '#') {

(*pTree) = NULL;

} 别的 {

if(!((*pTree) = (节点*)((节点)))) {

出口();

(*pTree)->ch = chr;

(&((*pTree)->));

(&((*pTree)->));

【C语言中指针的传递】相关文章:

1.C语言指针教学

2.C语言指针的使用

3.C语言中指针使用详解

4.C语言指针函数和函数指针详解

5.C语言中指针类型分析

6.C语言中指针的解释

7.C语言中指针数组的概念

8.C语言数组和指针详解

标签: 指针 函数 传递

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码