前言
指针的一些总结
一、指针
1.指针的概念
指针是内存中最小单元的编号,也就是地址。一个最小的内存单元通常是一个字节。
对于32位的机器,有32跟地址线,通电之后产生高电平(1)和低电平(0),就产生了32位0/1组成的二进制序列,就需要使用4个字节的空间来存储,会产生2的32次方个地址,同理64位的机器就需要使用8个字节的空间来存储,会产生2的64次方个地址,所以指针的大小是4/8个字节,每一个地址可以唯一的标识一个内存单元。
2.指针类型
char ch = ‘w’;
char* p = &ch;
这里的p是一个字符指针,*代表p是一个指针,char表示p所指向的ch的类型是char。同理,还有其他类型的指针。
int * pi =NULL;
short* ps = NULL;
float* pf = NULL;
double* pd = NULL;
指针的定义方式:类型+*
指针的类型决定了指针的步长(向前或向后走一步跳过几个字节)
指针的类型决定了指针解引用能返回几个字节
#include <stdio.h>
int main()
{
int a[] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(a) / sizeof(a[0]);
for (int i = 0; i < sz; i++)
{
printf("%d ", *(a + i));
}
/*for (int i = 0; i < sz; i++)
{
printf("%d ", a[i]);
}*/
return 0;
}
同时上面的例子也说明:在一块连续的内存空间中,*(数组名+i)等价于 数组名[i]
3.指针运算
指针和指针之间可以进行比较,同时指针可以加减整数来访问前后的数据(不非法访问的情况下),同时指针减指针所求的是指针之间的元素个数,利用这一点,可以求字符串的长度
int my_strlen(const char* str)
{
char* tail = str;
while (*tail++)
;
return tail - str - 1;
}
4.字符指针
字符指针有两种:
char s1[]=“hello world”;
char* ps = “hello world”;
第一种的字符指针,本质上实在栈区上开辟的空间
第二种的字符指针ps本质是将“hello world”首字符的地址放到了ps中,“hello world”是放在静态区上的的,所以*ps不能改变原字符串
所以在初始化时,可以加上cosnt 让程序更加健壮
5.指针数组
指针数组是指针的数组
int* arr1[10] 整形指针的数组
char* arr2[10] 字符指针的数组
首先 ,arr1和[]结合,说明arr1是一个数组,数组有10个元素,每个元素类型是int*
6.指针数组
指针数组是指针的数组
int(*p)[10]
p首先和*结合,说明p是一个指针,指向的是一个数组,数组有10个元素,每个元素类型为int
这里在说一下数组名和指针
数组名是数组首元素的地址,但有两个例外
1.sizeof(数组名),数组名单独出现在括号中,计算的是整个数组的大小,单位是字节
2.&数组名,取出的是整个数组的地址,加1跳过一个数组的大小
7.指针和数组习题
#include <stdio.h>
int main()
{
一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//4*4 16
//数组名单独放在括号里,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(a + 0));//4/8
//这里的a既没有单独放在括号里,有没有&,所以a是数组首元素的地址,a+0还是首元素的地址,是地址就是4/8字节
printf("%d\n", sizeof(*a));//4
//a是首元素的地址,解引用就是数组的第一个元素,即sizeof(int)
printf("%d\n", sizeof(a + 1));//4/8
//a是首元素的地址,a+1是数组第二个元素的地址
printf("%d\n", sizeof(a[1]));//4
//a[1]即*(a+1),就是数组的第二个元素,即sizeof(int)
printf("%d\n", sizeof(&a));//4/8
//&a取出的是数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*&a));//16
//*和&操作相反,可以消去,所以还是sizeof(a)
printf("%d\n", sizeof(&a + 1));//4/8
//&a取出的是数组的地址,+1还是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&a[0]));//4/8
//取出的是数组首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&a[0] + 1));//4/8
//取出的是数组首元素的地址,+1指向数组的第二个元素的地址,是地址就是4/8个字节
}
#include <stdio.h>
#include <string.h>
int main()
{
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//6
//arr单独放在()里,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(arr + 0));//4/8
//arr是首元素的地址,+0还是首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));//1
//arr是首元素的地址,解引用访问第一个元素,即sizeof(char)
printf("%d\n", sizeof(arr[1]));//1
//arr[1]=*(arr+1),arr是首元素的地址,加一之后解引用访问数组第二个元素,即sizeof(char)
printf("%d\n", sizeof(&arr));//4/8
//&arr,取出的是整个数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr + 1));//4/8
//&arr,取出的是整个数组的地址,+1之后还是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//4/8
//&arr[0]取出的是数组首元素的地址,加一指向数组第二个元素的地址,是地址就是4/8个字节
//strlen求字符串长度,直到遇到‘\0’才停止
printf("%d\n", strlen(arr));//随机值
//arr是首元素的地址,随机值,不知道‘\0’会出现在哪里
printf("%d\n", strlen(arr + 0));//随机值
//arr是首元素的地址,+0还是首元素的地址,随机值,不知道‘\0’会出现在哪里
//printf("%d\n", strlen(*arr));error
//*arr是数组的第一个元素,即‘a’,strlen的参数要求的是指针,会产生非法访问的内存错误;
//printf("%d\n", strlen(arr[1]));//error
//arr[1]=*(arr+1),*(arr+1)是数组的第二个元素,即‘b’,strlen的参数要求的是指针,会产生非法访问的内存错误;
printf("%d\n", strlen(&arr));//随机值
//&arr取出的是数组的地址,随机值,不知道‘\0’会出现在哪里
printf("%d\n", strlen(&arr + 1));//随机值
//&arr取出的是数组的地址,加一跳过一个数组,随机值,不知道‘\0’会出现在哪里
printf("%d\n", strlen(&arr[0] + 1));//随机值
//&arr[0]取出的是数组首元素的地址,加1指向数组的第二个元素,随机值,不知道‘\0’会出现在哪里
}
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7,‘\0’也算一个字节
//arr单独放在()里,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(arr + 0));//4/8
//arr是数组首元素的地址,+0还是首元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));//1
//*arr是数组首元素,即sizeof(char)
printf("%d\n", sizeof(arr[1]));//1
//arr[1] = *(arr+1),对数组的第二个元素解引用,就sizeof(char)
printf("%d\n", sizeof(&arr));//4/8
//&arr,取出的是整个数组的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr + 1));//4/8
//&arr,取出的是整个数组的地址,+1还是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//4/8
//&a[0],取出的是数组首元素的地址,加1指向数组的第二个元素的地址,是地址就是4/8个字节
printf("%d\n", strlen(arr));//6
//arr是数组首元素的地址
printf("%d\n", strlen(arr + 0));//6
//arr是数组首元素的地址,+0还是数组首元素的地址
//printf("%d\n", strlen(*arr));//error
//*arr是对数组的首元素解引用,即‘a’,会产生非法访问内存的错误
//printf("%d\n", strlen(arr[1]));//error
//arr[1] = *(arr+1),*(arr+1)是对数组的第二个元素解引用,即‘b’,会产生非法访问内存的错误
printf("%d\n", strlen(&arr));//6
//&arr,取出的是整个数组的地址
printf("%d\n", strlen(&arr + 1));//随机值
//&arr,取出的是整个数组的地址,+1跳过整个数组,不知道后面‘\0’的位置,随机值
printf("%d\n", strlen(&arr[0] + 1));//5
//&arr[0]取出的是数组首元素的地址,+1指向数组的第二个元素
}
#include <stdio.h>
#include <string.h>
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));//4/8
//p是指向'a'的指针,是指针就是4/8个字节
printf("%d\n", sizeof(p + 1));//4/8
//p是指向'a'的指针,+1指向‘b’,是指针就是4/8个字节
printf("%d\n", sizeof(*p));//1
//*p即sizeof(char)
printf("%d\n", sizeof(p[0]));//1
//p[0] = *(p+0),即sizeof(char)
printf("%d\n", sizeof(&p));//4/8
//&p是一个二级指针,是指针就是4/8个字节
printf("%d\n", sizeof(&p + 1));//4/8
//&p是一个二级指针,+1跳过一个一级指针的大小,是指针就是4/8个字节
printf("%d\n", sizeof(&p[0] + 1));//4/8
//&p[0],取出的是‘a’的地址,加一就是‘b’的地址
printf("%d\n", strlen(p));//6
//p指向字符串首元素
printf("%d\n", strlen(p + 1));//5
//p指向字符串首元素,+1即指向字符串第二个元素
//printf("%d\n", strlen(*p));//error
//*p首元素解引用,即‘a’,会产生非法访问内存的错误
//printf("%d\n", strlen(p[0]));//error
//p[0] = *p, 首元素解引用,即‘a’,会产生非法访问内存的错误
printf("%d\n", strlen(&p));//随机值
//&p取出的是p的地址,不知道后面‘\0’的位置,随机值
printf("%d\n", strlen(&p + 1));//随机值
//&p取出的是p的地址,+1跳过一个字符指针的大小,不知道后面‘\0’的位置,随机值
printf("%d\n", strlen(&p[0] + 1));5
//&p[0],指向字符串首元素,+1即指向字符串第二个元素
return 0;
}
#include <stdio.h>
int main()
{
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//48
//a单独放在()里,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(a[0][0]));//4
//a[0][0]是数组第一行第一个元素
printf("%d\n", sizeof(a[0]));//16
//a[0]是数组第一行的函数名,函数名单独放在()里,计算的是整个数组的大小
printf("%d\n", sizeof(a[0] + 1));//4/8
//a[0]是数组第一行的函数名,即a[0][0]的地址,加一指向a[0][1],是地址就是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));//4
//*(a[0] + 1)) = a[0][1],即数组第一行第二个元素
printf("%d\n", sizeof(a + 1));//4/8
//a表示首元素的地址,加一指向a[1],是地址就是4/8个字节
printf("%d\n", sizeof(*(a + 1)));//16
//*(a + 1) = a[1],就第二行的函数名,函数名单独放在()里,计算的是整个数组的大小
printf("%d\n", sizeof(&a[0] + 1));//4/8
//&a[0],取出的是数组首元素的地址,加一指向a[1],是地址,就是4/8个字节
printf("%d\n", sizeof(*(&a[0] + 1)));//16
//&a[0],可以看作a,即为a[1],就第二行的函数名,函数名单独放在()里,计算的是整个数组的大小
printf("%d\n", sizeof(*a));//16
//a是数组首元素的地址,*a 即a[0],数组第一行的函数名,函数名单独放在()里,计算的是整个数组的大小
printf("%d\n", sizeof(a[3]));//16
//a是数组首元素的地址,*a 即a[0],数组第四行的函数名,函数名单独放在()里,计算的是整个数组的大小
//虽然没有第四行,但sizeof计算的是类型
return 0;
}
8.函数指针
在我们调用函数时,其实本质上都是在去call这个函数的地址。使用函数指针可以保存函数的地址。