K&R Chapter 5. Pointers and Arrays

《5.1 Pointers and Addresses》

*ip += 1 将ip指向的内容加1,等同于 ++*ip(*ip)++,其中 (*ip)++ 的括号是必须的,因为*和++都是由右往左联合

《5.2 Pointers and Function Argument》

C使用按值传递的方式传递参数给函数。被调用函数 the called function 无法通过直接的方式改变调用函数 the calling function 的变量。

《5.3 Pointers and Arrays》

假设int a[10]和int *pa,pa = &a[O],则pa和a的值一样。
因为数组的名字是最初的元素位置的同义词,所以pa = &a[O]可以写成pa = a

a[i]可以写成(a+i),**C会间接将a[i]转化为`(a+i)**。&a[i]等同于a+i。简单来讲, **array-and-index 的表达式等价于写成 a pointer and offset 的表达式**。[]优先级高于,X[ii][j]等价于((X+ii))[j]但不等价于*(X+ii)[j]`。

指针和数组名的区别:指针是变量,pa=a和pa++是合法的;数组名不是变量,a=pa和a++是不合法的。传递一个数组名给函数时,传递的是首元素的位置,对被调用函数而言,该函数参数就是一个指针,一个包含地址的变量。

int a[5]={1,2,3,4,5};int *ptr=(int *)(&a+1); 数组名就是数组0号元素的地址,a = &a[0]。&a是指向一个有5个整型元素的数组的地址,int *ptr=(int*)(&a+1) => int *ptr=(int*)(a地址 + sizeof(a));sizeof(a) = 5*sizeof(int)。而printf("%p\n", iArry);printf("%p\n", &iArry);输出的地址值是一致的,这说明底层实现并没有为二级指针创建临时变量什么的,而只是在计算一级指针和二级指针的方式上有所区别。

《5.4 Address Arithmetic》

指针和整数不能互换,0则是特例,指针可被赋值0,也可以和0作比较。C保证 0 永远不会是数据的合法地址,可以通过返回 0 (函数返回值为指针类型)来标识异常事件。符号常量NULL定义于stdio.h,代表一个指针的特殊值,经常用于代替0。

当两个指针指向不同的数组时,指针之间的运算或比较是未定义的。但存在一个特例:超出数组末端的第一个元素的地址可以用于指针运算,如:int array[10]; int* a = array + 10;

指针减法:指向相同数组的两个指针p和q,如果p < q,q-p+1将返回从p到q的元素个数。

《5.5 Character Pointers and Functions》

strcpy函数的实现:

1
2
3
4
5
6
7
8
9
array版本
/* strcpy: copy t to s; array subscript version */
void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((s[i] = t[i]) != '\0')
i++;
}

1
2
3
4
5
6
7
8
9
pointers版本1
/* strcpy: copy t to s; pointer version 1 */
void strcpy(char *s, char *t)
{
while ((*s = *t) != '\0') {
s++;
t++;
}
}
1
2
3
4
5
6
7
pointers版本2
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
{
while (( *s++ = *t++) != '\0' )
;
}
1
2
3
4
5
6
7
pointers版本3
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

strcmp函数的实现:

1
2
3
4
5
6
7
8
9
10
array版本
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
int i;
for (i = 0; s[i] == t[i]; i++)
if (s[i] == '\0')
return 0;
return s[i] - t[i];
}

1
2
3
4
5
6
7
8
9
pointers版本
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0' )
return 0;
return *s - *t;
}

练习

练习5-3:实现strcat(s,t)函数(Chapters 2)的指针版本,将字符串t复制到s的末端。

1
2
3
while(*s++); /* Get to the end of the string */
s--; /*get back to the end of the string.*/
while((*s++ = *t++));

练习5-4:实现strend(s,t)函数,如果字符串t出现在s的末端,返回1,否则返回0。

1
2
3
4
5
6
7
8
9
10
11
12
int strend(char *s, char *t)
{
char *sc = s;
char *tc = t;

while (*s != '\0')
s++;
while (*t != '\0')
t++;
while (s > sc && t > tc && *s-- == *t--) ;
return (t == tc && *s == *t ? 1 : 0);
}

练习5-5:实现strncpy(s,t,n)、strncat(s,t,n)、strncmp(s,t,n)函数,至多操作参数字符串的前n个字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
char *_strncpy(char *s, const char *ct, size_t n) {
char *p;

p = s;
for (; n > 0 && *ct != '\0'; --n)
*p++ = *ct++;
for (; n > 0; --n)
*p++ = '\0';
return s;
}
char *_strncat(char *s, const char *ct, size_t n) {
char *p;

p = s;
while (*p != '\0')
++p;
for (; n > 0 && *ct != '\0'; --n)
*p++ = *ct++;
*p = '\0';
return s;
}
//库函数strncmp("a", "b",0)会返回0
int _strncmp(char *s, char *t,int n)
{
for ( ; n>0 && *s == *t; s++, t++,n--)
if (*s == '\0' )
return 0;
if(n==0 ) return 0;
return *s - *t;
}

显示 Gitment 评论