C语言的灵魂---指针详解
目录
- 基于内存映像图认识指针
- 指针的定义及其指类
- 指针的基本运算及其他运算
- 使用指针时常见的错误
- 指向函数的指针
- 指针与数组、字符串及结构体
基于内存映像图认识指针
内存是由多个字节组成的一维、线性、连续的存储空间。内存中的众多字节由编号进行管理和定位。
int a = 12901 => 32 65H;如图所示:
该变量存放在以3A 2B 65 32为编号的字节处开始的空间中,占用4B空间.为了能表示这个int类型的数据在内存中的位置,需要记录这个数所占用的字节的编号信息。为了能够准确记录该数的位置信息,计算机将数据所占用的多个字节的第一个字节的字节编号保存在其他字节中。即,在以3A 2B 65 38为编号的字节处开始的空间中存放了变量a的首地址。
站在计算机角度:一个“*”代表:内存中某个字节的编号,将指向那个字节。但,从那个字节开始,到底多少个字节应该看成一个整体存储空间,仅凭一个“*”无法确定,所以还要增加一个信息:指类!
所以,指针二要素为:
1.首地址:数据在内存中所占用的众多字节中的第一个字节编号
2. 指类:指针所指向的空间的数据类型
指针的定义及其指类
1.指针的定义:
int *p;
p是int*类型的变量, p占用4B空间,且,p的值将被C语言当作字节编号来看待,其值指向内存中的某一段空间。
2.不同数据类型的指针在内存中都占用4B空间;(32位操作系统)
3.指类的识别:
type *x;指类为type;(一级指针)
type **x 指类为type *;(二级指针)
如: int **p; 指针p的指类为:int * ;说明:p所指向的空间数据类型为int *。
即,将最后一个“*”去掉,剩余的所有内容为指针的指类。
变量定义语句中的“*”仅仅是变量为指针类型的说明符,不是指向运算符!
指针的基本运算及其他运算
一、基本运算
1.&取地址运算符
int *p;
int a = 4;
p = &a;
把a的首地址赋值给p,即p的值为a的首地址,则p指向a,且p的指类为a的数据类型。
2.*指向运算符
在赋值语句中使用,
int *p,*q, i,j;
p = &i;//p指向i
q = &j;//q指向j
*p = 30; //把30赋值给p所指向的空间
*q = *p +15;//把p所指向的空间的值与15求和得到的结果赋值给所指向的空间
赋值语句中的*x读法:
**x: 在=的左边:x所指向的空间
x: 在=的右边:x所指向的空间的值
二、其他运算
指针相加:C语言拒绝两个指针的相加v,指针相加语法错误.
指针相减:指针-指针=int; 两个指针相减结果的绝对值:两个指针所指向的空间之间的指类元素个数,相减条件:
1.两个相间的指针,指类必须保持一致
2.内部过程是:fabs(p所指向的空间字节编号- q所指向的空间字节编号)/ sizeof(指类)
使用指针时常见的错误
1.函数调用中指针使用时的常见错误
(1) 形参的改变并不影响实参的值
经典案例一:通过调用函数,将两个变量的值互换;
错误代码:
#include <stdio.h>
void exchange(int one,int other);
void exchange(int one,int other) {
int t;
t = one;
one = other;
other = t;
}
int main() {
int n;
int m;
printf("Input the n and m:");
scanf("%d%d",&n,&m);
exchange(n,m);
printf("%d %d\n",n,m);
return 0;
}
输入: 3 4
输出: 3 4
正确代码:
#include <stdio.h>
void exchange(int *one,int *other);
void exchange(int *one,int *other) {