指针
先说说指针的基本概念:
1.指针就是个变量,用来存放地址,地址唯一标识一块空间。
2.指针大小固定的4/8个字节(32位平台/64位平台)。
3.指针是有类型的,指针+1,是指加上其所指向类型的大小。
字符指针
在指针类型中,我们知道有一种指针类型为字符指针char*。
使用方式:
int main()
{
char a='q';
char* s=&a;
char* str="world!!!";//我们知道C语言中是没有字符串类型的,C语言保存字符串是将字符串首元素地址保存在字符指针中,这个字符串必须以'\0'结尾代表字符串结束,称带有'\0'的字符串称为C字符串。
return 0;
}
char* str=“world!!!”,是将字符串首元素的地址放在str中。代码中字符串放在字符常量区。若前面是char str[]=“world!!!”,则字符串是放在栈上。
来看看下面代码输出的结果是什么?
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char *str3 = "hello bit.";
char *str4 = "hello bit.";
if(str1 ==str2)
printf("str1 == str2 \n");
else
printf("str1 != str2\n");
if(str3 ==str4)
printf("str3 == str4\n");
else
printf("str3 != str4\n");
return 0;
}
因为str1和str2都是在栈上申请的空间,地址是不同的。只不过他们的内容恰好相等。但是str3和str4他们是指针变量,指向字符常量区的同一个字符串首元素的地址,所以相等。
**注意:**字符常量区的字符串,不能被改写。
int main()
{
//这种是不可以的
char* p="hello\n";
*p='H';
//建议大家可以这样写。
const char *p="hello\n";//代表p指向的内容不能变。
char *const p="hello\n";//代表p的指向不能变。也就是说,不能用p来遍历字符串。
}
指针数组
首先我们最应该知道的一点:指针数组是数组,是一个存放指针的数组。
int *arr1[10];//整形指针数组
int **arr2[15];//字符指针数组
那么如何来判别指针数组呢?
根据名称左右符号的优先级来判定,此处[]优先级高于*,因此是数组,所以就是指针数组。
数组指针
首先我们也应该知道的一点:数组指针是指针,是能够指向数组的指针。
int *p1[10];//指针数组
int (*p2)[10];//数组指针
判定方法与指针数组相同,看优先级。
这里我们回忆一些关于数组的知识
1.除了sizeof 和 取地址时,数组名代表的是整个数组。其他情况下数组名代表数组首元素的地址。只不过整个数组的地址和数组首元素的地址在数值上是相等的。
2.作为函数参数的数组名,降维为指向内部元素类型的指针。
3.任何数组作为函数参数,只能省略一维参数,其他维参数都不能省略。
看下面代码:
int main()
{
int a[10];
//int(*p)[10] = a;这样的话,只是把数组首元素的地址传给数组指针了,并不是整个数组的地址。而数组首元素的地址类型是int*型,p类型是数组指针,从而会造成类型不匹配。
int(*p)[10] = &a;//应该取数组的地址,代表将整个数组的地址传给p,这样才是正确的。
printf("%p\n", p);
printf("%p\n", p + 1);
printf("%p\n", (int)p + 1);//强转为整型,所以+1,就只是+1。
printf("%p\n", (int *)p + 1);
system("pause");
return 0;
}
1.因为指针类型是数组指针,又因为指针+1,是指加上其所指向类型的大小。所以p+1相当于+40。
2.因为强转为整型,所以(int)p+1,就只是+1。
3.因为强转为指针类型,所以(int*)p+1,代表+4。
再来看看下面代码,猜猜结果:
int main()
{
int a[10] = {0};
printf("a=%p\n", a);
printf("&a=%p\n", &a);
printf("a+1=%p\n", a+1);
printf("&a+1=%p\n", &a+1);
return 0;
}
1.由结果可看出,数组名(也就是数组首元素地址)和数组地址是相同的,但是他们的意义不同。
2.数组名+1是第二个元素的地址。所以+4。
3.数组地址+1,是下一个数组的地址。所以+40。
数组指针的使用:
void print_arr1(int arr[3][5], int row, int col){}
void print_arr2(int (*arr)[5], int row, int col) {}
int main()
{
int a[3][5]={1,2,3,4,5,6,7,8,9,10};
print_arr1(arr, 3, 5);
print_arr2(arr, 3, 5);
return 0;
}
代码中两个函数参数中,接收二位数组的两种形式,都是可以的。因为我们知道数组名作为函数参数,会降维成指向数组内部元素类型的指针。 此时数组内部元素类型是数组。所以降维成数组指针类型。用print_arr2更好些。
函数指针:
首先看一段代码:
#include <stdio.h>
void test()
{
printf("haha\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
通过结果我们可以发现,输出的是函数的地址。那么我们怎么来保存函数地址呢?这就要用到函数指针了。
函数指针的使用:
void test()
{//操作
}
int main()
{
void (*p)()=test;//这就是函数指针,保存的是函数的地址。
//若指向的函数有参数,比如:test(int a),则函数指针如下
void (*p) (int)=test;
return 0;
注意:与数组不同的是,void *p(),不是指针函数。他就是返回值为 void *的函数。