wangc
Oct 12, 2017
- 内存与地址
- bit: 计算机的内存由数以亿万计的位组成,每个位可以容纳0和1。因为一个位可以表示值得范围太有限,通常由许多位一组作为一个单位。
- byte: 每个字节包含存储量一个字符所需要的位数,许多现代性机器上,每个字节包括8个位(存储无符号值0-255)。每个字节通过地址来标识位置。
- 字: 每个字有2-4个字节组成,他的地址通常是最左边的或者最右边的那个字节的位置。
- 高级语言的特性之一是通过名字(变量)而不是地址来访问内存的位置。需要注意的是,名字与内存位置之间的关系不是硬件提供的,他是有编译器为我们实现的,硬件仍然通过地址访问内存位置。
- 值和类型
int a = 112, b = -1;
float c = 3.14;
int *d = &a;
float *e = &c;
名字 | a | b | c | d | e |
---|---|---|---|---|---|
地址 | 100 | 104 | 108 | 112 | 116 |
内容 | 112 | -1 | 10778523331 | 100 | 108 |
内存中每个字中存储的都是内容是0或1的位,数据类型并非固有的一种特性,而取决于他们被使用的方式,也就是我们看他们的方式,编译器会帮助我们设置和检查他起初的类型。
- 指针变量的内容
指针变量存储的就是所指向变量的地址值,指针当然也有相应的地址值。
- 间接访问操作符&取地址符
指针可以通过间接访问操作符(*),访问指向的变量。
变量可以通过(&)取出地址。 - 未初始化和非法的指针
未初始化的指针从而会随机指向一块内存位置,如果指向不可访问的内存位置还好,编译器会报错; 如果指向了合法的地址,那个位置的值会被无意修改,这种错误非常难以捕捉。所以指针变量声明时一定要初始化。
- NULL指针
未指向的指针可以初始化为NULL或者0,就实际而言NULL表示不指向任何东西,机器内部值可能不为0,编译器将负责0值和内部值之间的翻译转换。
- 指针的指针
int a = 12; int *b = &a; int **c = &b;
- 理解指针表达式
因为数据根本的状态有两个属性,内容和地址,左值和右值就是用来描述这两个属性的使用的。这就解释了赋值运算符’=’实际是把右边的临时存储的结果存进了左边以标识的特定内存位置,此为赋值。
lvalue-左值: 内存中持续存储的一个地址;
rvalue-右值: 临时存储的表达式结果;
声明:
char ch = 'a';
char *cp = &ch;
表达式 | rvalue | lvalue |
---|---|---|
ch | 表达式的内容(‘a’) | 该内存的地址 |
&ch | 变量ch的地址 | 非法 (未标识任何内存特定位置) |
cp | 表达式的内容 | 该内存的地址 |
&cp | 变量cp的地址 | 非法 (未标识任何内存特定位置) |
*cp | 变量ch的内容 | 变量ch的地址 |
*cp+1 | 根据优先级,先 *取值,值的拷贝+1为结果(‘b’) | 非法 (未标识任何内存特定位) |
*(cp+1) | 根据优先级,先地址+1,在取值 | 可以使用,前提是我们知道这个位置存储着什么东西 |
++cp | 表达式的结果是增值后指针的一份拷贝 | 非法(未标识任何内存特定位置) |
cp++ | 表达式的结果是指针原来值的一份拷贝 | 非法(未标识任何内存特定位置) |
*++cp | 增值后指针地址拷贝所指向的地址中的值 | 增值后的地址 |
*cp++ | ch的值(后缀++在表达式中使用其原先操作数的值) | ch的内存位置 |
++*cp | 表达式的结果是ch增值后的一份拷贝 | 非法 |
(*cp)++ | ch的值(首先执行间接访问操作) | 非法 |
++*++cp | 增值后地址的值+1(这些操作符的结合性都是从左到右) | 非法 |
++*cp ++ | … … | … … |
- 指针运算—指针±整数
当一个指针和一个整数量进行计算时,整数在执行加法前始终会根据适合的大小进行调整。比如p是指向double类型的指针,p+2,是相加2个double类型的大小。
- 指针运算—指针-指针
只有当两个指针都指向同一个数组中的元素时,才允许这样做,相减的结果是ptrdiff_t类型,结果是两个元素的距离,相当于下标相减。
Notes:
- 永远清楚指针指向了哪里,指针必须指向一块有意义的内存。
- 永远看清每个指针指向的对象内容是什么。
- 永远不要使用未经过初始化的指针变量。(NULL)
- 应用场景一
适用于函数需要返回多个值
void swap (int *a, int *b);
{
int t = *a;
*a = *b;
*b = t;
}
- 应用场景二
函数返回运算状态,结果由指针返回
int divide( int a, int b, int *c)
{
int ret = 1;
if(b == 0) ret = 0;
else{
*c = a/b;
}
return ret;
}
- 应用场景三
字符串的操作
int strlen( char * string )
{
int length = 0;
while( *string++ != '\0' )
length += 1;
return length;c
}
c