C语言深度解剖 (四)
原文链接: C语言深度解剖 (四)
前言
C语言的水深不见底,好在一些前辈们已经将很多雷区探了一遍
这里分享一下我在学习 《C语言深度解剖》 过程中的一些笔记和心得
概要
- TOC
{:toc}
指针与数组
#include <stdio.h>
void main()
{
int i=10; //&i 为 0x0018ff44
int *p=&i;
p=(int *)0x0018ff44;
*p=11;
*(int *)0x0018ff44=12;
printf ("%x\t%d\t%d\n",p,*p,*(int *)0x0018ff44); //18ff44 12 12
}
在VC++6.0中,上面的例子,数值变化都如预期,但是下面的数值变化会让人迷惑不解,因为p指针的值会随内容而变化(这个是不应该发生的事情,这是VC++6.0的bug)
#include <stdio.h>
void main()
{
int *p;
p=(int *)0x0018ff44;
*p=11;
*(int *)0x0018ff44=12;
printf ("%x\t%d\t%d\n",p,*p,*(int *)0x0018ff44);
}
不过,像这样,未经申请而直接使用内存的行为是很危险的
数组大小
void main()
{
int a[5]={1,2,3,4,5};
int i=sizeof(&a); //20 这是一个地址,但为什么是20个字节的长度呢
int j=sizeof(a); //20 a作为一个首地址,为什么是20个字节的长度呢
int k=sizeof(&a[0]); //4
int l=sizeof(&a[5]); //4 及便这个元素不存在
}
可以将它们的地址分别取出来看看
首地址
#include <stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1); // 一次性跳数组长度的字符个数
printf("%d,%d\n",*(a+1),*(ptr-1)); // 2,5
printf("%x,%x,%x,%x,%x\n",a,&a,a+1,&a+1,ptr-1); //18ff34,18ff34,18ff38,18ff48,18ff44
}
对指针进行加1操作,得到的是连续内存中下一个元素的地址
一个类型为T的指针的移动,是以sizeof(T)为移动单位的
&a 与 a 的值是一样的,但是意思不一样
&a 是数组(结构体/构造体)的首地址
a 是数组首元素的首地址
&a+1,取数组a的首地址,该地址的值加上sizeof(a)的值,即&a+5*sizeof(int)
可以将a理解为结构体名,同时其值为&a[0]
a+1,是数组下一元素的首地址,即 a[1]的首地址
#include <stdio.h>
void main()
{
char a[5]={'a','b','c','d','e'};
char (*p1)[3]=&a;
char (*p2)[3]=a;
char (*p3)[10]=&a;
char (*p4)[10]=a;
printf("%x,%x,%x,%x,%x\n",a,p1+1,p2+1,p3+1,p4+1); //18ff40,18ff43,18ff43,18ff4a,18ff4a
}
数组指针,是一个指针 ,但是它每次加一后,跳过的内存字节数为 n*sizeof(type)
地址的强制转换
#include <stdio.h>
void main()
{
int a[4]={1,2,3,4};
int *ptr1 =(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
printf("%x,%x\n",ptr1[-1],*ptr2); // 4,2000000
}
二维数组
#include <stdio.h>
void main()
{
int a[3][2]={(0,1),(2,3),(4,5)};
int *p;
p=a[0];
printf("%d\n",p[0]); //1
}
这里千万要看清楚小括号里逗号分隔的表达式
#include <stdio.h>
void main()
{
int a[5][5];
int (*p)[4];
p=a;
printf("a_ptr=%#p,p_ptr=%#p\n",&a[4][2],&p[4][2]); // a_ptr=0X0018FF3C,p_ptr=0X0018FF2C
printf("%p,%d\n",&p[4][2]-&a[4][2],&p[4][2]-&a[4][2]); //FFFFFFFC,-4
}
&a[4][2]
表示 &a[0][0]+4*5*sizeof(int)+2*sizeof(int)
&p[4][2]
表示 &a[0][0]+4*4*sizeof(int)+2*sizeof(int)
所以差 4*sizeof(int)
,而地址相减获得的是此类型数据占用内存的单位数,所以,虽然相差16个字节,但是相差4个单位,一个int占4字节