二维数组,字符串和指针
今天学习二维数组和指针之间的关系。
1.1 二维数组
二维数组是根据一维数组抽象出来的一个结构。定义方法int a[3][3]
就可以定义一个二维数组。关于二维数组,可以看作二维数组中保存着多个一维数组。这几个一维数组在地址上是连续的。以这个3x3的数组为例。
二维数组在内存中的分布如上图,可以将一个二维数组看作三个连续的一维数组所构成的。这样就可以可以很方便的来理解二维数组中某个元素所在的地址。下面这段简短的代码可以二维数组中某些元素和地址之间的关系。
#include <stdio.h>
int main()
{
int arr[3][3] = {0,1,2,0,1,2,0,1,2};
int *p = arr[0];
printf("address of arr[0][0] is %p\n", &arr[0][0]);
printf("address of arr[0] is %p\n", arr[0]);
printf("address of arr is %p\n", arr);
return 0;
}
从输出结果来看,第0个元素的地址就是二维数组的地址,同时也可以认位也是二维数组中第一个一维数组的地址。这样就很好理解了对于arr[3][3]
,有三个长度是3的一位数组组成。其中arr[0],arr[1],arr[2]
分别是着三个一维数组的地址。那么如何使指针指向的一个二维数组呢?
1.2 指针和二维数组
前面介绍到二维数组的名字也是一个地址,指针也是一个地址,但是通过下面这种方式对指针赋值却不能让这个指针指向这个二维数组。
int arr[2][2];
int *p;
p = arr;
原因是,使用这种方时,arr是二维数组的首地址,但是在赋值时,指针p,并知道这是二维数组。因此要使用如下的方式来定义一个指针并且使指针指向这个地址。
#include <stdio.h>
int main()
{
//声明一个二维数组并且初始化
int arr[3][3] = {0,1,2,3,4,5,6,7,8};
//声明一个指针,指针指向二维数组
int (*p)[3];
//对指针赋值
p = arr;
//通过指针遍历这个二维数组
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("arr[%d,%d] = %d\n", i, j, *(*(p + i)) + j);
}
}
return 0;
}
从上面的代码可以看出对于指向二维数组的指针,对其解引用后的结果任然是一个指针,这个指针所指向的内容是二维数组中一维数组的首地址,需要对解引用出来的结果再次解引用才能改变指向地址的内容。
2.1 字符串
字符串实际上是一个字符数组。
const char *s = "abcde";
char ss[]={'a','b','c','d','e','\0'};
上面所声明一个是字符串,一个是字符数组。两者在使用上相似,两者的内容都是abcde\0
但是两者在还是存在区别的。
char * s = "abcde"
这种方式,指针s所指向的内容是处于常量区的abcde。使用指针s不能对其内容进行修改。
#include<stdio.h>
int main(int argc, char const *argv[])
{
const char * s = "abcde";
char ss[] = {'a','b','c','d','e','\0'};
s[0] = 'w';
printf("content is %s\n",s);
printf("content of ss[] is %s\n", ss);
return 0;
}
上面提示信息就会给出指针s所指向的内容是只读的,位于常量区。对于字符数组ss[]来所就不存在这个问题,因为ss位于变量区,可以使用指针的方式来对其进行修改。
#include<stdio.h>
int main(int argc, char const *argv[])
{
const char * s = "abcde";
char ss[] = {'a','b','c','d','e','\0'};
ss[0] = 'W';
printf("content is %s\n",s);
printf("content of ss[] is %s\n", ss);
return 0;
}