初识数组与指针

来源:互联网 发布:阿里云2m带宽并发数 编辑:程序博客网 时间:2024/06/07 00:26

一,数组

数组是C语言中一种复合(构造)数据类型,是相同数据类型的一个集合我们可以把它看作是一个类型的所有数据的一个集合,并用一个数组下标来区分或指定每一个数。

eg:

int a[10]; 说明整型数组a,有10个元素。

float b[10],c[20]; 说明实型数组b,有10个元素,实型数组c,有20个元素。

char ch[20]; 说明字符数组ch,有20个元素。

eg:用for循环将数组初始化为1 2 3 4 5 6 7 8......

int main(){int arr[N];for(int i = 0;i < N;i++){arr[i] = i;}}
注:数组名a作为右值时,代表数组首元素的首地址,a不可作为左值。

C/C++中数组是内置的数据类型,但不是基础数据类型而是构造数据类型,语义上是有限个占据连续物理空间的相同数据元素的有序集合。C/C++数组在语言特性上的支持很简单,对应定义的形式T[n] a = {初始化列表};,实际进行的是分配sizeof(T)*n字节的空间,然后使这些空间内的值等于初始化列表中的值而已。分配的空间的回收是隐式的(对于自动变量是在函数结尾,对于静态变量是在进程结束),不需语言使用者干预。动态的线性表或者称为动态数组的数据结构不被C/C++语言特性直接支持,一般通过指针+长度手动调用库函数分配/释放空间,但同样可以通过[]运算符来实现引用其中的元素。对于[],如果不考虑重载,a[x]等价于*(a+x),其中a作为地址,而x是整数偏移量,实质工作(寻址)交给CPU完成。

在定义数组时,如果数组的元素个数不知道的话,只能通过动态内存分配了,静态内存分配是没有办法实现的,因为静态内存分配在定义数组的时候必须指定数组的大小为一个常量或者常数,例如:
int array[10];
或者
const int Size=10;
int array[Size];点击打开链接

二,数组逆置

eg:1.....100的整数逆序输出

#include<stdio.h>void fun(int a[], int n){int i, temp;for (i = 0; i <= n / 2 - 1; i++){temp = a[i];a[i] = a[n - i - 1];a[n - i - 1] = temp;}}int main(){int a[100], i;int n = 100;for (i = 0; i < n; i++){a[i] = i;}fun(a, n);for (i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");return 0;}

,指针

指针是一个地址

eg:int a = 10;
int *p = &a;
*p = 20;

有两种含义,一是作为数据类型,二是作为实体。 

指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量。指针一般出现在比较底层的程序设计语言中,如C语言。高层的语言如Java一般避免用指针,而是引用。
#include <stdio.h>main(){char *pT;char t='h';pT=&t;putchar(*pT);}

 
指针作为数据类型,可以从一个函数类型、一个对象类型或者一个不完备类型中导出。从中导出的数据类型称之为被引用类型(referenced type)。指针类型描述了一种对象,其值为对被引用类型的实体的引用。

,指针与数组的联系与区别

指针数组:就是一个由指针组成的数组,那个数组的各个元素都是指针,指向某个内存地址。 char *p[10];//p是一个指针数组
数组指针:数组名本身就是一个指针,指向数组的首地址。注意这是一个常数。
指针数组,顾名思义,就是说的首先是一个数组吧,然后数组的元素是指针而已。说明形式为:type *pointer_array[constant1][constant2]...[constantn]; 例如:int *pai[4]; 由于‘*’是自右向左结合,因此从右向左看,首先看到[4]说明是一个数组,是一个包含4个元素的数组,然后看到‘*’,显然是指针类型,由此可以看出数组中存放的是指针而不是一般的类型。同理,char *pac[2][3]是包含有6个元素,每一个元素都是一个字符型指针。再来说说他们的初始化: int *pai[3];既然是一个包含4个整形指针的数组那么其对应的将是一个二维整形数组,因为一个整形指针对应一个一维整形数组。那我就用一个二维整形数组来初始化它,事实上一般也都是这么做的,这里有一个二维数组,int arr[3][2]={{1,2},{3,4},{5,6}},一个三行两列的整形数组,注意这里的行必须和你的指针数组的维数一致,否则是不允许的
数组指针:指向一个数组的指针。说明形式为:type (*pointer_array)[constant1][constant2]...[constantn]; 注意这里的圆括号是必须就将这是由于方括号[],较指针说明符“*”的优先级高,若无此圆括号,编译器将把上述说明解释成成了一个数组指针。例如:int (*ap)[2]; 这样就说明了一个指向包含有2个元素的整形数组的数组指针,听起来确实有点别扭。不过仔细分析应该还是能理解的,就是说ap是一个指针,而它指向的对象是一个指针,注意不要将它和一个指向一个整形变量的指针搞混了。同样以一个二维数组来说明其初始化问题, int arr[3][2]={{1,2},{3,4},{5,6}};注意这里的列数必须和数组指针所指的数组的列数相同。
★相同点:
●都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
★不同点:
●指针是一个实体,而引用仅是个别名;
●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
●引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有 的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)
●引用不能为空,指针可以为空;
●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
●指针和引用的自增(++)运算意义不一样;
●引用是类型安全的,而指针不是(引用比指针多了类型检查)

五,预防野指针的方法

野指针,又称迷途指针,即指向“垃圾”内存的指针。此时指针指向的内存已被操作系统回收,程序已无法再访问。

       野指针,不是NULL指针,而是看上去指向合法内存,却在实际上该内存已经释放。

1.声明指针时,记得初始化

eg:char* p=NULL; 

2.当指针没有使用价值时,记得释放,释放成功后记得为该指针赋值NULL。

eg:

  1. if(NULL != P)  
  2. {  
  3.     delete p;  
  4.     p = NULL;  
  5. }  

3.如果指针作为函数的输入参数时,在引用参数前首先对指针进行参数检查。

      在函数的入口处使用assert(NULL != p)对参数进行检验,或者用if(NULL != p)来检验。它会提醒指针没有初始化,起到定位错误的功能。assert是一个宏,后面括号里的条件若不满足,则程序会终止运行并提示出错位置。使用完指针后,务必释放该指针所指向的内存。

4.尽量使用引用替代指针。

       引用具有指针的功能,同时它还有普通变量的功能。引用对应的变量务必真实存在。引用作为函数的输入参数具有比指针更直接的视觉效果。例如,swap函数的指针实现和引用实现。

5.使用智能指针,避免野指针。

六,sizeof(arr)/sizeof(arr[0])代表什么?

sizeof函数是求对象空间大小的函数。
arry是整个数组,arry[0]是数组中第一个元素

( sizeof(a) / sizeof(a[0]) )代表数组的维数,即计算数组名为a的数组的大小,如果不存在数组名为a的数组就会出错




原创粉丝点击