封装一个函数怎么样返回多个值?
1.用数组,例 int a = 2,b = 3; 返回a +b与 a * b;
int* calculate(int a, int b) {
int add = a + b;
int mul = a * b;
int arr[] = { add,mul }; //假设arr地址为0x111,存放数据5,6
return arr;//地址在这个函数,在这个花括号内是存在的,出了这个花括号,地址还会存在,只不过值不一定了
}
int main() {
int a = 10, b = 20;
int *arr = calculate(a, b);
printf("%d,%d\n", arr[0], arr[1]);
return 0;
}
这个方法有缺陷, 在主函数中,变量a,b的地址是定值,一直到程序结束,它们的地址值都不会发生变化。但在封装函数calculate中,一旦封装函数调用完毕,所有局部变量均被回收,系统会重新划分内存,arr地址0x111可能找不到,也可能存放了其它的数据。在这个程序中,因为只有a,b两个变量且地址已经固定。如果,还有其它变量,那么0x111地址可能会被占用,那么add与mul的值会被覆盖掉。
这种方法有随机性,代码有时候结果正确,有时候不一定。
所以,返回值类型不能是局部变量或临时变量的地址
2.参考scanf 函数的原理,scanf 函数用的时候,先定义一个变量 int num; scanf("%d",&num);
scanf 函数把从键盘上输入的值从scanf的作用域带出来了,并且赋值给了num。参考scanf函数的形式参数&num, 可以得知,从键盘上获取的值连同定义的变量的地址,一起传到scanf函数里面,在内部通过指针的解引用,将键盘上获取的值带出来并且赋值给num
所以,在主函数中定义a,b两个变量同时将它们的地址传到封装函数里,在封装的函数内部进行解引用,通过形参来改变实参。
void calculate(int num1,int num2,int* a, int* b) {
*a = num1 + num2;
*b = num1 * num2;
}
int main() {
int a = 10, b = 20;
calculate(a,b,&a, &b);
printf("%d %d\n", a, b);
return 0;
}
一维数组与指针之间的关系
数组名代表数组首元素的起始地址,数组的访问有两种方式1.通过下标访问arr[index]2.通过指针解引用来访问,*(arr +index)。arr[index] = *(arr + index)
arr + 1 ,数组首元素的地址向后平移一个单元格,单元格的大小与数组类型有关。
指针与const的结合
1.const 放在*前
const int *q = &value; 等价与 int const*q = &value;这是因为 const 对于基类型int而言,基类型相当于透明的。const在*前,修饰的是*q,也就是说q所指向的变量的值被锁定,可以访问,不能通过*p解引用被修改,但q(指针变量)可以改变,他可以等于&value,也可以等于&p.
2.const 放在*后
int * const q = &a; 这个与上面的区别是, 这个const 锁定的是q指针变量, q 不能改变,它指向a地址,就永远只能指向a地址, 不能等于其它的值,但可以通过解引用改变它所指向的变量的值。
如果碰到不让修改的数据,(const int a = 10; const int *p = &a;) ,我们可以 定义一个const int*p 类型的指针。
指针与字符串
char ch[] = {"hello"}; 字符数组,其中的元素值可以改,char[0] = 'a';
而char*p = "hello"; ,这中定义方式下的字符串以字符串常量的形式存在,字符串中的单个元素不允许被修改,*(p+1}='a'不成立,字符串常量就是常量。char *p 定义与字符串定义相矛盾,不要让*p修改p所指向的常量的值,与const 结合,锁住*p, const char*p = "hello"; 这种才是语法层面上的定义,指针指向字符串 const char * p = "hello";
涉及到函数调用,局部变量在栈区.stack区,而字符串常量,常量,全局变量在数据区.data区存在,
数组指针与指针数组
指针数组,落脚点是数组 char *arr[] = {……};数组内部存储的都是char*类型的元素;而字符串是char*类型元素的一种,所以 const char* arr[] = {"hello","world'};
字符数组,用char类型定义,字符串数组用char*类型来定义,但字符串就是常量,所以定义字符串数组时,需要在*前加const; 常量没有办法通过解引用来改变值,
数组指针,落脚点在指针,指向整个数组大小的指针变量
可以看出,数组指针加一,加的是 整个数组的字节数,怎么定义数组指针?
int (*p)[num] = &arr; 解释:1.*的优先级高于[], 2.num为几,就代表指向有几个元素的数组数组指针,指向数组的指针 int(*p)[] = &arr,[]的优先级高于定义指针时的*, 这里,我们把指针,指针加1,数组名,数组首元素的地址,还有数组的地址都打印出来,会发现数组指针加1,加的是整个数组所占的字节数,而且,数组指针指向的地址与数组首元素的地址,数组的地址一模一样。&arr[0] == &arr ==arr ,区别是,定义数组指针时,如果你在数组名前加了取地址符&,那么这个指针,加的就是整个数组的字节数。
typedef 用法:1.在自定义的头文件中进行函数声明时,可以对函数的类型进行重命名
typedef int ElemType; 将函数类型int 换一个新名字ElemType;
如果后面你不想用int 类型,想换double类型,只需要将第二行代码中的int 换为double 即可,类型重命名可以方便后面数据类型的切换。
头文件中进行函数声明,要实现函数功能,需要重新添加一个源文件(.cpp)文件,然后在源文件中实现功能。
在源文件中,我们需要引入自己写的头文件,在此说一下,#include<stdio.h> 与#include“stdio.h"
中<>与“”的区别,尖括号的意思是,在系统配置的路径下可以找到头文件,而双引号的作用是,系统在先在自己的项目中查找自己写的头文件,没有找到,然后会在系统路径下查找头文件。
输入缓冲区,从键盘上获取的所有值全部放到内存当中的一个地方,scanf 从输入缓冲区读取,
输入缓冲区有两个指针,一个头指针,一个尾指针,交替穿插进行, scanf("%d %d %d",&a,&b,&c);
通过指针偏移读取数据,直到读完。两个指针的走法
#define MAX 11 MAX 被替换为了11
typedef与#define 的作用不同,#define只是简单的宏替换,而typedef是类型的重命名
我们会发现,看到pointer就用int* 替换,结果定义出来的m,n,一个是指针,一个是整数,类型不匹配,所以报错。
而typedef是对指针类型进行重命名,重命名后会发现,它定义多个变量时,就与简单的宏替换不一样。
对数组指针的重命名
int(*pointer)[3];?//声明了一个数组指针,它的名字是pointer,指向的是一个含有3个元素的数组
第一步,先进行一次数组指针的声明,2. 前面直接加typedef,
函数指针,指针指向函数时,不需要加取地址符