DAY7

发布时间 2023-07-29 15:50:37作者: Ninnne

函数返回指针

## 一:

  1. 代码:

#include <stdio.h>
#include <stdlib.h>
int Add(int a,int b){
    int c = a + b;
    return c;
} 
int main(){
    int x = 2, y = 4;
    int z = Add(x,y);
    printf("Sum = %d\n",z);
    
}

输出结果:

Sum = 6
​
  1. x ,y ,z都是main函数的局部变量,a , b, c是Add函数的局部变量

  2. 当调用Add函数时,main函数中的x的值拷贝给函数Add的a,y的值拷贝给函数Add的b

  3. 函数形参只传值,不传址,用&才传址

#include <stdio.h>
#include <stdlib.h>
int Add(int a,int b){
    printf("Address of a in Add = %d\n",&a); 
    int c = a + b;
    return c;
} 
int main(){
    int a = 2, b = 4;
    printf("Address of a in main = %d\n",&a); 
    int c = Add(a,b);
    printf("Sum = %d\n",c);
    
}

输出结果:

Address of a in main = 6487572
Address of a in Add = 6487536
Sum = 6

可以发现两个a的地址是不同的,他们存放在不同的地址中

  1. main函数称为“主调函数”,Add函数被称为“被调函数”

二:

把main函数中a,b的地址传给Add函数

#include <stdio.h>
#include <stdlib.h>
int Add(int* a,int* b){//a,b在Add中是整型的指针变量
    printf("Address of a in Add = %d\n",&a);//会打印出指针变量
    printf("Value in a of Add (address of a of main) = %d\n",a);//会打印出main中a的地址
    printf("Value at address stored in a of Add = %d\n",*a);//会打印main中a的值
    int c = *a + *b;//通过*来访问这些地址的内容
    return c;
} 
int main(){
    int a = 2, b = 4;
    printf("Address of a in main = %d\n",&a); 
    int c = Add(&a,&b);
    printf("Sum = %d\n",c);
    
}

输出结果

Address of a in main = 6487576
Address of a in Add = 6487536
Value in a of Add (address of a of main) = 6487576
Value at address stored in a of Add = 2
Sum = 6
  1. 从这个函数返回一个整型指针:

#include <stdio.h>
#include <stdlib.h>
int* Add(int* a,int* b){//我们对Add函数所做的修改是返回一个整型指针
    int c = *a + *b;
    return &c;//返回c的地址
} 
int main(){
    int a = 2, b = 4;
    int* ptr = Add(&a,&b);//要接收返回的地址,所以需要定义一个指针变量
    printf("Sum = %d\n",*ptr);//打印这个指针地址的值
    
}

输出结果:

Sum = 6
​

这个代码存在问题

ptr保存了c的地址,但c作为子函数的局部变量,已经在栈中被消除了,找不到这个地址的

  1. 增加一个PrintHelloWorld函数

#include <stdio.h>
#include <stdlib.h>
void PrintHelloWorld(){
    printf("Hello World\n");
} 
int *Add(int* a,int* b){
    
    int c = *a + *b;
    return &c;
} 
int main(){
    int a = 2, b = 4;
    int* ptr = Add(&a,&b);
    PrintHelloWorld();//在打印Sum前先调用函数PrintHelloWorld
    printf("Sum = %d\n",*ptr);
    
}

输出:

Hello World
Sum = 0
​

输出有问题

原因:执行到函数PrintHelloWorld时,现在需要为PrintHelloWorld分配栈空间,因为之前没调用打印PrintHelloWorld, 就不会在栈上分配空间,main上面栈帧没改变,调用后改变了。Add函数的栈帧在main函数的上面,调用完以后,他的局部变量消失了

  1. 什么情况下我们回想从函数返回一个指针:如果我们在堆(heap)上有一个内存地址或者在全局区(global)有个变量,我们就可以安全的返回他们的地址

  2.  

#include <stdio.h>
#include <stdlib.h>
void PrintHelloWorld(){
    printf("Hello World\n");
} 
int *Add(int* a,int* b){
    
    int* c = (int*)malloc(sizeof(int));//使用malloc从堆上分配一些空间(malloc是一个库函数,返回一个指针
    *c = *a + *b;//把*a + *b赋给这个指针所指向的内存空间
    return c;//返回地址c(返回的是堆上的地址,是可以的)
} 
int main(){
    int a = 2, b = 4;
    int* ptr = Add(&a,&b);
    PrintHelloWorld();
    printf("Sum = %d\n",*ptr);
​
}

输出:正常

Hello World
Sum = 6
  1. 函数返回指针时,我们必须保证地址没有被重用(用来存储其他东西),以及那个地址的数据没有被清除

 

函数指针

可以用来储存函数的地址,此指针指向函数,我们可以用这样的指针来引用和执行函数。

函数指针储存函数的地址就是说,函数指针存放在了函数在内存中的起始地点或者说入口点

#include <stdio.h>
#include <stdlib.h>
int Add(int a, int b) {
    return a+b;
}
int main(){
    int c;
    int (*p)(int,int);//创建一个指针指向这个函数Add 
    p = &Add;//填入函数的地址 
    //把Add的地址赋给p ,通过p我们就可以执行函数Add 
    c = (*p)(2,3); //传入两个整型变量2和3 
    printf("%d",c); 
}

输出:

5
  1. 函数指针中声明的参数类型,要和所指向的这个函数的类型一致。所以指向函数的指针应该将(int,int)作为参数并返回int

int (*p)(int,int);
  1. 这里首先使用*操作符解引用来获得这个函数,然后把2个参数传给这个函数

c = (*p)(2,3);
  1. 如果不使用括号把指针变量名括起来,就表示的是声明了一个函数,这个函数返回一个整型指针

int *p(int,int);
  1. 这是在声明一个函数,它返回一个整型指针

int *Func(int,int);
  1. 加上括号就是在声明一个函数指针

int *(Func)(int,int);
  1. 有两种方式引用和解引用

p = Add;//不使用&,它的含义也一样,只使用函数名也会返回函数的地址
c = p(2,3);//解引用时,也可以直接使用函数指针名
  1. 为了指向一个函数,函数的指针类型必须是正确的

void (*p)(int,int);//这样p就不能指向函数Add,从而产生编译错误
#include <stdio.h>
void PrintHello(char *name){
    printf("Hello %s\n",name);
} 
int main(){
    
    void (*ptr)(char*);
    ptr = PrintHello;
    ptr("Tom");//双引号也是一种指针,是指针常量,指向常量区的字符串,值等于字符串的地址
}