指针和数组
数组的指针
1、一个变量有一个地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,
它们都有相应的地址。所谓数组的指针是指数组的起始地址。
2、数组名表示数组的首地址,因此数组名也是一种指针
3、通过数组名访问数组中元素
int ch[] = {1,2,3,4};
假如我们想访问ch中的第3个元素:ch[3] == 4
我们也可以通过指针法引用数组中的元素:比如 *(ch + 3)
那么,如果想访问第n个元素呢?
*(ch + n) 注意:n<=sizeof(ch)/sizeof(ch[0])-1
练习:假如有数组int a[4], 编写代码实现如下功能:
1、通过从键盘上输入数字对数组a的每一个元素进行赋值
2、打印出数组a中每一个元素的地址
3、通过指针法将数组a中的每一个元素的值打印出来
int a[4];
int i;
for (i = 0; i < 4; i++)
scanf(“%d”, &a[i]);
for (i = 0; i < 4; i++)
{
printf(“%p %d\n”, &a[i], *(a+i));
}
5、通过指针变量间接访问数组
int a[4] = {1,2,3,4};
int *p;
p = a;
*(p + 2) = 100;
char ch[] = {'a', 'b', 'c'};
char *p2;
p2 = ch;
*(p2+1) = 'A';
int ch[] = {1, 2, 3, 4};
printf("%d\n", ch[4]);
printf("%p %p\n", &ch[3], &ch[4]);
//数组名:数组的首地址
printf("ch: %p\n", ch);
//数组中的第0个元素的地址:数组的首地址
printf("&ch[0]: %p\n", &ch[0]);
printf("%d %d\n", ch[3], *(ch+3));
int a[4];
int i;
for (i = 0; i < 4; i++)
{
scanf("%d", &a[i]); //a+i
getchar();
}
//打印数组中每个元素的地址
for (i = 0; i < 4; i++)
printf("%p\n", &a[i]);
//通过指针法将数组a中的每一个元素的值打印出来
for (i = 0; i < 4; i++)
printf("%d\n", *(a+i));
int *p;
p = a; //指针p指向了数组a
//指针指向了一个数组,可以将指针当数组看待
for (i = 0; i < 4; i++)
printf("%d\n", p[i]); //通过下标发访问数组中的元素
// printf("%d\n", *(p+i));
6、数组指针越界
int b[4] = {10, 20, 30, 40};
int a[4];
a[4] = 100;
printf("a[4]: %d\n", a[4]);
printf("b[0]: %d\n", b[0]);
printf("a: %u, b: %u\n", &a, &b); //打印数组a和b的首地址
指针数组
1、指针数组顾名思义就是:存放指针的数组,本质是数组,数组中的每个元素都是指针
#include <stdio.h>
int main()
{
int a = 10, b = 20, c = 30;
int *p[3];
p[0] = &a;
p[1] = &b;
p[2] = &c;
return 0;
}
2、注意:int *p[3]; 等价于 (int *) p[3]; 因为[] 比 *的优先级要高先与p匹配。
3、思考:如何通过一个数组存储10个人的姓名?
char *name[10] = {"zhangsan", "lisi", "wangwu", "zhaoliu, "tianqi"};
name数组中保存了10个字符串常量的首地址(注意:没有保存字符串常量而是常量的首地址)
指针变量的地址
1、我们在定义一个指针变量的时候,编译器会分配一块空间来存储这个指针变量的值,分配的这块
内存空间肯定有一个地址编码啦,那么这个地址编码肯定就是这个指针变量的地址啦
#include <stdio.h>
int main()
{
int a = 10;
int *p;
p = &a;
//将指针变量p的值以及变量a的地址打印出来(结果应该是两者相等)
printf("p: %p, &a: %p\n", p, &a);
//打印指针变量p的地址(存储指针变量p的内存空间的首地址)
printf("&p: %p\n", &p);
return 0;
}
2、强调:指针变量p的值保存的是另外一个变量a的地址0x300800,指针变量的地址是存储p这个指针变量的值的那块内存空间的首地址:0x3007F8,这块空间中保存的值是0x300800
一级指针作为函数的形参
1、函数的形参为数组
如果函数的形参是数组,该形参的定义方法如下:
void func(int a[], int n)
{}
我们也可以将形参定义为指针类型:
void func(int *a, int n)
{}
在实际工作中我们通常使用第二种方法!
2、调用函数时需要传递字符串可将形参设计为char *类型
void func(char *p) //调用函数时将字符串的地址赋值给指针变量p
{
printf("%c\n", p[0]);
}
int main()
{
func("hello");
return 0;
}
3、当形参为数组时,如果获取数组的长度呢?
为什么sizeof(a)和sizeof(b)的值都是8呢?
原因:编译器在编译的时候将a和b当做了指针来处理了!!!
4、注意:如果函数的形参为指针,在函数体中一般先对指针的值进行判断,判断指针的值是否为NULL
二级指针
1、用一个指针变量保存一个一级指针变量的地址,这个指针我们称之为二级指针
2、二级指针的定义
数据类型变量名;
int a = 10;
int *p = &a; //p为一级指针,保存变量a的地址
int **pp = &p; //pp为二级指针 保存一级指针p的地址
3、二级指针的应用
//二级指针的使用
int a = 10;
int *p = &a;
int **p2 = &p; //二级指针p2保存了一级指针p的地址(p2指向了p )
int ***p3 = &p2; //三级指针
//*p2 == p == &a
printf("%p %p %p\n", *p2, p, &a);
//**p2 == *p == *(&a) == a
printf("%d %d %d %d\n", **p2, *p, *(&a), a);
**p2 = 100;
printf("%d %d %d %d\n", **p2, *p, *(&a), a);
//*p3 == p2 = &p
//**p3 == *p2 == p == &a
//***p3 == **p2 == *p == *(&a) == a
printf("***p3: %d\n", ***p3);
评论区