有一个这样的错误:

在一个文件中定义:int mango[100]; 

在另一个文件中声明:extern int *mango; 

将会产生错误

定义和声明的区别:

在C中,任何对象都有且只有一个定义,但是可以有多个声明

  • definition:只出现一次    为一个对象指定类型,分配存储空间。用于创建一个新的对象
  • declaration:可以出现多次    描述这个对象的类型。用于引用某个已经定义了的对象

所以数组的定义需要指定大小,声明不需要。但是对于多维数组,需要在声明的时候指定除最左侧维度的其他维度的大小,这样编译器才知道怎么解析下标

地址y和地址y的内容:

虽然在大多数语言中二者使用相同的符号表示,但是二者有不同的含义

以一个赋值语句为例:x=y

  • 符号x:在这条语句中表示的是x这个符号代表的内存地址,这个地址被称为左值。左值在编译期间确定,指明存储值的位置
  • 符号y:在这个语句中表示的是y代表的地址的内容,这个内容被称为右值。右值直到运行期间才可以确定,"y的值"表示右值

"可修改左值"是C引进的术语

  • 表示一个左值可以放到一个赋值语句左侧(并不意味之左值本身代表的地址值可以被改变)
  • 这个概念为了兼顾数组名,数组名是一个指明对象位置的左值,但在C中不能被赋值,所以数组名是左值但不是可修改左值

编译器会为x和y都分配一个地址空间,也就是左值。这两个左值在编译期间确定,并用于在运行期间存放变量

但是这两个左值中存放的值只有在运行期间才可以确定,当需要用到存储在变量中的值的时候,编译器执行命令获取存储在地址空间中的值放到寄存器中

关键的区别在于:

因为编译期间就可以确定每个符号,所以如果编译器想要对某个地址(左值)进行操作就可以直接去做而不用执行指令去获取这个地址

而一个指针的值(右值)只有在运行期间才可以知道并被解引用

指针中存放的地址可以随便更改,地址指向的存储空间中的值也可以随便更改,但是数组的存储位置在程序运行期间不会改变,即便存储的值会变

所以声明一个数组和声明一个指针的区别在于指针需要在运行期间使用额外的指令去获取指针中存放的值,而数组是编译器已经知道的

错误的原因:

定义是数组,所以mango代表的地址空间以及之后的一片空间都直接存放的是char字符

引用是指针,编译器执行指针的解析方式:获取mango代表的地址空间,获取它里面存放的值,然后把这个值当作地址并加上偏移之后获取对应位置的值

但是实际上mango代表的地址空间中的值是一个ASCII字符,编译器解析为指针就会产生错误

正确的方式:

file 1: 

int mango[100]; 

file 2: 

extern int mango[];

字面量初始化:

数组和指针都可以用一个字面量初始化,但是二者的效果完全不同

指针定义时只会申请一个空间存放地址值而不会为初始化的值申请空间。ANSI标准规定用字面量初始化的指针是只读的,通过指针进行的更改是未定义的。一些编译器会把字面量放到程序的文本段中,那里的数据是受只读权限保护的、

但是数组会为字面量申请空间并存放,所以对它的修改是合法的

实际使用时的数组和指针:

当正常声明一个数组的时候,会发现编译器为这个数组分配的空间正好是数组元素占用的空间,不会为数组名分配有额外的空间

如果声明一个N维数组,你会发现所有维的第一个元素都指向分配的第一个内存地址

如果尝试对数组名进行取地址操作,那么你仍将得到分配的第一个内存地址。但是这个地址中存放的值其实是数组的第一个元素,而不是数组名代表的一个地址类型的值。所以并不会有一个内存地址(开发者可见的,当然编译器会为自己记录一下符号表之类的值)中存放着数组名,也就是数组名只是被编译器维护在符号表中的,而不存在一个实际的变量。编译器在维护的时候将它的地址和它的值都设置为分配的第一个内存地址。

所以,显然的,数组名不能被当作左值,任何将数组名当作左值的操作都会使编译器发出非左值的error

但是如果是一个指针,无论是通过将现有的数组赋给它还是动态申请内存来为它赋值,它本身都有一个实实在在的内存空间用于维护自身,所以它可以作为左值

函数传数组:

编译器在编译的时候会为参数和返回值申请栈空间

所以实际上是有实在的空间存储参数的

在向函数传递数组参数的时候,会向变量中实际传递这个数组名代表的值,因而这个参数占有实际的存储空间,这就成为一个指针了,所以这里的“数组名”将可以作为左值

这也是合理的,函数维护这个变量到底是一个数组还是一个指针将会花费额外的精力,在为参数申请栈空间的时候也要分情况考虑,如果使用一个指针,这将简单的多

但是编译器只会进行一重这样的退化,当参数是多维数组时,函数实际得到的是指向维数少一的数组的指针

这个指针的类型就是数组元素类型的指针,但是在获取它的大小的时候会有一个warring:

warning: 'sizeof' on array function parameter 'a' will return size of 'const double *' [-Wsizeof-array-argument]

到底还是一个指针

动态分配的数组就不会具有这样的性质,因为它们毕竟还是指针,每一重都会多占用一部分内存地址用于存放指针,但是数组就不会

C语言数组和指针是不同的的更多相关文章

  1. C语言 > 数组和指针

    C语言 数组和指针 const: 关于指针和const需要注意一些规则.首先,把const数据或非const数据的地址初始化为指向const的指针或为其赋值是合法的. 然而,只能把非const数据的地 ...

  2. C语言数组和指针的理解_在取地址运算上的操作_指针加减操作_a 和&a 的区别

    1.一个实例+理论分析 在了解数组和指针的访问方式前提下,下面再看这个例子: main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); pr ...

  3. 深入解析C语言数组和指针

    概述 指针是C语言的重点,同时也是让初学者认为最难理解的部分.有人说它是C语言的灵魂,只有深入理解指针才能说理解了C语言.暂且撇开这些观点不谈.这章是我在阅读<C和指针>这本书的读书笔记. ...

  4. C语言数组与指针总结

    寒假要开始猛刷<剑指offer>,先回顾一下C语言基础做个热身. 指针 相信大家对下面的代码不陌生: ; int *p; p=&i; 这是最简单的指针应用,也是最基本的用法.再来熟 ...

  5. (C语言)数组与指针的区别

    以前常常听过这种说法,说数组和指针这两者比较像,但是不能混淆,可是一直没能理解.刚刚在李云的<专业嵌入式软件开发>中,看了讲述数组与指针区别的一章,似乎有所领悟.本着知乎上看到的这张图,我 ...

  6. (转载)C语言 数组与指针的区别

    1) 字符串指针变量是个变量,指向字符串的首地址:而字符串数组名是个常量,为字符串数组第一个元素的地址: 2)字符串指针变量可以赋值,而字符串数组名不能赋值:对于字符数组只能对各个元素赋值,不能用以下 ...

  7. C语言-数组与指针 字符与字符串

    1 字符与字符串:char c='a'而不能写出char c="a" //字符变量用单引号'',而字符串用双引号. 2 字符数组与字符指针的初始化: char s[10]={0}, ...

  8. c语言-数组、指针面试题

    转载 说明:所有题目均摘录于网络以及我所见过的面试题目,欢迎补充! 无特殊说明情况下,下面所有题s目都是linux下的32位C程序. 先来几个简单的热热身. 1.计算以下sizeof的值. char ...

  9. C语言数组,指针小案例

    /* ============================================================================ Name : hello.c Autho ...

随机推荐

  1. Java并发--安全发布对象

    单例模式 懒汉模式:多线程非线程安全,在多线程中,可能会产生多个对象 饿汉模式:线程安全. 类加载的时候初始化,不推荐在构造函数需要做耗时操作的时候使用,因为可能导致类加载缓慢,而且可能初始化后并没有 ...

  2. Ubuntu18.04解决鼠标移动到Gnome顶栏左上角窗口不能平铺( Activites Overview 界面),和应用程序扩展不好用问题。

    在用习惯了GNOME我们知道一个很好的功能就是通过鼠标移动到Gnome顶栏左上角后所有打开的窗口就会平铺在显示器上方便我们选不同的窗口(Activites Overview 界面),苹果MAC系统也有 ...

  3. Codeforces Round #506 (Div. 3) A-C

    CF比赛题解(简单题) 简单题是指自己在比赛期间做出来了 A. Many Equal Substrings 题意 给个字符串t,构造一个字符串s,使得s中t出现k次;s的长度最短 如t="c ...

  4. 使用easyui combobox初始化+在input中触发下拉框+获取值

    效果图: 1.html <input id="alarmLeve" class="easyui-combobox" name="alarmLev ...

  5. ntp.log日志梳理

    [日志]offset 正负 机器A上执行: remote refid st t when poll reach delay offset jitter ======================== ...

  6. G700存储配置

    首先在G700上创建RAID组,这次选择的是SSD做RAID5,SAS磁盘做的是RAID10,把空闲的物理磁盘加入RAID组内,把已分配给RAID组的物理磁盘全部加在一次资源池里面pool 创建主机组 ...

  7. mysql局域网服务搭建

    首先配置电脑Mysql环境变量 新建 Mysql服务配置 CMD >命令 : mysql -u root -p 4. 创建用户 Mysql 用户权限分配 5 重启服务 如果还不能访问就一定是你的 ...

  8. java判断输入的数字的位数_数字问题

    import java.util.Scanner;public class Numbers { public void Judgy(int n){ for(int i=0;i<100;i++){ ...

  9. 排序代码(python,c++) 及 基本算法复杂度

    0.导语 本节为手撕代码系列之第一弹,主要来手撕排序算法,主要包括以下几大排序算法: 直接插入排序 冒泡排序 选择排序 快速排序 希尔排序 堆排序 归并排序 1.直接插入排序 [算法思想] 每一步将一 ...

  10. Java并发和多线程2:3种方式实现数组求和

    本篇演示3个数组求和的例子. 例子1:单线程例子2:多线程,同步求和(如果没有计算完成,会阻塞)例子3:多线程,异步求和(先累加已经完成的计算结果) 例子1-代码 package cn.fansuni ...