中国大学MOOC-C语言第九周指针(上)
本文为个人总结,难免出现错误,恳请批评指正。
PS:编译环境:Dev-C++ 编译器:gcc
9.1-1取地址运算:&运算符取得变量的地址
一、 &取址操作的时候操作数必须是变量;&不能对没有地址的东西取地址。C语言的变量放在内存中。
&可以取出一个变量的地址,这个地址的大小、数据类型和 int是否相同取决于编译器,取决于计算机架构(32位 or 64位)。
二、&不能取的地址:没有地址的东西取地址,人话就是&右边必须是变量
报错代码一:8字节指针强行转换为int4字节,编译过不了
#include<stdio.h>int main()
{int i=0;int p;p = (int)&i;printf("0x%x\n", p);return 0;
}
报错代码二:原因语法问题
#include<stdio.h>int main()
{int i=0;int p;
// p = (int)&i;p = (int)&(i++);p = (int)&(i+p);printf("0x%x\n", p);return 0;
}
PS:本地变量i,p分配在内存堆栈,自顶向下分配内存,先定义的变量地址高,后定义的变量地址低。(注意计算机是多少位架构)
接下来我们来看数组的地址,数组单元的地址,相邻的数组单元的地址.
由上图容易看出:对于同一个数组的地址打印,&a==a==&a[0].
9.1-2指针:指针变量就是记录地址的变量
一、重新认识scanf
scanf函数中一定有一个方法可以接收变量地址。
指针就是保存地址的变量。
#include<stdio.h>
int main()
{
// 指针就是保存地址的变量int i;int* p= &i;int* p,q;int *p,q; return 0;}
上图中下面两行里面只有 p 是指针变量,q只是普通的int整型变量,在C语言中没有int *这种类型,注意区分,在自己写代码的时候也要注意。
指针变量的值是内存的地址,普通变量的值是实际的值,指针变量的值是具体实际值的变量的地址。(有点绕口哈哈哈,但是概念确实是这样的)
二、作为参数的指针
由上图可知可以利用函数传递地址。
在函数中我们讲参数的转移是值的传递,但是现在传进来的是地址,所以通过地址在函数内部可以访问到i这个本地变量,可以修改 i 这个本地变量,示例代码如下:
#include<stdio.h>
void f(int *p);
int main()
{int i=6;printf("&i=%p\n",&i);f(&i);
// g(i);printf("i=%d",i);return 0;
}
void f(int *p)
{printf("p=%p\n",p);printf("*p=%d\n",*p);*p=26;
}
作为参数的指针可以访问到对应内存地址中的变量;指针的运算符&*,涉及到指针的时候从右往左看只看字符。举例如下:
互相反作用:*&yptr -> *(&yptr) -> *(yptr的地址) -> 得到那个地址上的变量 ->yptr
&*yptr -> &(*yptr) ->&y -> 得到y的地址即yptr的地址 ->yptr
注意左值是什么意思:是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果,比如a[0]=2;*p=3. 是特殊的值所以叫左值
9.1-3指针的使用:指针有什么用呢
一、指针第一个应用场景:作为函数中的参数交换数值
#include<stdio.h>
void swap(int *pa,int *pb);
int main()
{int a=5;int b=6;swap(&a,&b);printf("%d %d",a,b);return 0;
}
void swap(int *pa,int *pb)
{int t=*pa;*pa=*pb;*pb=t;
}
二、指针第二个应用场景:函数返回多个值,某些值需要通过指针返回,传入的参数实际是需要保存带回的变量;(代码太长我懒得敲了,截的图凑合看吧)
指针应用场景2b:函数返回运算的状态,结果(实际的值)通过指针返回。常用套路是让函数返回特殊的不属于有效范围内的值来表示出错:
-1或0(文件操作的时候会看到大量的例子)
但是当任何数值都是有效的可能结果时候,就得分开返回了,后续语言(C++,Java)采用异常机制来解决这个问题。
三、指针最常见的错误:定义了指针变量直接用:翻译过来就是实际内存中还没有这个变量的位置,编译是一定过不了的。
任何一个指针变量没有被赋值之前,没有得到任何一个实际变量的地址之前,不能通过它访问其他变量。
9.1-4指针与数组:为什么数组传进函数后的sizeof就不对了
数组变量是特殊的指针,在参数表中出现,以下四种函数原型是等价的:
int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);
函数参数表里的数组实际上是指针(sizeof(a) == sizeof (int*)),下面两个等价函数
void minmax(int a[], int len, int *max, int *min)
void minmax(int *a, int len, int *max, int *min)
[] 运算符可以对数组做,也可以对指针做;
*运算符可以对指针做,也可以对数组做
数组变量是const的指针,所以不能被赋值。
int a[] <==> int * const a=......
9.1-5指针与const:指针:指针本身和所指的变量都可能const
一、指针与const
指针是const:表示一旦得到了某个变量的地址,不能再指向其他变量。
举例:int* const q=&i; //q是const,q只能指向i了,不能指向别人了
*q=26; // 可以写
q++;//ERROR!
指针所指是const:表示不能通过这个指针去修改那个变量(并不能使那个变量成为const)
const int* p=&i;
*p=26; //ERROR! 原因是(*p)是const类型
i=26;//OK
q=&j;//OK
下面这几种写法的含义:
int i;
const int* p1 = &i; 变量p1是const,不能被修改
int const* p2=&i; 变量p2是const,不能被修改
int *const p3=&i; 指针是const,指针不能被修改
判断哪个被const了的标志是const在前面还是后面
二、转换
三、const数组
数组实质上已经是const了:int a[] <==> int * const a=......