复习主要以代码分析方式进行,对于一些概念一并略过:
1.
#include <stdio.h> int main( void ) { int x = 1; int y = 2; int z = 3; int *ip = 0; ip = &x; printf("%u,%d\n", ip, *ip); y = *ip; *ip = 0; printf("%u,%d,%d\n", ip, *ip, x ); ip = &z; printf("%u,%d\n", ip, *ip); return 0; }
程序输出:
注意ip地址和其值的变化,以及与之关联的x的变化。
对指针是变量的一个解释:
#include <stdio.h> int main( void ) { int x = 1; int *ip = 0; int *iq = 0; ip = &x; iq = ip; printf("ip:%u--%d\niq:%u--%d\n", ip, *ip, iq, *iq); return 0; }
程序输出:
经典的swap函数,解释C语言智能以传值方式给调用函数:
1. 错误定义的函数:
#include <stdio.h> void swap( int x, int y) { printf("&x:%u,&y:%u\n", &x, &y); int temp; temp = x; x = y; y = temp; } int main( void ) { int x = 1; int y = 2; printf("&x:%u,&y:%u\n", &x, &y); swap( x, y ); printf("&x:%u,&y:%u\n", &x, &y); return 0; }
所以,确实是传值,如果传址的话,函数内的&x应该和第一个&x相同。
但是我有个疑问,地址应该是4个字节的,类似第二行中&x和&y只相差4字节,而为什么主函数中却相差12个字节呢?
#include <stdio.h> int main( void ) { int x = 1; int y = 2; printf("&x:%u,&y:%u\n", &x, &y); printf("%d:%d:%d:%d\n", *(&y),*(&y+1),*(&y+2),*(&y+3)); return 0; }
我并不知道为什么会相差12,中间的8个字节明显是没利用起来,也许是编译器的优化,也许其他我不知道的原因。PS:这里是+1,+2,+3而不是+4,+8,+12,因为对地址的相加,它会自动根据其类型进行增加的,比如我们对int的地址+1,实际上是+4个字节(如果是64位系统,则不一定。)
现在明白既然C语言只能进行传值的话,那么我们还是直接把地址传进去,我们改变地址的值,也就是改变了两个变量的值了:
#include <stdio.h> void swap( int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; printf("%u--%u\n", px, py); } int main( void ) { int x = 1; int y = 2; printf("&x:%u--%d,&y:%u--%d\n", &x, x, &y, y); swap(&x, &y); printf("&x:%u--%d,&y:%u--%d\n", &x, x, &y, y); return 0; }
我们并未改变变量的地址,我们只是改变了该变量上的值而已。当然,有种改法也很简单,我们直接把x,y的地址互换不就行了吗?(PS:实际上是错误的,只是为了举例而已)
#include <stdio.h> void swap( int *px, int *py) { int *temp; temp = px; px = py; py = temp; printf("%u--%u\n", px, py); } int main( void ) { int x = 1; int y = 2; printf("&x:%u--%d,&y:%u--%d\n", &x, x, &y, y); swap(&x, &y); printf("&x:%u--%d,&y:%u--%d\n", &x, x, &y, y); return 0; }
地址确实变了,但为什么x,y的值没互换呢?还记得C语言只能传值吗?哈哈,有点绕,但至少我通过这个例子明白了C语言中只能传值的含义了。
2. 关于指针和数组
这个程序可以俏皮的说明指针和数组的关系:
#include <stdio.h> int main( void ) { int a[10]; int *pa = a; int i = 0; for ( i = 0; i < 10; i++ ){ a[ i ] = i; } for ( i = 0; i < 10; i++ ){ printf("%d ", pa[ i ]); } return 0; }
一个字符串长度的指针版本:
#include <stdio.h> int myStrlen1( char *s ) { int n; for ( n = 0; *s != '\0'; s++) n++; return n; } int myStrlen2( char *s ) { char *temp = s; while ( *temp != '\0' ) temp++; return temp - s; } int main( void ) { char *str1 = "hello world"; printf("%d\n", myStrlen1( str1 ) ); printf("%d\n", myStrlen2( str1 ) ); return 0; }
备注:这里极力不推荐写while (*temp++ != '\0').
3. 地址算数运算
我们来现场模拟一下一些字符串的指针实现形式:
备注:
1. 为避免一个程序过长,分开写。
2. char *str是字符串,不可更改,所以程序中声明为char str[].
#include <stdio.h> void myStrcpy(char *s, char *t) { while (*s++ = *t++ ) ; } int myStrcmp(char *s, char *t) { while ( *s == *t ){ s++; t++; } return *s - *t; } void myStrcat( char *s, char *t) { while (*s){ s++; } while ( *s++ = *t++ ) ; } int myStrend(char *s, char *t) { char *tempS = s; char *tempT = t; while (*s){ tempS = s; tempT = t; while (*tempS == *tempT){ tempS++; tempT++; } if ( *tempT == '\0' ){ return 1; } tempS++; s = tempS; } return 0; } int main( void ) { char str1[] = "hello world"; char str2[] = "i love this world"; char str3[] = "hello hello"; myStrcpy( str1, str2 ); printf("%s\n", str1 ); printf("%d\n",myStrcmp(str1, str3) ); myStrcat( str1, str3); printf("%s\n", str1 ); printf("%d\n",myStrend( str1, "world") ); printf("%d\n",myStrend( str1, "wworld") ); return 0; }
#include <stdio.h> void myStrncpy( char *s, char *t, int n ) { while ( n-- && ( *s++ = *t++ ) ) ; *s = '\0'; } void myStrncat( char *s, char *t, int n ) { while (*s){ s++; } while (n-- && ( *s++ = *t++ ) ) ; *s = '\0'; } int myStrncmp( char *s, char *t, int n ) { while ( n-- && ( *s == *t )){ s++; t++; } return *s - *t; } int main( void ) { char str1[] = "hello world"; char str2[] = "i love this world"; char str3[] = "hello hello"; myStrncpy( str1, "123456789", 5 ); printf("%s\n", str1 ); myStrncpy( str1, "123456789", 20 ); printf("%s\n", str1 ); myStrncat( str2, "123456789", 5); printf("%s\n", str2 ); myStrncat( str2, "123456789", 20); printf("%s\n", str2 ); printf("%d\n", myStrncmp( str3, "hello world", 5 )); printf("%d\n", myStrncmp( str3, "hello world", 8 )); return 0; }
4. 指针数组以及指向指针的指针
书上的例子不错,于是打算写下来测试一下:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXLINES 5000 char *lineptr[ MAXLINES ]; int readlines(char *lineptr[], int nlines ); void writelines( char *lineptr[], int nlines); void qsort(char *lineptr[], int left, int right); #define MAXLEN 1000 int getline(char *line, int len); int main(void) { int nlines; if ((nlines = readlines(lineptr, MAXLINES)) >= 0){ qsort(lineptr, 0, nlines - 1); writelines(lineptr, nlines); return 0; }else{ printf("error:input too big to sort\n"); return 1; } } int readlines(char *lineptr[], int maxlines) { int len, nlines; char *p, line[MAXLEN]; nlines = 0; while ((len = getline(line, MAXLEN)) >0){ if (nlines >= maxlines || (p = (char *)malloc(sizeof(char) * len)) == NULL){ return -1; }else{ line[len - 1] = '\0'; strcpy( p, line ); lineptr[nlines++] = p; } } return nlines; } void writelines(char *lineptr[], int nlines) { int i = 0; for ( i = 0; i < nlines; i++ ) printf("%s\n", lineptr[i]); } void qsort( char *v[], int left, int right) { int i, last; void swap(char *v[], int i, int j); if (left >= right) return; swap(v, left, (left + right) / 2); last = left; for (i = left + 1; i <= right; i++) if (strcmp(v[i], v[left]) < 0) swap(v, ++last, i); swap(v, left, last); qsort(v, left, last - 1); qsort(v, last + 1, right); } void swap( char *v[], int i, int j) { char *temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } int getline(char *line, int len) { fgets( line, len, stdin); return strlen(line); }
后面叫复杂的部分先不看。