一、指针与数组的关系
其实,指针与数组变量并没有本质的区别,指针变量就是数组变量,而数组变量也是指针变量。为什么这么说呢?我们来看看面代码,定义一个数组array和一个指向这个数组首元素的地址的指针p,还有将数组变量直接赋值给了一个指针变量p1:
int array[4] = { 0, 1, 2, 3 };
int *p = &array[0];
int *p1 = array;
for (int i = 0; i < 4; i++)
{
printf("%d %d %d\n", array[i], p[i], p1[i]);
}
0 0 0
1 1 1
2 2 2
3 3 3
从运行结果中我们可以看到定义的指针和数组其实工并没有什么区别,这三个变量在内存中所处的位置如下
对于上面程序我们需要说明的是int *p = &array[0];表示的是将数组变量中的第一个元素的地址赋值给指针变量p,而int *p1 = array;的表示的是将数组变量的值赋值给p指针p21。这两个语句的结果都是一样的,这是因为在C语言中数组变量的值就是这个数组中第一个元素的地址,也就是这个数组的首地址。注意:array是一个地址,它表示的是这个数组的首地址,而&array[0]所表示的是这个数组的第一个元素所在的地址,也同样是这个数组的首地址,所以这两个地址的值是相同的。 而对于指针类型变量p和p1来说它们所表示的是一个地址,所以我们可以用取数组元素的方式来对这个指针做取数组元素操作例如p[0]、p[1]、[2]和p1[0]、p1[1]、p1[2]这样的语句都是合法的。同理,我们知道 & 符是对变量取地址,而 * 是对指针地址反取变量,所以*p就表示的是数组中第一个元素变量的值,例如*p的值为0。
二、指针的算数运算
在上面例子中我们已经知道了指针与数组的关系接下来我们来看一看指针的四则运算。指针变量与其它变量一样,也可以进行四则运算,但通常我们只对指针做加法和减法运算。例如我们可以将指针先指向一个数组,然后再对其做加法运算
char array[6] = "hello";
char *p = array;
printf("%c", *p);
printf("%c", *(p + 1));
printf("%c", *(p + 2));
printf("%c", *(p + 3));
printf("%c", *(p + 4));
hello
我们来分析一下上面例子中指针变量的运算过程,由于p是一个指针型变量,它指向了一个数组,也就是说p这个指针变量中存放了一个内存地址,这个地址就是数组array首个元素的地址,也就是array[0]的地址,对指针进行p+1操作时, p+1表示的也同样是一个指针,它指向数组中第二个变量array[1]。同理当执行p+2时,p+2也表示一个指针,它指向的是是array[2],p+3指向array[3]。p+4指向array[4]。因为它们都表示的是指针,所以我们可以对它们做取变量操作,也就是使用 * 来根据它们所指向的地址取出这些变量。上面程序还可以使用循环来实现:
char array[6] = "hello";
char *p = array;
for (int i = 0; i < 5; i++)
{
printf("%c", *(p + i));
}
hello
我们使用变量i来对指针做加法运算,然后再通过循环将其显示出来。我们现在再通过数组与指针在内存中的关系来看看这一过程:
同样的,我们也可以对指针p做++操作,从而达到指向下一个数组元素的目的。例如我们使用针指来实现一个字符串拷贝的功能:
char source[6] = "hello";
char target[6];
char *s = source;
char *t = target;
while (*s != '\0')
{
*t++ = *s++;
}
*t = '\0';
printf("%s\n", target);
hello
对于上面的例子我们一定要注意运算符的优先级,什么时候加小括号,什么时候不加括号。
注意:在C语言中对指针的加减实际上是对指针类型占用字节数的加减。也就是说,对于字符型指针的+1表示指针增加一个的字节的地址;而对于short型的指针+1表示增加2个字节的地址;对于int型的地址对其+1表示增加4个字节的地址等等。
另外,通常情况下我们只能对指针变量做加法和减法操作,而其它的运算是不可以用在指针变量上的,例如我们不能直接对指针变量做乘法和除法运算,但可以通过使用类型转换的办法将其转为一个整数,对其做完运算之后再将其转为指针变量。有兴趣的读者可以参见《C语言深处》
关于指针的减法与加法类似,这里不再赘述。
欢迎关注公众号:编程外星人