C语言指针与数组程序员
数组的下标应该从0仍是1开始? 我提议的妥协方案是0.5,惋惜他们未予认真考虑便一口回绝 -- Stan Kelly-Bootle
1. 数组并不是指针
为何不少人会认为指针和数组始终应该能够互换的呢? 由于对数组的引用老是能够写成对指针的引用,并且确实存在一种指针和数组的定义彻底相同的上下文环境,
不幸的是,这只是数组的一种极为普通的用法,并不是所用状况下都是如此。
2. 什么是声明,什么是定义
C语言中对象必须有且只有一个定义,但它能够有多个extern声明.
定义:只能出如今一个地方,
肯定对象的类型并分配内存,用于建立新的对象,例如 int a[100]
声明:能够屡次出现,描述对象的类型,用于指代其余地方定义的对象(例如在其余文件里) 例如 extern int a[100]
extern对象声明告诉编译器对象的类型和名字,对象的内存分配则在别处进行
3. 数组与指针的区别
出如今赋值左边的符号被称为 左值, 出如今赋值右边的符号被称为 右值。
编译器为每一个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址中。
存储于变量中的值(右值)只有在运行时才可知,若是须要用到变量中存储的值,编译器就发出指令从指定地址读入变量并将它存于寄存器中。
例如: char a[9] = "abcdefgh"; c = a[i]
假设编译器符号表具备一个地址9980
运行时步骤1:取 i 的值,将它与 9980 相加 (基址加偏移量)
运行时步骤2:取地址 [9980+i] 的内容
例如:char* p; c = *p;
假设编译器符号表有一个符号p,它的地址为4624
运行时步骤1:取地址 4624 的内容,假设是 1024
运行时步骤2:取地址1024的内容
例如:char* p = "abcdefgh" c = p[i]
假设编译器符号表有一个p,地址为 4624
运行时步骤1:取地址4624的内容,假设是 1024
运行时步骤2:取得 i 的值,并将它与 1024 相加 (基址加偏移量)
运行时步骤3:取地址 [1024+i] 的内容
指针 |
数组 |
保存数组的地址 |
保存数据 |
间接访问数据,首先取指针的内容,把它做为地址,而后从这个地址提取数据。数组 若是指针有一个下标[i],就把指针的内容 加上i做为地址,从中提取数据 数据结构 |
直接访问数据 a[i]只是简单的以a+i做为地址取数据 |
一般用于动态数据结构 |
一般用于存储数目固定且数据类型相同的元素 |
相关的函数为 malloc free |
隐式分配和删除 |
一般指向匿名数据 |
自身即为数据名 |
定义指针时,编译器没有为指针所指向的对象分配空间,只是分配指针自己的空间
ANSI C中,初始化指针时所建立的字符串常量所定义为 只读。在有些编译器中,字符串常量被存放在只容许读取的文本段中,以防止它被修改
char* ptr = "hello world" // 这种写法是很是不推荐的,由于
ptr 所指对象是只读的,这将隐式的将 const 转 non-const,任何对 ptr 的修改都会 coredump
const char* ptr = "hello world" // 这种写法明确表示 ptr 的const属性,这时对 ptr 所指对象的修改都会
在编译时报错
char a[] = "hello world" //这种写法代表 数组中元素都是可修改的,可是
数组名是不可修改的左值,即数组首地址不能够改变,是常量
4. 何时数组与指针相同
全部做为函数参数的数组名能够经过编译器转换为指针
数组的声明就是数组,指针的声明就是指针,二者不能混淆
注意:若是定义一个数组,在其余文件中对它extern声明时也必须把它声明为数组,指针也是如此
在使用数组(在语句或表达式中引用)时,数组老是能够写成指针的形式
数组下标表达式老是能够改写成带偏移量的指针表达式
何时数组和指针是相同的:
规则1:表达式中的数组名(与声明不一样)被编译器看成一个指向该数组第一个元素的指针 (具体见 ANSI C标准 第6.2.2.1 节)
规则2:下标老是与指针的偏移量相同(具体见ANSI C标准 第6.3.2.1 节)
规则3:在函数参数的声明中,数组名被编译器看成指向该数组第一个元素的指针(具体见ANSI C标准 第6.7.1 节)
其实规则1和规则1合起来理解以下:对数组下标的引用老是写成"一个指向数组的起始地址的指针加上偏移量"
对数组的引用如a[i]在编译时老是被编译器改写成*(a+i)指针访问的形式
"做为函数参数的数组名"等同于指针
void func(int* arg);
void func(int arg[10]);
void func(int arg[]);
上述三种形式是彻底等同的
5. 为何C语言把数组形参看成指针
把做为形参的数组和指针等同起来是出于效率缘由的考虑
在C语言中,全部非数组形式的数据实参均以传值形式(对实参作一份拷贝并传递给调用的函数,函数不能修改做为实参的实际变量的值,而只能修改传递给它的那份拷贝)调用
C语言容许程序员把形参声明为数组(程序员打算传递给函数的东西)或者指针(函数实际所接收到的东西)
无论程序员实际所写的是哪一种形式,函数并不自动知道指针所指数组共有多少个元素,因此必须有个约定,如数组以NULL结尾或者另外一个附加的参数表示数组的范围
能够经过向函数传递一个指向数组第一个元素的指针来访问整个数组,但也可让指针指向任何一个元素,这样传递给函数的就是从该元素以后的数组片断