小C的第一宇宙
wangc
Oct 12, 2017
阅读本文需要 7 分钟(按字数)
  1. 内存与地址
  • bit: 计算机的内存由数以亿万计的位组成,每个位可以容纳0和1。因为一个位可以表示值得范围太有限,通常由许多位一组作为一个单位。
  • byte: 每个字节包含存储量一个字符所需要的位数,许多现代性机器上,每个字节包括8个位(存储无符号值0-255)。每个字节通过地址来标识位置。
  • : 每个字有2-4个字节组成,他的地址通常是最左边的或者最右边的那个字节的位置。
  • 高级语言的特性之一是通过名字(变量)而不是地址来访问内存的位置。需要注意的是,名字与内存位置之间的关系不是硬件提供的,他是有编译器为我们实现的,硬件仍然通过地址访问内存位置
  1. 值和类型
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的位,数据类型并非固有的一种特性,而取决于他们被使用的方式,也就是我们看他们的方式,编译器会帮助我们设置和检查他起初的类型。

  1. 指针变量的内容

    指针变量存储的就是所指向变量的地址值,指针当然也有相应的地址值。

  2. 间接访问操作符&取地址符

    指针可以通过间接访问操作符(*),访问指向的变量。
    变量可以通过(&)取出地址。

  3. 未初始化和非法的指针

    未初始化的指针从而会随机指向一块内存位置,如果指向不可访问的内存位置还好,编译器会报错; 如果指向了合法的地址,那个位置的值会被无意修改,这种错误非常难以捕捉。所以指针变量声明时一定要初始化

  4. NULL指针

    未指向的指针可以初始化为NULL或者0,就实际而言NULL表示不指向任何东西,机器内部值可能不为0,编译器将负责0值和内部值之间的翻译转换。

  5. 指针的指针
    int a = 12;
    int *b = &a;
    int **c = &b;
    
  6. 理解指针表达式

    因为数据根本的状态有两个属性,内容和地址,左值和右值就是用来描述这两个属性的使用的。这就解释了赋值运算符’=’实际是把右边的临时存储的结果存进了左边以标识的特定内存位置,此为赋值。

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 ++ … … … …
  1. 指针运算—指针±整数

    当一个指针和一个整数量进行计算时,整数在执行加法前始终会根据适合的大小进行调整。比如p是指向double类型的指针,p+2,是相加2个double类型的大小。

  2. 指针运算—指针-指针

    只有当两个指针都指向同一个数组中的元素时,才允许这样做,相减的结果是ptrdiff_t类型,结果是两个元素的距离,相当于下标相减。

Notes:

  1. 永远清楚指针指向了哪里,指针必须指向一块有意义的内存。
  2. 永远看清每个指针指向的对象内容是什么。
  3. 永远不要使用未经过初始化的指针变量。(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