【重生之我要苦学C语言】深入理解指针6
深入理解指针6
sizeof和strlen的对比
sizeof
操作符
整型:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a = 10;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof a );
return 0;
}
字符串:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char arr[] = "abcdef";
//a b c d e f \0
printf("%zd\n", sizeof(arr));
return 0;
}
输出为 7
strlen
库函数
只能求字符串长度
size_t strlen(const char* str);
strlen统计的是str后,\0之前字符串的个数
strlen函数会一直向后找\0字符,直到找到为止,可能存在越界查找
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = "abcdef";
//a b c d e f \0
printf("%zd\n", sizeof(arr));
printf("%zd\n", strlen(arr));
return 0;
}
输出为:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = { 'a','b','c' };
//a b c
printf("%zd\n", sizeof(arr));
printf("%zd\n", strlen(arr));
return 0;
}
strlen越界访问
总结
- sizeof是操作符
- strlen是库函数,使用时需要包含string.h
- sizeof计算操作数所占内存大小,单位是字节
- strlen是求字符串长度的,统计的是\0之前字符的个数
- sizeof不关注内存中存放什么数据
- sizeof关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界
数组和指针中sizeof和strlen辨析
1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));//16
printf("%zd\n", sizeof(a + 0));//X86——4 X64——8
//a做为数组名,并未单独放在sizeof内部,a是数组首元素的地址,a+0是数组首元素的地址
printf("%zd\n", sizeof(*a));//4
//a是数组首元素的地址 *a首元素
printf("%zd\n", sizeof(a + 1));//X86——4 X64——8
//第二个元素的的地址
printf("%zd\n", sizeof(a[1]));//4
//a[1]第二个元素
printf("%zd\n", sizeof(&a));//X86——4 X64——8
//&a整个数组的地址,是地址,长度就是4/8个字节
//&a+1跳过16个字节
printf("%zd\n", sizeof(*&a));//16 sizeof(a)
printf("%zd\n", sizeof(&a + 1));//X86——4 X64——8
printf("%zd\n", sizeof(&a[0]));//X86——4 X64——8
printf("%zd\n", sizeof(&a[0] + 1));//X86——4 X64——8
return 0;
}
数组名的理解:
数组名是数组首元素的地址,但是有两个例外:
1.sizeof(数组名),数组名表示整个数组
2.&数组名,数组名表示整个数组
2
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", sizeof(arr));//6
//计算整个数组的大小
printf("%zd\n", sizeof(arr+0));//X86——4 X64——8
//首元素地址
printf("%zd\n", sizeof(*arr));//1
//首元素
printf("%zd\n", sizeof(arr[1]));//1
//第二个元素
printf("%zd\n", sizeof(&arr));//X86——4 X64——8
//数组的地址
printf("%zd\n", sizeof(&arr+1));//X86——4 X64——8
printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8
return 0;
}
3
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机值 strlen找\0
printf("%d\n", strlen(arr+0));//随机值
printf("%d\n", strlen(*arr));//*arr——'a'——97
//strlen把97当成地址,非法访问 error
printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));//随机值
return 0;
}
4
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char arr[] = "abcdef";
//a b c d e f \0
printf("%zd\n", sizeof(arr));//7
printf("%zd\n", sizeof(arr+0));//X86——4 X64——8
printf("%zd\n", sizeof(*arr));//1
printf("%zd\n", sizeof(arr[1]));//1
printf("%zd\n", sizeof(&arr));//X86——4 X64——8
printf("%zd\n", sizeof(&arr+1));//X86——4 X64——8
printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8
return 0;
}
5
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = "abcdef";
printf("%zd\n", strlen(arr));//6
printf("%zd\n", strlen(arr+0));//6
printf("%zd\n", strlen(*arr));//error
printf("%zd\n", strlen(arr[1]));//error
printf("%zd\n", strlen(&arr));//6
//&arr——char(*)[7]
//strlen(const char* str)警告
printf("%zd\n", strlen(&arr+1));//随机值
//&arr+1跳过整个数组
printf("%zd\n", strlen(&arr[0]+1));//5
return 0;
}
6
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char* p = "abcdef";
printf("%zd\n", sizeof(p));//X86——4 X64——8
//计算的是p这个指针变量的大小
printf("%zd\n", sizeof(p+1));//X86——4 X64——8
//p+1是第二个元素的地址
printf("%zd\n", sizeof(*p));//1
printf("%zd\n", sizeof(p[0]));//X86——4 X64——8
printf("%zd\n", sizeof(&p));//X86——4 X64——8
printf("%zd\n", sizeof(&p+1));//X86——4 X64——8
printf("%zd\n", sizeof(&p[0]+1));//X86——4 X64——8
return 0;
}
7
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char* p = "abcdef"
printf("%zd\n", strlen(p));//6
printf("%zd\n", strlen(p+1));//5
printf("%zd\n", strlen(*p));//error
printf("%zd\n", strlen(p[0]));//error
printf("%zd\n", strlen(&p));//随机值
printf("%zd\n", strlen(&p+1));//随机值
printf("%zd\n", strlen(&p[0]+1));//5
return 0;
}
二维数组中sizeof和strlen辨析
8
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a[3][4] = { 0 };
printf("%zd\n", sizeof(a));//48
//a数组名,单独放在sizeof里,表示整个数组,计算的是整个数组的大小
printf("%zd\n", sizeof(a[0][0]));//4
//a[0][0]第一行第一个元素
printf("%zd\n", sizeof(a[0]));.//16
//a[0]第一行数组名,单独放在sizeof内部,计算的是第一行的大小
printf("%zd\n", sizeof(a[0]+1));//X86——4 X64——8
//a[0]不是单独放在sizeof内部,a[0]就是首元素的地址,a[0][0]的地址,a[0]+1第一行第二个元素的地址
printf("%zd\n", sizeof(*(a[0]+1)));//4
//a[0]+1是a[0][1]的地址,*(a[0]+1)就是a[0][1]
printf("%zd\n", sizeof(a+1));//X86——4 X64——8
//a是二维数组第一行的地址 a+1是第二行的地址
printf("%zd\n", sizeof(*(a+1)));//16
//计算的是第二行的大小
printf("%zd\n", sizeof(&a[0]+1));//X86——4 X64——8
//&a[0]第一行的地址 &a[0]+1第二行的地址
printf("%zd\n", sizeof(*(&a[0]+1)));//16
printf("%zd\n", sizeof(*a));//16
//a是二维数组第一行的的地址 *a就是行,计算的是第一行的大小
printf("%zd\n", sizeof(a[3]));//16
//sizeof在计算的时候是根据类型计算长度的,即使写的是一个表达式,编译器也会推算出最后的类型来计算长度
return 0;
}
指针运用笔试题
例1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a[5] = { 1,2,3,4,5 };
int* ptr = (int*)(&a + 1);
printf("%d %d", *(a + 1), *(ptr - 1));
//2 5
return 0;
}
例2 指针+1
X86环境下
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p=(struct Test*)0x100000;
int main() {
printf("%p\n", p + 0x1);
//结构体指针+1跳过20个字节 0x100014
printf("%p\n", (unsigned long)p+0x1);
//0x100001
printf("%p\n",(unsigned int*) p + 0x1);
//跳过四个字节 0x100004
return 0;
}
例3
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a[3][2] = { (0,1),(2,3),(4,5) };
//逗号表达式 1 3
// 5 0
// 0 0
int* p;
p = a[0];
printf("%d", p[0]);
//1
return 0;
}
例4 指针-指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int a[5][5];
int(*p)[4];
//数组指针,指向的数组里有四个int类型的元素
p = a;
printf("%p %d\n", &p[4][2]-&a[4][2],&p[4][2]-&a[4][2]);
//FFFFFFFC -4
return 0;
}
例5
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
//第二行地址
printf("%d %d", *(ptr1 - 1), *(ptr2 - 1));
//10 5
return 0;
}
例6
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char* a[] = { "work","at","c" };
char** pa = a;
pa++;
printf("%s\n", *pa);
//at
return 0;
}
例7
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char* c[] = { "ENTER","NEW","POINT","FIRST"};
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp);//POINT
return 0;
}
printf("%s\n", *-- * ++cpp + 3);//ER
printf("%s\n", *cpp[-2] + 3);//ST
//**(cpp-2)+3
printf("%s\n", cpp[-1][-1] + 1);//EW
//*(*cpp-1)-1)+1
END……
世界上有太多孤独的人,害怕先踏出第一步。
There are too many lonely people in the world who afraid to take the first step.
——《绿皮书》