数组和指针


一、一维数组的创建

类型符 数组名 [常量表达式]:       int  arr[i]-----arr和i是[]的两个操作数

       
   注意 1.数组在内存中是连续存放的,地址由低到高
   2.数组的初始化若只给定部分值,则未赋值部分初始化为0(字符型数组初始化为\0,指针型数组初始化为NULL)
   3.若为arr[10]={0}则剩余部分自动给0;若为int arr[0];(数组的定义并未初始化,值为随机值)
   4.数组初始化为字符串时可写为 int arr[] = { 'a', 'b', 'c' };和int arr2[] = "abc";arr2中包含'\0' 
  5.C语言不允许对数组大小进行动态定义,但如果在被调用的函数(不包含主函数)中定义数组,其长度可以是变量或非常量表达式

              eg:①动态定义(错误)
int n=10;
scanf( "%d" , &n);
int a[n]; //错误 数组的大小不能是变量
②实参定义(视情况而定)
在gcc中编译正确,在vs中编译错误,具体取决于编译器
void fun( int n )
{
    int a[2* n ];
}
int main()
{
    int n=10;
   fun(n);
   return 0 ;
        }
       ③指定数组为静态(static)存储方式
        static int a[2*n];//不合法


二、一维数组的指针访问

数组名的值是一个指针 常量,指向数组首元素地址;
只有两种情况下,数组名表示的是数组的地址(1.数组名作为sizeof操作符 2.数组名作为单目运算符&的操作数时)
数组和指针的属性大相径庭,当声明一个数组时,同时也为数组分配了一些内存空间,用于容纳数组元素,但当声明一个指针时,它只分配了用于容纳指针本身的空间

1.下标引用和指针
  (1)   *(b+3)//b是一个整型指针,3这个值根据整型的长度进行调整,等价于a[3]
  (2) 一个有趣的题:2[arr] 是合法的,如何理解呢?
           根据上面所述2[arr]等价于*(2+arr)而根据加法交换律可等价于*(arr+2),所以2[arr]等价于arr[2]是合法的
三、二维数组的创建

类型符 数组名 [常量表达式][常量表达式]
二维数组的定义: char arr[3][4]
二维数组的初始化: int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
int arr[3][2] = { { 1, 2 }, {3,4} ,{ 5, 6 } };
int arr[][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; //行可省,列不可省
int arr[3][4] = { { 1, 2, 3 }, { 4, 5, 6 } };  //其他自动赋为0: 1,2,3,0
                                        //  4,5,6,0
                                        //  0,0,0,0
二维数组在内存中也是连续存放的

arr(4,3)在许多语言中,多重下标用逗号分隔的值列表形式。有些语言这两种形式都允许,
但C语言中逗号表达式首先对第一个表达式求职随机丢弃这个值,最后结果是第二个表达式的值,
因此arr[4,3]等价于arr[3]不能用于表示二维数组arr[4][3]

四、二维数组的指针访问


int arr[10];
int *p = arr;  //合法
int arr1[3][10];
int *mp = arr1; //非法
第一个声明是合法的,它是一个整型数组分配内存,并把p声明为一个指向整型的指针
第二个声明是非法的,它正确的创建了数组arr1,并把mp声明 为一个指向整型的指针,
         但arr1并不是一个指向整型的指针,而是一个指向整型数组的指针。

      int i = 0;
     int arr[2][3] = { { 1, 2, 3 }, { 4, 5 } };
     int *p = &arr[0][0];  //用一维指针访问二维数组
      for (i = 0; i < 15; i++)
      {
        printf("%d",*(p+i));
      }
五、指向数组的指针

int (*p)[10];
下标引用操作符[]优先级高于解引用操作符*,但该表达式内有小括号,因此先对指针p执行解引用操作,得到一个整型数组,再对整型数组进行下标引用操作,得到一个整型值。
所以p是一个指向整型数组的指针。

int arr[2][2] = { { 1, 2 }, {3,4} };
int(*p)[2]=arr; 
p是一个指向一个拥有2个整型数组的指针,当给p加上一个数时,该整数值首先根据两个整型值得长度进行调整(p一行一行移动)

int *pi =&arr[0][0];
int *pi =arr[0];
两个指针均指向二维数组第一行的首元素(p一个元素一个元素移动)

int (*p)[]= arr;
如果用指针进行运算,应避免此写法,此写法p仍指向整型数组,但数组没有定义长度,运算时无法调整,易出错

六、未初始化和非法的指针


int *a;
···
*a=12;
该代码段说明了一个极为常见的错误: 野指针!
这个声明创建一个指针变量a,赋值语句把12存储在a指向的内存位置,a并未初始化,a所指向的内存位置未知,
赋值为12很有可能将原本在a所指内存空间的值覆盖掉,引起其他程序段出错;或者a指向一个非法空间,赋值语句出错,中断程序,这种错误在UNIX系统上称为“段违例”或“内存错误”;
或者该存储在错误的边界上,这种错误在UNIX系统上称为“总线错误”

综上,因此在使用指针过程中,一定要对指针进行初始化操作,避免不必要的错误!!!
另外对空指针NULL进行解引用操作是违法的,但有的编译器无法识别错误,因此在对指针进行解引用操作时,都要保证指针不为空。

*&a  //将值25赋给变量a,相当于a=25,但该方法过于冗杂,应避免这种写法的出现

*100=25 //该写法明显错误
想要将25赋给地址为100的空间,应采用强制类型转换的方式表达式如下:
*(int *)100=25;
但一般情况下地址都是未知的,这种写法一般用于访问设备控制器接口,此时这些地址是已知的


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值