一维数组
int a[] = { 1,2,3,4 };
- printf("%d\n", sizeof(a)); //数组a的字节大小:16
- printf("%d\n", sizeof(a + 0));//数组首元素地址a[0]的地址的大小:4/8,x86占4个字节,x64占八个字节
- printf("%d\n", sizeof(*a)); //a==(a+0),a[0]的字节大小:4
- printf("%d\n", sizeof(a + 1));//数组首元素的下一个元素(即a[1]地址所占的字节长度:)4/8
- printf("%d\n", sizeof(a[1])); //元素a[1]所占字节的大小 :4
- printf("%d\n", sizeof(&a)); //数组a的地址所占的字节大小:4/8
- printf("%d\n", sizeof(*&a)); //&a是整个数组的地址,*解引用得到的是整个数组的元素,所以真个数组的大小占16个字节
- printf("%d\n", sizeof(&a + 1)); //&a表示的是整个数组地址的大小,+1表示指向数组后面的地址,所占字节为:4/8
- printf("%d\n", sizeof(&a[0])); //&a[0]表示数组的第一个元素的地址所占的字节:4/8
- printf("%d\n", sizeof(&a[0] + 1)); //&a[0]+1表示数组中a[1]的地址所占的字节:4/8
#include<stdio.h>
int main() {
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a)); //数组a的字节大小:16
printf("%d\n", sizeof(a + 0));//数组首元素地址a[0]的地址的大小:4/8,x86占4个字节,x64占八个字节
printf("%d\n", sizeof(*a)); //*a==*(a+0),a[0]的字节大小:4
printf("%d\n", sizeof(a + 1));//数组首元素的下一个元素(即a[1]地址所占的字节长度:)4/8
printf("%d\n", sizeof(a[1])); //元素a[1]所占字节的大小 :4
printf("%d\n", sizeof(&a)); //数组a的地址所占的字节大小:4/8
printf("%d\n", sizeof(*&a)); //&a是整个数组的地址,*解引用得到的是整个数组的元素,所以真个数组的大小占16个字节
printf("%d\n", sizeof(&a + 1)); //&a表示的是整个数组地址的大小,+1表示指向数组后面的地址,所占字节为:4/8
printf("%d\n", sizeof(&a[0])); //&a[0]表示数组的第一个元素的地址所占的字节:4/8
printf("%d\n", sizeof(&a[0] + 1)); //&a[0]+1表示数组中a[1]的地址所占的字节:4/8
return 0;
}
字符数组
char arr[]={‘a’,‘b’,‘c’,‘d’,‘e’,’'f};
在内存中显示如下:
- printf("%d\n", sizeof(arr)); //显示数组的所占的大小:6
- printf("%d\n", sizeof(arr + 0)); //arr[0]所在地址所占字节的大小:4/8
- printf("%d\n", sizeof(*arr)); //arr==(arr+0)显示数组的第一个元素的所占字节的大小:1
- printf("%d\n", sizeof(arr[1])); //数组中第二个元素所占字节的大小:1
- printf("%d\n", sizeof(&arr)); //数组arr的地址所占的字节:4/8
- printf("%d\n", sizeof(&arr + 1)); //数组arr的地址后面的地址所占的字节:4/8
- printf("%d\n", sizeof(&arr[0] + 1));//数组元素arr[1]的地址所占的字节元素:4/8
- printf("%d\n", strlen(arr)); //随机值 由于数组后面不是以’\0’为结尾,strlen直到’\0’才计数结束,所以产生随机值
- printf("%d\n", strlen(arr + 0)); //从arr[0]开始计数,也是产生的随机值
- printf("%d\n", strlen(*arr)); //arr==(arr+0)==arr[0]=‘a’,ascii 码为:97 会产生报错
- printf("%d\n", strlen(arr[1])); //arr[1]=‘b’,ascii 码为:98 会产生报错
- printf("%d\n", strlen(&arr)); //随机值
- printf("%d\n", strlen(&arr + 1)); //随机值
- printf("%d\n", strlen(&arr[0] + 1)); //随机值
#include<stdio.h>
#include<string.h>
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr)); //显示数组的所占的大小:6
printf("%d\n", sizeof(arr + 0)); //arr[0]所在地址所占字节的大小:4/8
printf("%d\n", sizeof(*arr)); //*arr==*(arr+0)显示数组的第一个元素的所占字节的大小:1
printf("%d\n", sizeof(arr[1])); //数组中第二个元素所占字节的大小:1
printf("%d\n", sizeof(&arr)); //数组arr的地址所占的字节:4/8
printf("%d\n", sizeof(&arr + 1)); //数组arr的地址后面的地址所占的字节:4/8
printf("%d\n", sizeof(&arr[0] + 1));//数组元素arr[1]的地址所占的字节元素:4/8
printf("%d\n", strlen(arr)); //随机值 由于数组后面不是以'\0'为结尾,strlen直到'\0'才计数结束,所以产生随机值
printf("%d\n", strlen(arr + 0)); //从arr[0]开始计数,也是产生的随机值
// printf("%d\n", strlen(*arr)); //*arr==*(arr+0)==arr[0]='a',ascii 码为:97 会产生报错
// printf("%d\n", strlen(arr[1])); //arr[1]='b',ascii 码为:98 会产生报错
printf("%d\n", strlen(&arr)); //随机值
printf("%d\n", strlen(&arr + 1)); //随机值
printf("%d\n", strlen(&arr[0] + 1)); //随机值
return 0;
}
字符串数组
char arr[]={“abcdef”};
- printf("%d\n", sizeof§);//p表示的是指针变量 4/8
- printf("%d\n", sizeof(p + 1));//p+1表示字符b的地址,所占字节:4/8
- printf("%d\n", sizeof(*p)); //p==(p+0)表示字符a,字符所占字节为:1
- printf("%d\n", sizeof(p[0]));//p[0]==*(p+0),表示字符a,所占字节为:1
- printf("%d\n", sizeof(&p));//表示指向p的指针的地址的指针的地址,所占字节为:4/8
- printf("%d\n", sizeof(&p + 1));//指向地址:4/8
- printf("%d\n", sizeof(&p[0] + 1));//字符b的地址指向的所占的字节:4/8;
- printf("%d\n", strlen§); //字符串的字符为6
- printf("%d\n", strlen(p + 1));//从b开始,字符串的长度为5
- printf("%d\n", strlen(*p));//*p表示’a’,产生错误
- printf("%d\n", strlen(p[0]));//产生错误
- printf("%d\n", strlen(&p)); //随机值
- printf("%d\n", strlen(&p + 1)); //随机值
- printf("%d\n", strlen(&p[0] + 1)); //5 &p[0]==*&(p+0)=p 所以长度为5
#include<stdio.h>
int main() {
const char *p = "abcdef";
printf("%d\n", sizeof(p));//p表示的是指针变量 4/8
printf("%d\n", sizeof(p + 1));//p+1表示字符b的地址,所占字节:4/8
printf("%d\n", sizeof(*p)); //*p==*(p+0)表示字符a,字符所占字节为:1
printf("%d\n", sizeof(p[0]));//p[0]==*(p+0),表示字符a,所占字节为:1
printf("%d\n", sizeof(&p));//表示指向p的指针的地址的指针的地址,所占字节为:4/8
printf("%d\n", sizeof(&p + 1));//指向地址:4/8
printf("%d\n", sizeof(&p[0] + 1));//字符b的地址指向的所占的字节:4/8;
printf("%d\n", strlen(p)); //字符串的字符为6
printf("%d\n", strlen(p + 1));//从b开始,字符串的长度为5
printf("%d\n", strlen(*p));//*p表示'a',产生错误
printf("%d\n", strlen(p[0]));//产生错误
printf("%d\n", strlen(&p)); //随机值
printf("%d\n", strlen(&p + 1)); //随机值
printf("%d\n", strlen(&p[0] + 1)); //5 &p[0]==*&(p+0)=p 所以长度为5
return 0;
}
二维数组
- printf("%d\n", sizeof(a)); //表示整个数组所占字节的大小:48
- printf("%d\n", sizeof(a[0][0])); //首元素的大小所占的字节的大小:4
- printf("%d\n", sizeof(a[0])); //首行元素所占字节的大小:16
- printf("%d\n", sizeof(a[0] + 1)); //第二行元素所占字节的大小:16
- printf("%d\n", sizeof(*(a[0] + 1))); //表示第一行第二个元素的所占字节的大小:4
- printf("%d\n", sizeof(a + 1));//数组名a,并没有单独放在sizeof内部,也没&,所以表示首元素(第一行)的地址,a+1就是第二行的地址,(把每一行看成一个元素)4/8
- printf("%d\n", sizeof(*(a + 1)));//表示第二行元素所占的字节的大小:16
- printf("%d\n", sizeof(&a[0] + 1));//第二行地址所占的字节的大小:4/8
- printf("%d\n", sizeof(*(&a[0] + 1)));//第二行元素所占字节的大小:16
- printf("%d\n", sizeof(*a));//a表示首元素,a==(a+0)==a[0],表示第一行元素所占字节的大小:16
#include<stdio.h>
int main() {
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); //表示整个数组所占字节的大小:48
printf("%d\n", sizeof(a[0][0])); //首元素的大小所占的字节的大小:4
printf("%d\n", sizeof(a[0])); //首行元素所占字节的大小:16
printf("%d\n", sizeof(a[0] + 1)); //第二行元素所占字节的大小:16
printf("%d\n", sizeof(*(a[0] + 1))); //表示第一行第二个元素的所占字节的大小:4
printf("%d\n", sizeof(a + 1));//数组名a,并没有单独放在sizeof内部,也没&,所以表示首元素(第一行)的地址,a+1就是第二行的地址,(把每一行看成一个元素)4/8
printf("%d\n", sizeof(*(a + 1)));//表示第二行元素所占的字节的大小:16
printf("%d\n", sizeof(&a[0] + 1));//第二行地址所占的字节的大小:4/8
printf("%d\n", sizeof(*(&a[0] + 1)));//第二行元素所占字节的大小:16
printf("%d\n", sizeof(*a));//a表示首元素,*a==*(a+0)==a[0],表示第一行元素所占字节的大小:16
return 0;
}
常见的面试题
#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));
return 0;
}
根据上述的内存空间图可以看出:*(a+1)=a[1], *(ptr-1)=a[4];
所以打印的结果为:2 5
#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);
printf("%s\n", *--*++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}
这段代码还是比较有难度的,我们可以进行画图进行更容易的理解:(注意:这里的箭头我省略了,因为自己画图实在太难看。。。)这里是刚刚初始时各级指针的指向。
当代码执行打印printf("%s\n", **++cpp) 时: cp先自增再使用,所以现在的指针指向为:
所以此时此举打印的内容为:POINT
当执行第二句打印函数的时候:**printf("%s\n", –++cpp + 3); 我们继续画图方便理解:
可知cpp首先再自增,然后解引用,事得cp再自减,其次再解引用,让原来的c的原有值再+3:画图得到:
所以此时打印的字符串的结果是:ER。
继续分析下一句打印的内容:printf("%s\n", cpp[-2] + 3);
我们可以看出 cpp[-2]==(cpp-2),此时指针回退两步,(注意:此时的cpp没有发生自增或自减,所以cpp的值没有发生改变),解引用后,使cp中的内容在原来的基础上+3,画图可得:
此时打印的字符串为:ST.
终于快要画完图了 哈哈哈,斗志昂扬的分析最后一个打印的函数:printf("%s\n", cpp[-1][-1] + 1);
cpp[-1][-1]=*( *(cpp-1)-1),我们上个打印函数的时候提到,cpp在自增自减的时候之才能发生改变,所以cpp指针依旧指向cp的第三块内存地址:
可知打印的字符串的结果为:EW
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
同样,我们根据画内存空间的方式来理解此段程序:
初始时,内存图的结构如下:
运行pa++后:
所以*pa的打印的字符串为:at
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));
return 0;
}
所以打印结果为:10 和5
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
而指针-指针等于两个地址之间的元素,所以当打印:&p[4][2] - &a[4][2]的整形的时候:值为:-4
而打印地址的形式的时候:-4的原码为:1000 0000 0000 0000 0000 0000 0100
反码为:1111 1111 1111 1111 1111 1111 1111 1011
补码为:1111 1111 1111 1111 1111 1111 1111 1100
所以打印的地址形式为:FF FF FF FC
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
所以打印结果为:1
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
结构体指针大小为20个字节,p是一个指向结构体的指针,p加1跳过二十个字节,所以 p + (0x1) =0x10014 。第二个是把结构体指针强制类型转换为(unsigned long)的数,对它加1,就直接给这个数加1,结果为0x100001。第三个是把结构体指针强制类型转换为(unsigned int*)类型,对它加1,偏移4个字节,结果为0x100004