指针
什么是指针
指针是我们进阶C语言的“拦路虎”,因为他在小白看来其定义如此复杂多变,难以捉摸。可是大神或者有一定变成经验的人来看,就是一个简答的概念。我们只要记住:指针即是变量又是地址。就像光具有波粒二象性一样。你可以把指针理解成为地址(方便理解),但是其本质还是一个变量只不过这个变量是专门存放地址的。
指针简单上手
int a = 100;
printf("%d", a);
int* p = &a;//这个p就是存放a的地址的指针变量,任何指针变量在定一起类型的时候要加一个‘*’声明其是一个指针变量。
*p = 20;
printf("%d", a);//通过找到地址可以更改这的地址所指的内容。
指针的分类
整形指针&字符指针
这两个是比较常见和容易理解的指针,依次用int和char表示,他们的区别在于指向变量类型不同,内存也不一样,在进行解引用操作时访问的字节大小也因为变量类型的区别会有所差异。整型指针可以访问4个字节,而字符指针只能访问1个字节。也就是说对整型指针变量解引用,一次可以操作一个整型,而对字符变量解引用一次只能操作一个字符。
较为特殊的char* p="hello"这并不是将整个字符串的地址传个了p,而是传了字符穿首元素‘h’的地址,可以通过’h‘的地址来找到整个字符串。此时出现char*p2=“hello”,p2和p代表的是同一处地址,因为hello是常量字符串,没有必要开辟两块不同的空间的来存储它。这是字符指针的一个特性。
- 整型指针 - int* - 指向整型的指针
字符指针 - char * - 指向字符的指针
int a = 100;
char ch = 'm';
char* pc = &ch;
printf("%d\n", a);
printf("%c\n", ch);
int* p = &a;
*p = 20;
*pc = 's';
printf("%d\n", a);
printf("%c\n", ch);
void指针
void型的指针可以接受任何类型的地址,但是不能对void型指针进行解引用操作。解引用操作要有特定的访问字节的数量,比如对整型指针解引用就是访问4个字节,字符型指针解引用就是访问1个字节,而void型指针无法确定访问字节个数,所以不能进行解引用操作。同时void这种类型的指针也不能进行加减整数的操作,因为无法确定跳过的字节个数。
典型的例子可以举一个 memmove函数。它可以对任意类型的数组变量进行粘贴,且可以出现重叠。
void * memmove ( void * destination, const void * source, size_t num );
在memmove的声明中,出现了void * 这个类型的变量,memmove可以对任意类型进行处理,因为可以通过void类型转化为想要的类型。定义子有很多,不会像strncpy只可以针对字符串。
/* memmove example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "memmove can be very useful......";
memmove (str+20,str+15,11);
puts (str);
return 0;
}
数组指针
这是一种指向数组的指针,例如int(p)[10]这就是一个指向数组的指针,它指向的数组有10个元素,每个元素都是整型。给p加上括号是因为p和[10]优先结合,这样的话就变成了一个数组而不是指针了。这个数组叫 指针数组 ,int*p[10]这样的写法意思是一个有10个元素的数组,每一个元素都是整型指针,这和数组指针是两个不同的东西。
指向数组的指针里面存放的便是数组的地址,而非数组某个元素的地址,所以在定义数组指针时要用 &+数组名,而不是简单使用 数组名。
//关于数组名
//数组名是数组首元素的地址
//但是有2个例外:
//1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
//2. &数组名 - 数组名也表示整个数组,取出的是整个数组的地址
//除了这个2个例外,你见到的所有的数组名都表示首元素的地址
数组指针:指向数组的指针
char arr[] = "abcdef";
char* pa = arr;
printf("%s", pa);
但是我们还是要区分另外一个概念就是 指针数组,它是存放指针的数组。二者不要搞混了。
int a[] = {
1,2,3,4 };
int* p = a