1、指针变量的定义
1.1 一级指针
数据类型* 变量名;
注意事项:
1、在定义指定变量时,*起到标志性的作用, 除此情况以外,所有指针变量前面加*,表示指针指向的内存
2、*指针变量: 可以作左值也可以作右值
3、*指针变量: 本质就是解引用,访问从保存的地址开始,n个连续的内存
4、指针变量要与保存的地址类型匹配, 否则保存地址一点问题都没有,但是通过指针访问数据存在问题
5、不要出现野指针, 如果指针不知道指向哪里,可以指向NULL
6、所有指针变量的大小是一样的, 32位:4字节 64位:8字节
练习:通过指针交换两个整型变量的
int main()
{
int x=1, y=2;
int *px = &x, *py = &y;
int temp;
temp = *px ;
*px = *py;
*py = temp;
printf("x=%d, y= %d\n", x, y);
return 0;
}
1.2 二级指针
数据类型** 变量名;
一级指针变量保存普通变量的地址
二级指针变量保存一级指针变量的地址
实例:
#include <stdio.h>
int main()
{
int a = 10;
int *p = &a;
int**q = &p;
printf("a:%d, *p=%d, **q=%d\n", a, *p, **q);
printf("&a: %p, p=%p, *q=%p\n", &a, p, *q);
printf("&p:%p, q=%p\n", &p, q);
printf("&q:%p\n", &q);
return 0;
}
2、数组
2.1 一维数组
(1)&a[0] &a[1] .... &a[i] ------》每个元素的起始地址
(2) a a+1 ..... a+i ------》每个元素的起始地址
(3) &a ----》表示数组的起始地址
&a+1 ----》偏移一个数组的大小
(4)数组名的含义: 表示数组首元素的起始地址,并且是一个常量,不能被改变的!!!!
2.2 指针操作一维数组
实例:
#include <stdio.h>
//1、指针自增的方式访问数组每一个元素, 指针的指向发生改变
int main01()
{
int a[5] = {1,2,3,4,5};
int *p = a; // a, &a[0]都表示数组首元素的起始地址!
while(p < a+5)
{
printf("%d ", *p);
p ++;
}
printf("\n");
return 0;
}
//2、通过指针加上一个整数的方式访问数组每一个元素, 指针的指向并没有发生改变
int main02()
{
int a[5] = {1, 2, 3, 4, 5};
int *p = &a[0];
for(int i=0; i<5; i++)//每个元素的起始地址
{
printf("p+%d = %p\n", i, p+i);
}
for(int i=0; i<5; i++)
{
printf("*(p+%d) = %d\n", i, *(p+i)); //表示每一个元素
}
return 0;
}
//3、指针和下标的组合访问数组每一个元素
int main03()
{
int a[5] = {1,2,3,4,5};
int *p = a;
// p[i] 等价于 *(p+i)
for(int i=0; i<5; i++)
{
printf("p[%d] = %d\n", i, p[i]);
}
return 0;
}
2.3 二维数组
int a[3][4];
(1)要将二维数组理解成数组的数组: a表示数组名, 3表示3个元素,而每个元素都是4个元素的整型数组!!
(2)a[0] a[1] a[2] ---->表示第1维数组的三个元素
&a[0] &a[1] &a[2] ----> 表示第1维数组每个元素的起始地址,或者理解成每一行的起始地址
a a+1 a+2 ----->表示第1维数组每个元素的起始地址
a[0] :对于第一数组数组来说是第一个元素,但又是一个一维数组, 并且a[0]可以理解为第一行一维数组的数组名!
a[0][0] a[0][1] a[0][2] a[0][3] ----->表示第一行的一维数组每一个元素
&a[0][0] &a[0][1] &a[0][2] &a[0][3] ------>表示第一行一维数组每一个元素的起始地址 a[0]
a[0]+1 a[0]+2 a[0]+3 --->表示第一行一维数组每一个元素的起始地址
2.4 指针操作二维数组
p:是一个数组指针,保存二维数组第一行的起始地址
p+i : 第i+1行的起始地址
*(p+i) :每一行第一个元素的起始地址
*(p+i)+j :每一行每一个元素的起始地址
*(*(p+i)+j) :每一行的每一个元素
实例:
#include <stdio.h>
int main()
{
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,0,11,12}
};
int (*p)[4] = a;
for(int i=0; i<3; i++) //每一行的起始地址
{
printf("p+%d=%p\n", i, p+i);
}
for(int i=0; i<3; i++) //每一行每一个元素的起始地址
{
for(int j=0; j<4; j++)
{
printf("*(p+%d)+%d = %p ", i, j, *(p+i)+j);
}
printf("\n");
}
for(int i=0; i<3; i++)//每一行的每一个元素
{
for(int j=0; j<4; j++)
{
printf("*(*(p+%d)+%d) = %d ", i, j, *(*(p+i)+j));
}
printf("\n");
}
return 0;
}
3、数组指针和指针数组
3.1 数组指针
数组指针: 本质是一个指针变量,保存数组的起始地址
数组指针语法:
每个元素的类型(*p)[元素个数]
如 int (*p)[8] : 表示p是一个指针变量,保存有8个元素,每个元素是整型的数组的起始地址
实例:
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int (*p)[5] = NULL;
p = &a;
// p:保存的是数组的起始起始地址
// p+1 : 偏移一个数组的大小
// *p : 表示数组首元素的起始地址
// *p +1 :表示数组的起始地址
printf("p = %p, p+1=%p\n", p, p+1);
for(int i=0; i<5; i++)
{
printf("*p+%d = %p\n", i, *p+i); //表示每个元素的起始地址
}
for(int i=0; i<5; i++)
{
printf("*(*p+%d)= %d\n", i, *(*p+i)); //表示每个元素的起始地址
}
return 0;
}
3.2 指针数组
指针数组:本质就是一个数组,每一个元素都是指针类型的!!!
实例:
#include <stdio.h>
int main()
{
int x=1, y=2, z=3, w=4, u=5;
int* a[5] = {&x, &y, &z, &w, &u};
for(int i=0; i<5; i++)
{
printf("a[%d] = %p\n", i, a[i]);
}
for(int i=0; i<5; i++)
{
printf("*(a[%d]) = %d\n", i, *(a[i]));
}
return 0;
}
4、综合训练题
(1)从键盘获取一行字符序列(通过循环的方式,一个字符一个字符的获取),通过指针将获取的字符序列反转。
#include <stdio.h>
int main()
{
char a[1024];
char temp;
int i = 0;
while(1)
{
temp = getchar();
if('\n' == temp)
{
break;
}
a[i] = temp;
i ++;
}
for(char *begin = &a[0], *end = &a[i-1]; begin<end; begin++, end--)
{
temp = *begin;
*begin = *end;
*end = temp;
}
for(int j=0; j<i; j++)
{
printf("%c", a[j]);
}
printf("\n");
return 0;
}
(2)从键盘获取一行字符序列, 判断是否是回文字符
abcba abba 类似这样的都是回文字符
#include <stdio.h>
int main()
{
char a[1024];
int i=0;
char temp;
//获取字符序列
while((temp=getchar())!='\n')
{
a[i] = temp;
i ++;//i 控制数组的下标, 同时表示字符的个数
}
char *begin=NULL, *end=NULL;
for(begin=&a[0], end=&a[i-1]; begin<end; begin++, end--)
{
if(*begin != *end)
{
break;
}
}
if(begin < end)
{
printf("不是回文序列\n");
}
else
{
printf("是回文序列...\n");
}
return 0;
}