主要是为 Reference 存个书签.
Pointers
在写程序的过程中, array 是相当有用的. 但是 array 是静态的, 也就是它的大小不能改 变. 此时指针就派上用场.
在 C 中, pointer 表示一个 data 的内存地址. 如果一个 pointer 为 0, 那它叫做 null pointer, 也叫 NULL , "nil" .
Declarations
指针声明的方式是, 在一个已经存在的数据类型前加一个 *
. 如
int *ip; |
声明了一个名为 ip
的 pointer 指向一个整数.
创建一个指针的方法是用算符 &
(address-of) . 顾名思义, 它作用到一个变量后, 得到它
的地址. 如
int *ip; |
将 42
赋值给 x
, 将 x
的地址赋值给 ip
.
Using a pointer
使用 pointer 的方法是使用算符 *
, 它叫做 dereference operator. 它作用在一个指针
上, 得到的结果是它指向的内存地址中的值.
printf("%d %d\n", x, *ip); |
会输出 42 42
.
也可以
*ip = 37; |
此时, 这块内存中的值就变成了 37
.
Memory allocation and deallocation
一般来讲, 把一个指针指向一个已经声明的变量, 没什么用. 真正有用的是用它来分配一块 没有使用的内存. 这使得程序能够处理大量的内存.
基本的内存分配函数是
(void *) malloc(size_t numbytes); |
它的意思是分出一定数量的内存空间, 并返回一个指向它的指针. 由于 malloc 不知道你 想要什么类型的指针, 它返回的是 pointer to void, 也就是指向一块数据类型不明的区域.
常用的是把它和内置算符 sizeof()
放在一起用. sizeof()
返回特定数据类型的比特
数. 如
int *ip; |
这将分配出 1 个 int
大小的内存, 将其指针给 ip
.
Pointers and arrays
分配单个整型大小的内存没什么用, 有用的是 allocate arrays. 实际上, 指针可以当作一 个 array 用. 如
int *ip; |
Freeing memory, and memory leaks
如果有以下 code
int *ip; |
它没有金鼓齐鸣. 可以给一个指针重新赋值. 但是重新赋值之后, 之前分出的那 10 ints 的内存呢? 答案是它永远地消失了, 直到程序结束. 这叫内存(memory leak). 虽然这 10 ints 内存是被分配的, 但程序再也无法使用这些内存了.
解决方法是, 在 C 或者 C++ 中, 当被分配的内存用完后, 可以通过 free()
来释放内存.
如
ip = (int *) malloc( sizeof(int)*10 ); // allocate 10 ints |
上面的 code 就不会发生内存泄漏. 有一些语言 (如 Java) 会自动清理分配的内存, 这叫 automatic garbage collection , 但是 C 和 C++ 没有这种机制. 所以你在用完后, 应该 负责释放掉它们.
Pointers and arrays
pointers 可以用 array 的指标, 或者说, 一个数组的名字本质上就是一个 constant pointer.
int *p; |
指针和数组是不同的, 但是当指针被用来 access 一块区域时, 用法是一样的. 但是
the array declares a block of some datatype while a pointer only declares space for itself (the data area needs malloc'd)
数组会声明一块特定数据类型的区域, 而指针只会声明这块空间本身.
The address of the array (i.e., a pointer to it) is not stored anywhere; the compiler figures it out while it is compiling your program, so when you use the array name as a pointer, you are essentially using a constant number as an address.
数组的地址没有存在任何地方, 编译器编译的时候才搞清它. 所以将数组的名字当作指针 使用的时候, 本质上是将一个常数当作地址使用.
Pointers and arrays as arguments
有一个地方,指针和数组几乎是完全相同的, 那就是 当它们作为一个函数的参数的时候. 这 是因为 agruments pass only the address of the array to the function. 也就是说数 组作为指针传递.
在 C 中, 大部分值的传递方法是 call-by-value, 函数得到的是值的一个副本, 函数不会 改变原来的值. 但数组的传递方法是 call-by-reference, 传递的是指针, 而不是数组本 身.
如果传递数组时, 传递一个副本的话, 当数组非常大时, 那是非常浪费的. 所以数值的传递 方法是 call-by-reference. 这也意味着函数中对数组的修改, 会直接修改原来的数组.
因此, 下面的声明是等价的
int func(int A[]); |
How to dynamically allocate a 2D array in C?
有四种方法能够动态的给一个二维数组赋值. 比如
1 2 3 4 |
1. Using a single pointer
#include <stdio.h> |
2. Using an array of pointers
#include <stdio.h> |
3. Using pointer to a pointer
#include <stdio.h> |
4. Using double pointer and one malloc call
#include<stdio.h> |
Memory leak
下面的 code 可以演示内存泄漏
include <stdio.h> |
结果是几秒后内存就满了. 但是系统会有保护机制? 直接杀掉了进程(memoryleak.c makefile):