一.变量的内存址
C程序中变量的值都是储存在计算机内存特定的储存单元中,具有唯一的地址,这时候可以通过取地址符“&”来获得变量的地址。
int a = 10;
printf("%p", &a)
提示:这里使用了%p格式符---输出地址,这里的地址是用一个十六进制的无符号整数表示的。
上述生成的一串就是该变量的地址。
二.指针变量的初始化
存放变量地址需要一种特殊的变量--指针变量
指针变量的定义:类型关键字 *指针变量名;
注意:指针变量一定要进行初始化,避免出现野指针,如果没有初始化的对应变量一般采用NULL对其进行初始化
指针也有类型,指针的类型就是定义时的类型加*;
int a = 10;
int* p = &a;//将变量a的地址传给指针变量p
printf("%d", *p);//此处的*号是解引用
非定义时在指针变量前使用“*”号的意思是解引用(调取该地址中的数据)
提示:指针变量存放的是变量的地址,两者在数值上相等,但变量的地址是一个常量不能够对其进行赋值操作,而变量的指针是一个变量,它的值可以被改变;
int a = 10;
int* p = &a;//将变量a的地址传给指针变量p
*p = 1;//赋值操作;
printf("%d", *p);//此处的*号是解引用
此时运行结果是赋值之后的结果就是1;
注意:指针变量只能指向同一基类型的变量(例:int---int *)
使用指针必须恪守的如下三条准则
1.永远清楚每个指针指向了哪里,指针必须指向一块有意义的内存;
2.永远清楚每个指针指向的对象的内容是什么;
3.永远不要使用未初始化的变量
提示:指针的作用之一是可以在函数中改变实参的值
需要从函数返回多个值是使用指针
三.函数指针及其应用
函数指针就是指向函数的指针--存储函数的入口地址(不带()的函数名)
定义格式:函数返回值类型 (* 指针变量名) (函数参数列表);
提示:这个参数列表中只需要写函数的参数类型即可
下面举一个例子来说明函数指针的使用方法;
上台阶递归问题:一次只能上1节或者2节台阶,台阶的总数为n,求有多少种上法
#include <stdio.h>
int solution(int m) {
int result;
if (m == 0)
return result = 0;
if (m == 1)
return result = 1;
if (m == 2)
return result = 2;
else
{
return result = solution(m - 1) + solution(m - 2);
}
}
int main() {
int m;
scanf_s("%d", &m);
m = m % 50;
int(*p)(int);//定义一个函数指针
p = solution;//让此指针指向该函数
int result = (*p)(m);
printf("%d", result);
return 0;
}
四.指针和一维数组的关系
C语言中的数组名有着特殊的含义---存放数组元素的首地址
即数组名本身就是数组的首地址
数组中某一元素的地址表示方法:&a[10]=a+10;
引用数组中某一个元素的方法:a[10]=*(a+10);
int a[2] = { 1 };
int* p = a;
printf("%d\n", a[1]);
printf("%d\n", *(a + 1));//调取数组中的第二个元素
注意a+1==a++;这里不是进行赋值的操作而是将指针变量向后移动了一个1*sizeof(基类型)个字节,指向了下一个元素
一维数组当做实参传给函数
#include <stdio.h>
void arr(int *num, int n)
{
num++;
*num = 1;
}
int main(void)
{
int a[2] = { 1 };
int* p = a;
printf("%d\n", a[1]);
arr(a, 2);
printf("%d\n", *(a + 1));//调取数组中的第二个元素
}
形参声明为指针变量是也可以使用访问下标的方式访问数组
使用指针进行数组的遍历
#include<stdio.h>
int sum_array( int a[], int n)
{
int *j, sum;
sum = 0;
for (j = a; j <=a+n-1;)
sum += *j++;
return sum;
//使用指针进行数组的遍历
}
int main(void)
{
int a[5] = { 1,2,3,4,5 };
int sun = sum_array(a, 5);
printf("%d", sun);
}
五.指针和二维数组
int num[10][10] = { {1,2,3},{4,5,6} };
printf("%d", *(*(num+1) + 1));
//a[x][y]=*(a[x]+y)=*(*(a+x)+y)=(*(a+x))[y]
//4种访问数组内数据的方法
a[x][y]=*(a[x]+y)=*(*(a+x)+y)=(*(a+x))[y]
4种访问数组内数据的方法
1.将二维数组当做实参传给形参
#include<stdio.h>
//二维数组做参数向形参传递
void num(int e_num[][5])
{
for (int x = 0; x <= 1; x++)
{
for (int y = 0; y <= 4; y++)
printf("%d\t", *(*(e_num + x) + y));
}
}
int main(void)
{
int arr[2][5] = { {1,2,3,4,5},{6,7,8,9,10} };
num(arr);
return 0;
}
提示:除了用二维数组做函数形参外还可以用二维数组的行指针做函数形参,主函数不变
void num(int (*p)[5])
还可以向函数传递二维数组第0行第0列的首地址
#include<stdio.h>
//二维数组做参数向形参传递
void num(int *p,int n,int m)
{for (int x=0;x<n;x++)
for (int y = 0; y < m; y++)
{ //当将二维数组看成一维数组是可以使用下标偏移量来访问数组中的数据
printf("%d\t", p[x*m+y]);
}
}
int main(void)
{
int arr[2][5] = { {1,2,3,4,5},{6,7,8,9,10} };
num(*arr,2,5);
return 0;
}
提示://当将二维数组看成一维数组是可以使用下标偏移量来访问数组中的数据
int num[2][3];
例如:可以将num[1][0]在函数中使用p[3]来进行访问
六.指针数组用于储存多个字符串
可以用一个二维数组存放多个字符串
定义方法:char 数组名[个数][最长字符串的长度]