今天来探讨一下关于指针的一些知识
1、指针
#include <stdio.h>
#if 0
1、指针变量的定义
数据类型* 变量名;
注意事项:
1、在定义指定变量时,*起到标志性的作用, 除此情况以外,所有指针变量前面加*,表示指针指向的内存
2、*指针变量: 可以作左值也可以作右值
3、*指针变量: 本质就是解引用,访问从保存的地址开始,n个连续的内存
4、指针变量要与保存的地址类型匹配, 否则保存地址一点问题都没有,但是通过指针访问数据存在问题
5、不要出现野指针, 如果指针不知道指向哪里,可以指向NULL
6、所有指针变量的大小是一样的, 32位: 4字节 64位:8字节
gdb调试常用指令:
(1)编译 : gcc xx.c -o xx -g
(2)执行: gdb ./xx
(3)gdb内部指令:
r : 运行
b 行号/函数名: 打断点
n : 单步调试
p 变量名: 打印变量数据
q : 退出gdb
l : 查看代码
#endif
int main01()
{
int a = 10;
int* p = &a;
//int b = *p;
*p = 200;
printf("a: %d, *p= %d\n", a, *p);
printf("&a: %p, p=%p\n", &a, p);
printf("&p: %p\n", &p);
return 0;
}
int main02()
{
char a = '1';
char* p;
p = &a;
printf("a: %c, *p= %c\n", a, *p);
printf("&a:%p, p=%p\n", &a, p);
printf("&p: %p\n", &p);
return 0;
}
int main03()
{
printf("sizeof(int*) = %ld\n", sizeof(int*));
printf("sizeof(double*) = %ld\n", sizeof(double*));
printf("sizeof(char*) = %ld\n", sizeof(char*));
printf("sizeof(long*) = %ld\n", sizeof(long*));
return 0;
}
int main04()
{
int a = 0x11223344;
//char *p = &a;
int *p = &a;
printf("&a:%p, p:%p\n", &a, p);
printf("a: %#x, *p=%#x\n", a, *p);
return 0;
}
int main()
{
int a;
int *p = NULL;
*p = 89;
return 0;
}
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;
}
int main()
{
int a[5] = {1,2,3,4,5};
int *p = &a[3];
printf("p[0] = %d\n", p[0]);
return 0;
}
3、二级指针
#include <stdio.h>
#if 0
数据类型* 变量名;
一级指针变量保存普通变量的地址
二级指针变量保存一级指针变量的地址
#endif
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;
}
4、数组指针
#include <stdio.h>
#if 0
数组指针: 本质是一个指针变量,保存数组的起始地址
数组指针语法:
每个元素的类型(*p)[元素个数]
int (*p)[8] : 表示p是一个指针变量,保存有8个元素,每个元素是整型的数组的起始地址
#endif
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;
}
5、指针操作二维数组
#include <stdio.h>
#if 0
p: 是一个数组指针,保存二维数组第一行的起始地址
p+i : 第i+1行的起始地址
*(p+i) :每一行第一个元素的起始地址
*(p+i)+j :每一行每一个元素的起始地址
*(*(p+i)+j) :每一行的每一个元素
#endif
int main01()
{
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;
}
int main()
{
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,0,11,12}
};
int (*p)[3][4] = &a;
return 0;
}
6、指针数组
#include <stdio.h>
#if 0
指针数组: 本质就是一个数组,每一个元素都是指针类型的!!!
#endif
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;
}