1. 指针
指针包括两个方面的内容:
-
指针指向的对象,即指针变量的值,也就是数据对象存放的地址
-
指针的类型,指针的类型决定了该怎么去解释其指向的对象区域,同一片内存区域,按照不同的解释,其意义是完全不同
指针本身也是一个对象,也占据内存空间。
这是 The C Programming Language 里面的示意图,c is a char and p is a pointer that points to it.
分清楚指针与指针指向的对象意义重大。
有几个常见的错误。
错误1.没有为指针指向的对象分配内存
- char *str;
- gets(str); // 错误,没有为str分配内存, str指向垃圾数据
当定义一个指针变量char *str时,只是在栈上分配了str的空间,指针的值则是未定义的,也就是了垃圾。
下面的才是正确的:
- char *str;
- str = (char*)malloc(100);// 申请一片内存区,让str指向这片区域
- gets(str); // ok
事实上,上面的代码再作一个内存申请是否成功的检测:If( str != NULL ) 就更好了。
错误2. 野指针问题
指针使用完毕后,一般会free 释放其指向的内存区域,但释放完毕以后,此时指针的值是存在的,只不过是垃圾值。用 if( p != NULL ) 会返回真。
比较好的习惯是,free掉以后显式设置 p = NULL
错误3.同一片内存区域 多次释放
这类错误一般隐藏的比较深。尤其在C++里,呵。
比如
- char *p1 = (char*)malloc(100);
- char *p2 = p1; // 两个指针指向同一片内存区域
- free(p1);
- free(p2); // 错误!前一个语句已经释放内存;
- // 晕死,用MinGW测试这段代码居然没问题,靠
C++的指针比 C 语言的指针要复杂许多,因为有许多内存的自动申请与释放,还有继承关系,交叉在一起,头疼。
指针相加毫无意义,相减表示两个指针中间的元素个数。
指针占用空间:地址总线32位时,指针占四个字节。Int* p1;Char* p2;Char (*p3)[10];
Sizeof P1,p2,p3的大小会是一样的。但是其指向的对象迥异
2. 指针与数组
数组与指针是不同的。数组名对应着(不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。数组名是常量,因而不能修改。比如int m[10], m++是一个编译错误。定义一个指针n指向m第一个元素,int *n = m, 此时n++合法,表达式执行完毕后n指向数组第2个元素。另外,用sizeof(m) 与 sizeof(n) 会是完全不同的结果。sizeof(m)返回的是整个数组的长度,sizeof(n)则是指针的长度。
表达式a[i]会自动被转换成*(a+i)参与运算,因此使用指针形式并不会比数组形式更有效率。另外,&a[i]与a+i也是等价的。下标总是和指针的偏移量相同
将数组作为参数传到函数中时,数组形式与指针形式等价。数组名被编译器当作指向该数组第一个元素的指针。
Fun ( int *arr ){···}
fun ( int arr [] ){···}
fun ( int arr[10] ){···}//这里实参是多大的数组都可以
字符串常量初始化指针与数组(The C Programming Language P104)
There is an important difference between these definitions:
char amessage[] = "now is the time"; /* an array */
char *pmessage = "now is the time"; /* a pointer *
amessage is an array, just big enough to hold the sequence of characters and '/0' that initializes it. Individual characters within the array may be changed but amessage will always refer to the same storage. On the other hand, pmessage is a pointer, initialized to point to a string constant; the pointer may subsequently be modified to point elsewhere, but the result is undefined if you try to modify the string contents.
3. 数组指针与指针数组
数组指针:指向数组的指针
指针数组:指针构成的数组
char a[100];
char (*p)[100] = &a;
// 这里b就是一个数组指针,它指向整个数组,数组包含100个char
int matrix[3][10];
int (*mm)[10] = matrix;
// 这也是一个数组指针,指向matrix的第一行, 这个数组包含10个整形元素
典型的指针数组定义如下:
char *a[10]; // 数组,包含10个元素,每个元素都是指向char的指针
比如:
char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
(The C Programming Language P112)
The parentheses are necessary since brackets [] have higher precedence than *. Without parentheses, the declaration int *daytab[13] is an array of 13 pointers to integers.
4. 指针数组与二维数组(The C Programming Language P114)
char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };
5. 函数指针
int *p1();
int (*p2)();
p1是一个函数,它返回一个指向int* 型数据的指针。
p2是一个函数指针,它指向一个参数为空的函数,这个函数返回一个整数数据
(The C Programming Language P120)
int (*comp)(void *, void *)
which says that comp is a pointer to a function that has two void * arguments and returns an int.
The use of comp in the line
if ((*comp)(v[i], v[left]) < 0)
is consistent with the declaration: comp is a pointer to a function, *comp is the function, and
(*comp)(v[i], v[left])
is the call to it. The parentheses are needed so the components are correctly associated; without them,
int *comp(void *, void *) /* WRONG */
says that comp is a function returning a pointer to an int, which is very different.