深入理解指针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 \0printf("%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 \0printf("%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));//16printf("%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——8printf("%zd\n", sizeof(&a[0]));//X86——4 X64——8printf("%zd\n", sizeof(&a[0] + 1));//X86——4 X64——8return 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——8printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8return 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找\0printf("%d\n", strlen(arr+0));//随机值printf("%d\n", strlen(*arr));//*arr——'a'——97//strlen把97当成地址,非法访问 errorprintf("%d\n", strlen(arr[1]));//errorprintf("%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 \0printf("%zd\n", sizeof(arr));//7printf("%zd\n", sizeof(arr+0));//X86——4 X64——8printf("%zd\n", sizeof(*arr));//1printf("%zd\n", sizeof(arr[1]));//1printf("%zd\n", sizeof(&arr));//X86——4 X64——8printf("%zd\n", sizeof(&arr+1));//X86——4 X64——8printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8return 0;
}
5
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {char arr[] = "abcdef";printf("%zd\n", strlen(arr));//6printf("%zd\n", strlen(arr+0));//6printf("%zd\n", strlen(*arr));//errorprintf("%zd\n", strlen(arr[1]));//errorprintf("%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));//5return 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));//1printf("%zd\n", sizeof(p[0]));//X86——4 X64——8printf("%zd\n", sizeof(&p));//X86——4 X64——8printf("%zd\n", sizeof(&p+1));//X86——4 X64——8printf("%zd\n", sizeof(&p[0]+1));//X86——4 X64——8return 0;
}
7
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {char* p = "abcdef"printf("%zd\n", strlen(p));//6printf("%zd\n", strlen(p+1));//5printf("%zd\n", strlen(*p));//errorprintf("%zd\n", strlen(p[0]));//errorprintf("%zd\n", strlen(&p));//随机值printf("%zd\n", strlen(&p+1));//随机值printf("%zd\n", strlen(&p[0]+1));//5return 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)));//16printf("%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 5return 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个字节 0x100014printf("%p\n", (unsigned long)p+0x1);//0x100001printf("%p\n",(unsigned int*) p + 0x1);//跳过四个字节 0x100004return 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 0int* p;p = a[0];printf("%d", p[0]);//1return 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 -4return 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 5return 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);//atreturn 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);//POINTreturn 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.
——《绿皮书》