运算符 &

  • scanf(“%d”,&i);里的&
  • 获得变量的地址,它的操作数必须是变量

    • int i; printf(“%x”,&i);
  • 地址的大小是否与int相同取决于编译器 |

    • inti; printf(“%p”,&i);

scanf

  • 如果能够将取得的变量的地址传递给一个函数, 能否通过这个地址在那个函数内访问这个变量?

    • scanf(“%d”,&i);
  • scanf()的原型应该是怎样的?我们需要一个参数 能保存别的变量的地址,如何表达能够保存地址 的变量?

指针

  • 就是保存地址的变量

int i;

int*p=&i;

int*p,q;

int*p,q;

指针变量

  • 变量的值是内存的地址

    • 普通变量的值是实际的值
    • 指针变量的值是具有实际值的变量的地址

作为参数的指针

  • void f(int *p);
  • 在被调用的时候得到了某个变量的地址:

    • int i=0;f(&i);
  • 在函数里面可以通过这个指针访问外面的这个i

访问那个地址上的变量

  • *是一个单目运算符,用来访问指针的值所表示的地 址上的变量
  • 可以做右值也可以做左值 。

    • int k= *p;
    • *p=k+1;

左值之所以叫左值

  • 是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果:

    • a[0]=2;
    • *p=3;
  • 是特殊的值,所以叫做左值

指针的应用场景

场景一

  • 交换两个变量的值
void swap(int *pa, int *pb){
int t=*pa; 
*pa=*pb; 
*pb=t; 
}

场景二

  • 函数返回多个值,某些值就只能通过指针返回 ·
  • 传入的参数实际上是需要保存带回的结果的变量

场景二B

  • 函数返回运算的状态,结果通过指针返回
  • 常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错:
  • -1或0(在文件操作会看到大量的例子)
  • 但是当任何数值都是有效的可能结果时,就得分开返回了
  • 后续的语言(C++,Java)采用了异常机制来解决这个问题

指针常见错误

  • 定义了指针变量,还没有指向任何变量,就开始使用指针

指针与数组

数组变量是特殊的指针

  • 数组变量本身表达地址,所以

    • int a[10];int*p=a;//无需用&取地址
    • 但是数组的单元表达的是变量,需要用&取地址
    • a==&a[0]
  • []运算符可以对数组做,也可以对指针做:
  • p[0]<==>a[0]
  • *运算符可以对指针做,也可以对数组做
  • *a=25;
  • 数组变量是const的指针,所以不能被赋值

    • int a[]< :==> int*const a

指针与const(只适用于C99)

指针是const

  • 表示一旦得到了某个变量的地址,不能再指向 其他变量 ·

    • int*constq=&i;//q是const
    • *q=26;1/ OK
    • q++; // ERROR

所指是const

  • 表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const) )

    • const int *p=&i;
    • p=26;//ERROR!(p)是const
    • i=26;//OK
    • P=&j;//OK

这些是啥意思?

int i; 
const int* p1 = &i; 
int const* p2= &i; 
int *const p3= &i;

判断哪个被const了的标志是const在*的前面还是后面。

转换

  • 总是可以把一个非const的值转换成const的
void f(const int*_x); 
int a=15; 
f(&a);// ok 
const'int b = a;
 f(&b);// ok 
b=a'+1;// Error!
  • 当要传递的参数的类型比地址大的时候,.这是常用的手 段:既能用比较少的字节数传递值给参数,又能避免函 数对外面的变量的修改

const数组

  • const int a[]={l,2,3,4,5,6,};
  • 数组变量已经是const的指针了,这里的const 表明数组的每个单元都是constint
  • 所以必须通过初始化进行赋值

保护数组值

  • 因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值
  • 为了保护数组不被函数破坏,可以设置参数为const
  • int sum(const int a[],int length);

指针运算

  • 给一个指针加I表示要让指针指向下一个变量
  • int a[10]; intp=a; (p+I)—> a[l]
  • 如果指针不是指向一片连续分配的空间, 如数组,则这种运算没有意义

*p++

  • 取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
  • *的优先级虽然高,但是没有++高
  • 常用于数组类的连续空间操作
  • 在某些CPU上,这可以直接被翻译成一条汇编指令

指针比较

  • <,<=,==,>,>=,!= 都可以对指针做
  • 比较它们在内存中的地址
  • 数组中的单元的地址肯定是线性递增的

0地址

  • 当然你的内存中有0地址,但是0地址通常是 个不能随便碰的地址
  • 所以你的指针不应该具有0值
  • 因此可以用0地址来表示特殊的事情:

    • 返回的指针是无效的
    • 指针没有被真正初始化(先初始化为0)
  • NULL是一个预定定义的符号,表示0地址

    • 有的编译器不愿意你用0来表示0地址

指针的类型

  • 无论指向什么类型,所有的指针的大小都 是一样的,因为都是地址
  • 但是指向不同类型的指针是不能直接互相 赋值的
  • 这是为了避免用错指针

指针的类型转换

  • void* 表示不知道指向什么东西的指针

    • 计算时与char相同(但不相通)
  • 指针也可以转换类型

    • int p=&i; voidq=(void*)p
  • 这并没有改变p所指的变量的类型,而是让 后人用不同的眼光通过p看它所指的变量

    • 我不再当你是int啦,我认为你就是个void!

用指针来做什么

  • 需要传入较大的数据时用作参数
  • 传入数组后对数组做操作函数返回不止一个结果

    • 需要用函数来修改不止一个变量
  • 动态申请的内存...

参考资料

程序设计入门——C语言\_浙江大学\_中国大学MOOC(慕课) (icourse163.org)

最后修改:2023 年 10 月 21 日
如果觉得我的文章对你有用,请随意赞赏