1、指针与指针变量
启动一个程序,系统在内存上给该程序分配一块内存空间。如果是32位系统,内存大小为4G。 内存空间是由一个个字节构成,每个字节系统会分配一个编号,称为地址。
回顾C语言基础: 整型变量:int a = 10; ,其中,a为整型变量,存储整数。 指针变量:int *p ,其中,p为指针类型。指针变量可理解为存指针(地址)的变量。在32位系统中,因为地址编号格式为:0x 0000 0000,所以指针变量占4个字节。指针的实质就是地址
- 指针变量的定义和初始化
int main()
{
int a = 10;
int *p;
p = &a;
system("pause");
return 0;
}
- 指针变量保存谁的地址就指向谁
*p = 100;
在使用时,对一个表达式取 *,就相当于对表达式减少一级 * ;如果对表达式取 & ,就相当于加一级 *
- 指针变量的大小
无论是哪种类型指针,其大小只和编译器有关。
int main()
{
char *p1;
short *p2;
int *p3;
int **p4;
printf("%d\n", sizeof(p1));
printf("%d\n", sizeof(p2));
printf("%d\n", sizeof(p3));
printf("%d\n", sizeof(p4));
system("pause");
return 0;
}
- 指针的宽度和步长
指针宽度(步长) = sizeof(指针类型) 例如:sizeof(int *); sizeof(int **)等…… 步长:指针加1跨过多少字节 char *p1 宽度:1字节 short *p2 宽度:2字节 int *p3 宽度:4字节 int **p3 宽度:4字节
int main()
{
int num = 0x01020304;
char *p1 = (char *)#
short *p2 = (short *)#
int *p3 = #
printf("%x\n", *p1);
printf("%x\n", *p2);
printf("%x\n", *p3);
printf("%p\n", p1);
printf("%p\n", p2);
printf("%p\n", p3);
printf("%p\n", p1 + 1);
printf("%p\n", p2 + 1);
printf("%p\n", p3 + 1);
system("pause");
return 0;
}
- 野指针
int main()
{
int *p;
*p = 2000;
printf("%d\n", *p);
int a = 10;
int *p = &a;
*p = 2000;
printf("%d\n", *p);
system("pause");
return 0;
}
- 空指针
空指针作用:如果使用完指针将指针赋值为NULL,在使用时判断指针是否为NULL,就可以知道其是否被用
int main()
{
int a;
int *p = NULL;
*p = 200;
printf("%d\n",*p);
system("pause");
return 0;
}
- 万能指针
注意:定义 void * 类型, 其类型是4字节(32位系统下),打印的时候,系统并不知道 void类型 取多少字节,因此打印会报错,而定义不会报错
int main()
{
int a = 10;
short b = 200;
void *p = (void *)&a;
void *q = (void *)&b;
printf("%d\n", *(int *)p);
system("pause");
return 0;
}
- const 关键字修饰
const 修饰变量 a ,意为不能通过a修改a内存中的值,但可以通过指针修改
int main()
{
const int a = 10;
int *p = &a;
*p = 100;
printf("%d\n", *p);
printf("a = %d\n", a);
system("pause");
return 0;
}
int main()
{
int a = 10;
const int *p = &a;
a = 100;
printf("%d\n", *p);
printf("a = %d\n", a);
int b = 20;
int * const p = &a;
*p = 123;
printf("%d\n", *p);
const int *const p = &a;
system("pause");
return 0;
}
- 多级指针
定义多级指针时,定义的指针类型只需要比想保存的的数据类型多一个 * 即可 “ int *p ” :代表这个p是一个指针变量,其中 p 为变量。 p的类型 :将p删除,剩下的类型 p保存谁的地址:将 * 和 p 一起删除,剩下的类型,就是其保存的类型。
int main()
{
int a = 10;
int *p = &a;
int **q = &p;
printf("%d\n", **q);
printf("%d\n", *p);
system("pause");
return 0;
}
- 通过指针操作数组
指针 + 1 :跨一个步长 要得到内存手中的内容,需要先拿到该内存的地址,再解引用取内容 : *(address)
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *p = a;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", *(p + i));
}
int b[10] = { 0 };
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
*(p + i) = i;
}
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
printf("%d ", *(p + i));
}
system("pause");
return 0;
}
- 指针的运算
两指针类型一致,相减得到中间跨过多少个元素; 两指针相加无意义
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *p = a;
printf("%d\n", *(p + 3));
int *q = (int *)(&a + 1) - 1;
printf("%d\n", q - p);
system("pause");
return 0;
}
- [ ]不是数组的专属
[ ] <==> *()
int main()
{
int a = 10;
int *p = &a;
*p = 100;
printf("%d\n", a);
int b[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *p = b;
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
printf("%d ", b[i]);
printf("%d ", *(p + i));
printf("%d ", p[i]);
printf("%d ", *(b + i));
}
system("pause");
return 0;
}
- 指针数组
整形数组:是一个数组,数组中每个元素都是一个整型变量 指针数组:是一个数组,数组中每个元素都是一个指针 注意:一定要注意指针的指向,及其存的值是代表什么!!!
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *num[3] = { &a,&b,&c };
printf("%d\n", sizeof(num));
for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++)
{
printf("%d ", *num[i]);
}
int **q = num;
printf("%d\n", **q);
for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++)
{
printf("%d ", *(*(q+i)));
}
system("pause");
return 0;
}
- 指针作为形参
值传递函数:不会修改实参的值 入参为变量,其实质是局部变量,子函数被调用完之后,局部变量会被释放,因此不会影响到实参的值 址传递函数:会修改实参的值 入参为地址,表示对改地址中的内容进行操作,即便返回主函数中,该内存中的值已经被改变,因此会改变实参的值
void swap1(int x, int y)
{
int temp = x;
x = y;
y = temp;
printf("交换后: x = %d, y = %d\n", x, y);
return;
}
void swap2(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
printf("交换后: x = %d, y = %d\n", *x, *y);
return;
}
int main()
{
int a = 10;
int b = 20;
printf("值传递交换函数:\n");
printf("a = %d, b = %d\n", a, b);
swap1(a, b);
printf("址传递交换函数:\n");
printf("a = %d, b = %d\n", a, b);
swap2(&a, &b);
system("pause");
return 0;
}
- 数组作为函数的参数
数组作为函数的参数,在子函数形参列表中会退化为指针 Eg: void print_arr(int x[10]) ====> void print_arr(int *x)
void print_arr(int *x, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", *(x + i));
}
printf("\n");
}
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr(a,10);
system("pause");
return 0;
}
- 指针作为函数返回值
int *getnum1()
{
srand(time(NULL));
num = rand();
return #
}
int num = 0;
int *getnum2()
{
srand(time(NULL));
num = rand();
return #
}
int main()
{
int *p = getnum1();
int *p = getnum2();
printf("%d\n", *p);
system("pause");
return 0;
}
|