指针就是地址
1 变量与地址
int i = 1;//变量i是存放值1当下地址的房间名,地址则是该房间的经纬度或门牌号,房间名可变但地址不可变
2 指针与指针变量
int i = 1; int *p = &i;//指针就是值1所在的地址,指针变量就是存放指针所在地址的房间名
3 直接访问与间接访问
int i = 1; int *p = &i; printf("i = %d\n",i);//通过变量名直接访问叫做直接访问 printf("i = %d\n",*p);//通过指针取值访问叫做间接访问
4 空指针与野指针
int *p = NULL;//空指针,把指针初始化为空指针是为了防止野指针 野指针:指的是该指针指向的地址是不确定的
5 空类型
void *p = NULL;//空类型属于百搭类型的指针,它能与诸如int、char等类进行匹配,在值传递是不知道对方类型时可以使用空类型
6 定义与初始化的书写规则
int i = 1; int *p = &i;//一级指针 int **q = &p;//二级指针
7 指针运算
* 取值 & 取地址 关系运算 ++ --
8 指针与数组
指针与一维数组
int a[i] = {1,2,3};
值:a[i] = *(a+i) = *(p+i) = p[i]
地址:&a[i] = a+i = p+i =&p[i]
注意:
数组a[i]中的a为常量,不能用来做算数运算,而p是变量可以用来运算,a++(×),p++(√)
注意p++与p+1的区别,p++ -> p= p+1(改变了指针的指向),p+1没有左值并没有改变p的值
练习:
int main()
{
int a[] = {2,4,6,8,10};
int y;
int *p = &a[1];//p的值为a[1]的地址;
y = (*--p)++;//y = a[0]++;
printf("y = %d\n",y); //y = a[0]; 即y = 2;
printf("a[0] = %d\n",a[0]);//a[0] = a[0]+1; a[0] = 3;
}
指针与二维数组
定义与初始化:
int a[2][3];
int *p;
错误定义:p = a;//因为a是一个行地址量,加一或者减一是以行为单位增减的,而p是列地址的指针,强调逐个元素的增减
正确定义:p = &a[0][0]; // p = *(a+0) = *a;
指针与二维数组的输出:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[2][3] = {1,2,3,4,5,6};
int i;
int *p;
p = &a[0][0];
for(i = 0; i < 6 ; i++)
printf("%d\t",p[i]);
printf("\n");
}
指针与字符数组
字符数组:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "hello";//定义一个数组并初始化
printf("%d\t%d\n",sizeof(str),strlen(str));//打印数组所占的字节数及其有限字符数目
//结果为 6 5
strcpy(str,"world");//用字符串world覆盖hello
puts(str);
exit(0);
}
字符指针:
int main()
{
char *str = "hello";//定义一个字符指针并初始化
printf("%d\t%d\n",sizeof(str),strlen(str));//打印字符指针所占的字节数及其有限字符数目
//结果为 8 5
str = "world";//用字符串world覆盖hello
puts(str);
exit(0);
}
结果是,字符数组的大小是不固定的,而字符指针是固定大小的,使用字符指针时要注意内存大小的问题,以及注意字符串覆盖的不同方式
9 const 与指针
const int a; int const a;//定义一个int型常量 const int *p;//常量指针,指针的指向可以发生改变,但是指针所指向的值不能发生改变 int const *p;//这两个都为常量指针,没有啥区别 int *const p;//指针常量,指针的指向不能发生变化,但是指针指向的值不能发生变化 const int *const p;//指针的指向与指针所指向的值都不能发生改变
常量指针:
常量指针,指针的指向可以发生改变,但是指针指向的值不能改变
记忆方法:先看到const再看到*号,就读常量指针,const限制 *p 所指向的值,即值不能变但是指针的指向可以改变
int const *p;
const int *p;
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1;//定义一个变量
const int *p = &i;//将i的地址赋给一个int类型的常量指针
//(F) *p = 2; //因为*p是常量指针,所以不能通过指针来改变i的值
i = 2;//可以通过变量名赋值来改变i的值
printf("%d",i);
}
指针常量:
指针常量,指针的指向不可以发生改变,但是指针指向的值可以改变
记忆方法:先看到 * 再看到const,就读指针常量,const限制 p 所指向的地址,即指向不能变但是指针指向的值可以改变
const用法之一:定义一个常量
#define PI 3.14 //定义一个常量,3.14为PI,缺点define是在预处理与编译阶段就会被处理,所以不会检查语法是否错误
如define PI abcdef 因为错误输入,并不想如此定义但因为该语句不检查语法就会发现不了错误
const float pi = 3.14;//定义一个float类型的常量,可以检查语法,防止错
const注意问题之二:小心被const限制的值被修改
#include <stdio.h>
#include <stdlib.h>
int main()
{
const float pi = 3.14;//定义一个float型常量
float *p = π//定义一个指向pi的float型指针
*p = 3.14159;//修改指针p所指向的值,将3.14改为3.14159
printf("pi = %f\n",*p);//打印
exit(0);
}
结果就是将一个被const限制的值给修改了
解决方法:
将定义的float类型的指针被const限制,即const常量对应常量指针
const float pi = 3.14;
const float *p = π
10 指针数组与数组指针
数组指针:【存储类型】 数据类型 ( * 指针名)【下标】 = 值 如:int (*p)[3]; ->type name -> (int[3]) *p
数组指针与二维数组的关系:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[2][3] = {1,2,3,4,5,6};//定义一个二维数组
int (*q)[3] = a;//定义一个数组指针*q指向数组a,a为行地址的起始地址,因为*q是一个行指针
int i,j;
printf("%p\t%p\n",a,a+1);//打印a与a+1的地址
printf("%p\t%p\n\n",q,q+1);//打印数组指针q与q+1的地址
//数组指针q的地址是以行为单位变化的,q+1递增了三个int型数据,与a+1递增三个int型数据一样
for(i = 0; i < 2 ; i++)
{
for(j = 0; j < 3; j++)
{
printf("%p->%d\n",*(q+i)+j,*(*(q+i)+j));//打印数组指针的值与地址
}
printf("\n");
}
exit(0);
}
总结:数组指针是针对二维数组的,减少了内存的浪费
指针数组: 【存储类型】 数据类型 * 数组名 【长度】
如:int *arr[3]; - >TYPE NAME ; ->int *[3] arr;
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
char *str[5] = {"Fellow me","Basic","Great","Fortran","Computer"};
for(i = 0 ; i < 5 ; i++)
{
puts(str[i]);
}
exit(0);
}
总结:指针数组主要是处理多个字符串,将字符串定义为指针类型的字符串,方便处理以及节省内存
11 多级指针
多理解一级与二级指针即可
指针大小:
#include <stdio.h>
#define STRSIZE 128
int main()
{
int i = 1;
int *p;
float *f;
double *d;
char *c;
//打印指针所占地址的大小
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(f));
printf("%d\n",sizeof(d));
printf("%d\n",sizeof(c));
}
从下图结果中可以看出,指针所占的地址空间是一样的,在不同的计算机系统中会有不同的大小,但要注意的是相应类型的指针要与相应类型的值对应,例如,char i = 1 要与 char *c 对应,因为指针在运算时隔多少个字节读出来的数不一样,不然会出错