全球要闻:C语言基础知识入门 C语言的具体结构
一、C语言基础知识入门
C语言一经出现就以其功能丰富、表达能力强、灵活方便、应用面广等特点迅速在全世界普及和推广。C语言不但执行效率高而且可移植性好,可以用来开发应用软件、驱动、操作系统等。C语言也是其它众多高级语言的鼻祖语言,所以说学习C语言是进入编程世界的必修课!
【资料图】
需 要 PDF版 和 详 细 教 程 的可以看一下文章结尾
二、C语言的具体结构
简单来说,一个C程序就是由若干头文件和函数组成。
#include就是一条预处理命令, 它的作用是通知C语言编译系统在对C程序进行正式编译之前需做一些预处理工作。
函数就是实现代码逻辑的一个小的单元。
三、主函数
一个C程序有且只有一个主函数,即main函数。
C程序就是执行主函数里的代码,也可以说这个主函数就是C语言中的唯一入口。而main前面的int就是主函数的类型.printf()是格式输出函数,这里就记住它的功能就是在屏幕上输出指定的信息return是函数的返回值,根据函数类型的不同,返回的值也是不同的。\n是转义字符中的换行符。(注意:C程序一定是从主函数开始执行的)
四、规范
一个说明或一个语句占一行,例如:包含头文件、一个可执行语句结束都需要换行。函数体内的语句要有明显缩进,通常以按一下Tab键为一个缩进。括号要成对写,如果需要删除的话也要成对删除。当一句可执行语句结束的时候末尾需要有分号。代码中所有符号均为英文半角符号。
五、程序解释——注释
注释是写给程序员看的,不是写给电脑看的。
C语言注释方法有两种:
六、C的标识符
C语言规定,标识符可以是字母(A~Z,a~z)、数字(0~9)、下划线_组成的字符串,并且第一个字符必须是字母或下划线。在使用标识符时还有注意以下几点:
标识符的长度最好不要超过8位,因为在某些版本的C中规定标识符前8位有效,当两个标识符前8位相同时,则被认为是同一个标识符。标识符是严格区分大小写的。例如Imooc和imooc 是两个不同的标识符。标识符最好选择有意义的英文单词组成做到"见名知意",不要使用中文。标识符不能是C语言的关键字。想了解更多C语言关键字的知识。
七、变量及赋值
变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前必须先定义变量,要区分变量名和变量值是两个不同的概念。
变量定义的一般形式为:数据类型 变量名;
多个类型相同的变量:数据类型 变量名, 变量名, 变量名…;
注意:在定义中不允许连续赋值,如int a=b=c=5;是不合法的。
变量的赋值分为两种方式:
先声明再赋值声明的同时赋值
八、基本数据类型
C语言中,数据类型可分为:
基本数据类型构造数据类型指针类型空类型四大类
最常用的整型, 实型与字符型(char,int,float,double):
整型数据是指不带小数的数字(int,short int,long int, unsigned int, unsigned short int,unsigned long int):
注:
int short int long int是根据编译环境的不同,所取范围不同。而其中short int和long int至少是表中所写范围, 但是int在表中是以16位编译环境写的取值范围。另外 c语言int的取值范围在于他占用的字节数 ,不同的编译器,规定是不一样。ANSI标准定义int是占2个字节,TC是按ANSI标准的,它的int是占2个字节的。但是在VC里,一个int是占4个字节的。
浮点数据是指带小数的数字。
因为精度的不同又分为3种(float,double,long double):
九、格式化输出语句
格式化输出语句,也可以说是占位输出,是将各种类型的数据按照格式化后的类型及指定的位置从计算机上显示。
其格式为:printf("输出格式符",输出项);
当输出语句中包含普通字符时,可以采用以下格式:
printf("普通字符输出格式符", 输出项);
注意:格式符的个数要与变量、常量或者表达式的个数一一对应
十、常量
在程序执行过程中,值不发生改变的量称为常量。
mtianyan: C语言的常量可以分为直接常量和符号常量。
直接常量也称为字面量,是可以直接拿来使用,无需说明的量,比如:
整型常量:13、0、-13;实型常量:13.33、-24.4;字符常量:‘a’、‘M’字符串常量:”I love imooc!”
在C语言中,可以用一个标识符来表示一个常量,称之为符号常量。符号常量在使用之前必须先定义,其一般形式为
#define 标识符 常量值
#include#define POCKETMONEY 10 //定义常量及常量值int main(){ // POCKETMONEY = 12; //小明私自增加零花钱对吗? printf("小明今天又得到%d元零花钱\n", POCKETMONEY); return 0; }
符号常量不可以被改变。
十一、自动类型转换
数据类型存在自动转换的情况. 自动转换发生在不同数据类型运算时,在编译的时候自动完成。
char类型数据转换为int类型数据遵循ASCII码中的对应值.
注:
十二、强制类型转换
强制类型转换是通过定义类型转换运算来实现的。其一般形式为:
(数据类型) (表达式)
其作用是把表达式的运算结果强制转换成类型说明符所表示的类型
在使用强制转换时应注意以下问题:
数据类型和表达式都必须加括号, 如把(int)(x/2+y)写成(int)x/2+y则成了把x转换成int型之后再除2再与y相加了。转换后不会改变原数据的类型及变量值,只在本次运算中临时性转换。强制转换后的运算结果不遵循四舍五入原则。
十三、运算符号
C语言中运算符:
1.算术运算符
c语言基本运算符:
2.自增与自减运算符
自增运算符为++,其功能是使变量的值自增1自减运算符为--,其功能是使变量值自减1。
它们经常使用在循环中。自增自减运算符有以下几种形式:
3.赋值运算符
C语言中赋值运算符分为简单赋值运算符和复合赋值运算符
简单赋值运算符=号了,下面讲一下复合赋值运算符:
复合赋值运算符就是在简单赋值符=之前加上其它运算符构成.
注意:复合运算符中运算符和等号之间是不存在空格的。
4.关系运算符
C语言中的关系运算符:
关系表达式的值是真和假,在C程序用整数1和0表示。
注意:>=, <=, ==, !=这种符号之间不能存在空格。
5.逻辑运算符
C语言中的逻辑运算符:
6.三目运算符
C语言中的三目运算符:?:,其格式为:
表达式1 ? 表达式2 : 表达式3; 执行过程是:
先判断表达式1的值是否为真,如果是真的话执行表达式2;如果是假的话执行表达式3。
7.运算符大比拼之优先级比较
各种运算符号的顺序:
优先级别为1的优先级最高,优先级别为10的优先级别最低。
十四、分支结构
1.简单if语句
C语言中的分支结构语句中的if条件语句。
简单if语句的基本结构如下:
if(表达式){执行代码块;}
其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。
注意:if()后面没有分号,直接写{}
2.if-else语句
简单的if-else语句的基本结构:
语义是: 如果表达式的值为真,则执行代码块1,否则执行代码块2。
3.多重if-else语句
C语言中多重if-else语句,其结构如下:
语义是:依次判断表达式的值,当出现某个值为真时,则执行对应代码块,否则执行代码块n。
注意:当某一条件为真的时候,则不会向下执行该分支结构的其他语句。
4.嵌套if-else语句
C语言中嵌套if-else语句。嵌套if-else语句的意思,就是在if-else语句中,再写if-else语句。其一般形式为:
十五、循环结构
1.while循环
反复不停的执行某个动作就是江湖人称的循环。
C语言中有三种循环结构,先看一下C语言while循环的结构
其中表达式表示循环条件,执行代码块为循环体。
while语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体代码块。
while语句中的表达式一般是关系表达或逻辑表达式,当表达式的值为假时不执行循环体,反之则循环体一直执行。一定要记着在循环体中改变循环变量的值,否则会出现死循环(无休止的执行)。循环体如果包括有一个以上的语句,则必须用{}括起来,组成复合语句。
2.do-while循环
C语言中的do-while循环,一般形式如下:
do-while循环语句的语义是:
它先执行循环中的执行代码块,然后再判断while中表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句。
注意:mtianyan: 使用do-while结构语句时,while括号后必须有分号。
3.for循环
c语言中for循环一般形式:
它的执行过程如下:
执行表达式1,对循环变量做初始化;判断表达式2,若其值为真(非0),则执行for循环体中执行代码块,然后向下执行;若其值为假(0),则结束循环;执行表达式3,(i++)等对于循环变量进行操作的语句;执行for循环中执行代码块后执行第二步;第一步初始化只会执行一次。循环结束,程序继续向下执行。
注意:for循环中的两个分号一定要写
在for循环中:
表达式1是一个或多个赋值语句,它用来控制变量的初始值;表达式2是一个关系表达式,它决定什么时候退出循环;表达式3是循环变量的步进值,定义控制循环变量每循环一次后按什么方式变化。这三部分之间用分号 ; 分开。
使用for语句应该注意:
for循环中的“表达式1、2、3”均可不写为空,但两个分号(;;)不能缺省。省略“表达式1(循环变量赋初值)”,表示不对循环变量赋初始值。省略“表达式2(循环条件)”,不做其它处理,循环一直执行(死循环)。省略“表达式3(循环变量增减量)”,不做其他处理,循环一直执行(死循环)。表达式1可以是设置循环变量的初值的赋值表达式,也可以是其他表达式。表达式1和表达式3可以是一个简单表达式也可以是多个表达式以逗号分割。表达式2一般是关系表达式或逻辑表达式,但也可是数值表达式或字符表达式,只要其值非零,就执行循环体。各表达式中的变量一定要在for循环之前定义。
3.三种循环比较
while, do-while和for三种循环在具体的使用场合上是有区别的,如下:
在知道循环次数的情况下更适合使用for循环;在不知道循环次数的情况下适合使用while或者do-while循环:如果有可能一次都不循环应考虑使用while循环如果至少循环一次应考虑使用do-while循环。但是从本质上讲,while,do-while和for循环之间是可以相互转换的。
4.多重循环
多重循环就是在循环结构的循环体中又出现循环结构。
在实际开发中一般最多用到三层重循环。
因为循环层数越多,运行时间越长,程序越复杂,所以一般用2-3层多重循环就可以了。另外不同循环之间也是可以嵌套的。
多重循环在执行的过程中,外层循环为父循环,内层循环为子循环,
**父循环一次,子循环需要全部执行完,直到跳出循环。**父循环再进入下一次,子循环继续执行…
十六、结束语句
1.break语句
那么循环5次的时候,需要中断不继续训练。在C语言中,可以使用break语句进行该操作.
使用break语句时注意以下几点:
在没有循环结构的情况下,break不能用在单独的if-else语句中。在多层循环中,一个break语句只跳出当前循环。
2.continue语句
那么循环5次的时候,需要中断后继续训练。在C语言中,可以使用continue语句进行该操作
continue语句的作用是结束本次循环开始执行下一次循环。
break语句与continue语句的区别是:
break是跳出当前整个循环,continue是结束本次循环开始下一次循环。
十七、局部与全局
C语言中的变量,按作用域范围可分为两种,即局部变量和全局变量。局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的。在复合语句中也可定义变量,其作用域只在复合语句范围内。 全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序。
十八、变量存储类别
mtianyan: C语言根据变量的生存周期来划分,可以分为静态存储方式和动态存储方式。
静态存储方式:是指在程序运行期间分配固定的存储空间的方式。静态存储区中存放了在整个程序执行过程中都存在的变量,如全局变量。 动态存储方式:是指在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数;自动变量;函数调用时的现场保护和返回地址等。 C语言中存储类别又分为四类:
自动(auto)、静态(static)、寄存器的(register)外部的(extern)。
十九、内部函数与外部函数
在C语言中不能被其他源文件调用的函数称谓内部函数 ,内部函数由static关键字来定义,因此又被称谓静态函数,形式为: static [数据类型] 函数名([参数]) 这里的static是对函数的作用范围的一个限定,限定该函数只能在其所处的源文件中使用,因此在不同文件中出现相同的函数名称的内部函数是没有问题的。 在C语言中能被其他源文件调用的函数称谓外部函数 ,外部函数由extern关键字来定义,形式为: extern [数据类型] 函数名([参数]) C语言规定,在没有指定函数的作用范围时,系统会默认认为是外部函数,因此当需要定义外部函数时extern也可以省略。 静态变量只赋值一次
二十、数组初体验
程序中也需要容器,只不过该容器有点特殊,它在程序中是一块连续的,大小固定并且里面的数据类型一致的内存空间,它还有个好听的名字叫数组。可以将数组理解为大小固定,所放物品为同类的一个购物袋,在该购 物袋中的物品是按一定顺序放置的。
1.我们来看一下如何声明一个数组:
数据类型 数组名称[长度];
数组只声明也不行啊,看一下数组是如何初始化的。说到初始化,C语言中的数组初始化是有三种形式的,分别是:
数据类型 数组名称[长度n] = {元素1,元素2…元素n};数据类型 数组名称[] = {元素1,元素2…元素n};数据类型 数组名称[长度n]; 数组名称[0] = 元素1; 数组名称[1] = 元素2; 数组名称[n-1] = 元素n;
我们将数据放到数组中之后又如何获取数组中的元素呢?
获取数组元素时: 数组名称[元素所对应下标];
如:初始化一个数组 int arr[3] = {1,2,3}; 那么arr[0]就是元素1。
注意:
数组的下标均以0开始; 数组在初始化的时候,数组内元素的个数不能大于声明的数组长度; mtianyan: 如果采用第一种初始化方式,元素个数小于数组的长度时,多余的数组元素初始化为0; 在声明数组后没有进行初始化的时候,静态(static)和外部(extern)类型的数组元素初始化元素为0,自动(auto)类型的数组的元素初始化值不确定。
2.数组的遍历
数组就可以采用循环的方式将每个元素遍历出来,而不用人为的每次获取指定某个位置上的元素,例如我们用for循环遍历一个数组:
注意以下几点:
最好避免出现数组越界访问,循环变量最好不要超出数组的长度.C语言的数组长度一经声明,长度就是固定,无法改变,并且C语言并不提供计算数组长度的方法。
由于C语言是没有检查数组长度改变或者数组越界的这个机制,可能会在编辑器中编译并通过,但是结果就不能肯定了,因此还是不要越界或者改变数组的长度
3.数组作为函数参数
数组可以由整个数组当作函数的参数,也可以由数组中的某个元素当作函数的参数:
整个数组当作函数参数,即把数组名称传入函数中,例如:
数组中的元素当作函数参数,即把数组中的参数传入函数中,例如:
数组作为函数参数时注意以下事项:
数组名作为函数实参传递时,函数定义处作为接收参数的数组类型形参既可以指定长度也可以不指定长度。数组元素作为函数实参传递时,数组元素类型必须与形参数据类型一致。
4.字符串与数组
C语言中,是没有办法直接定义字符串数据类型的,但是我们可以使用数组来定义我们所要的字符串。一般有以下两种格式:
char 字符串名称[长度] = “字符串值”;char 字符串名称[长度] = {‘字符1’,‘字符2’,…,‘字符n’,’\0’};
注意:
[]中的长度是可以省略不写的;采用第2种方式的时候最后一个元素必须是’\0’,’\0’表示字符串的结束标志;采用第2种方式的时候在数组中不能写中文。在输出字符串的时候要使用:printf(“%s”,字符数组名字);或者puts(字符数组名字);。
5.mtianyan:字符串函数
常用的字符串函数如下(strlen,strcmp,strcpy,strcat,atoi):
使用字符串函数注意以下事项:
strlen()获取字符串的长度,在字符串长度中是不包括‘\0’而且汉字和字母的长度是不一样的strcmp()在比较的时候会把字符串先转换成ASCII码再进行比较,返回的结果为0表示s1和s2的ASCII码相等,返回结果为1表示s1比s2的ASCII码大,返回结果为-1表示s1比s2的ASCII码小strcpy()拷贝之后会覆盖原来字符串且不能对字符串常量进行拷贝strcat在使用时s1与s2指的内存空间不能重叠,且s1要有足够的空间来容纳要复制的字符串
6.多维数组
多维数组的定义格式是: 数据类型 数组名称[常量表达式1][常量表达式2]…[常量表达式n];
定义了一个名称为num,数据类型为int的二维数组。其中第一个[3]表示第一维下标的长度,就像购物时分类存放的购物;第二个[3]表示第二维下标的长度,就像每个购物袋中的元素。
多维数组的初始化与一维数组的初始化类似也是分两种:
数据类型 数组名称[常量表达式1][常量表达式2]…[常量表达式n] = {{值1,…,值n},{值1,…,值n},…,{值1,…,值n}};数据类型 数组名称[常量表达式1][常量表达式2]…[常量表达式n]; 数组名称[下标1][下标2]…[下标n] = 值;
多维数组初始化要注意以下事项:
采用第一种始化时数组声明必须指定列的维数。mtianyan: 因为系统会根据数组中元素的总个数来分配空间,当知道元素总个数以及列的维数后,会直接计算出行的维数;采用第二种初始化时数组声明必须同时指定行和列的维数。
二维数组定义的时候,可以不指定行的数量,但是必须指定列的数量
二十一、C语言最核心的指针
说到指针,就不可能脱离开内存,学会指针的人分为两种,一种是不了解内存模型,另外一种则是了解。
不了解的对指针的理解就停留在“指针就是变量的地址”这句话,会比较害怕使用指针,特别是各种高级操作。
而了解内存模型的则可以把指针用得炉火纯青!
想学好C语言,很关键就是搞懂内存、指针、还有各种编译链接,
1、内存本质
编程的本质其实就是操控数据,数据存放在内存中。
因此,如果能更好地理解内存的模型,以及 C 如何管理内存,就能对程序的工作原理洞若观火,从而使编程能力更上一层楼。
大家真的别认为这是空话,我大一整年都不敢用 C 写上千行的程序也很抗拒写 C。
因为一旦上千行,经常出现各种莫名其妙的内存错误,一不小心就发生了 coredump...... 而且还无从排查,分析不出原因。
相比之下,那时候最喜欢 Java,在 Java 里随便怎么写都不会发生类似的异常,顶多偶尔来个 NullPointerException,也是比较好排查的。
直到后来对内存和指针有了更加深刻的认识,才慢慢会用 C 写上千行的项目,也很少会再有内存问题了。(过于自信
「指针存储的是变量的内存地址」这句话应该任何讲 C 语言的书都会提到吧。
所以,要想彻底理解指针,首先要理解 C 语言中变量的存储本质,也就是内存。
(1)内存编址
计算机的内存是一块用于存储数据的空间,由一系列连续的存储单元组成,就像下面这样,
每一个单元格都表示 1 个 Bit,一个 bit 在 EE 专业的同学看来就是高低电位,而在 CS 同学看来就是 0、1 两种状态。
由于 1 个 bit 只能表示两个状态,所以大佬们规定 8个 bit 为一组,命名为 byte。
并且将 byte 作为内存寻址的最小单元,也就是给每个 byte 一个编号,这个编号就叫内存的地址。
这就相当于,我们给小区里的每个单元、每个住户都分配一个门牌号,在生活中,我们需要保证门牌号唯一,这样就能通过门牌号很精准的定位到一家人。
同样,在计算机中,我们也要保证给每一个 byte 的编号都是唯一的,这样才能够保证每个编号都能访问到唯一确定的 byte。
(2)内存地址空间
上面我们说给内存中每个 byte 唯一的编号,那么这个编号的范围就决定了计算机可寻址内存的范围。
所有编号连起来就叫做内存的地址空间,这和大家平时常说的电脑是 32 位还是 64 位有关。
早期 Intel 8086、8088 的 CPU 就是只支持 16 位地址空间,寄存器和地址总线都是 16 位,这意味着最多对 2^16 = 64 Kb的内存编号寻址。
这点内存空间显然不够用,后来,80286 在 8086 的基础上将地址总线和地址寄存器扩展到了20 位,也被叫做 A20 地址总线。
当时在写 mini os 的时候,还需要通过 BIOS 中断去启动 A20 地址总线的开关。
但是,现在的计算机一般都是 32 位起步了,32 位意味着可寻址的内存范围是 2^32 byte = 4GB。
所以,如果你的电脑是 32 位的,那么你装超过 4G 的内存条也是无法充分利用起来的。
好了,这就是内存和内存编址。
(3)变量的本质
有了内存,接下来我们需要考虑,int、double 这些变量是如何存储在 0、1 单元格的。
在 C 语言中我们会这样定义变量:
int a = 999;char c = "c";
当你写下一个变量定义的时候,实际上是向内存申请了一块空间来存放你的变量。
我们都知道 int 类型占 4 个字节,并且在计算机中数字都是用补码(不了解补码的记得去百度)表示的。
999 换算成补码就是:0000 0011 1110 0111
这里有 4 个byte,所以需要四个单元格来存储:
有没有注意到,我们把高位的字节放在了低地址的地方,那能不能反过来呢?
当然,这就引出了大端和小端。
像上面这种将高位字节放在内存低地址的方式叫做大端,反之,将低位字节放在内存低地址的方式就叫做小端。
上面只说明了 int 型的变量如何存储在内存,而 float、char 等类型实际上也是一样的,都需要先转换为补码。
对于多字节的变量类型,还需要按照大端或者小端的格式,依次将字节写入到内存单元。
记住上面这两张图,这就是编程语言中所有变量的在内存中的样子,不管是 int、char、指针、数组、结构体、对象... 都是这样放在内存的。
2、指针是什么啥?
变量放在哪?上面我说,定义一个变量实际就是向计算机申请了一块内存来存放。
那如果我们要想知道变量到底放在哪了呢?可以通过运算符&来取得变量实际的地址,这个值就是变量所占内存块的起始地址。
PS: 实际上这个地址是虚拟地址,并不是真正物理内存上的地址
我们可以把这个地址打印出来
printf("%x", &a);
大概会是像这样的一串数字:0x7ffcad3b8f3c
上面说,我们可以通过&符号获取变量的内存地址,那获取之后如何来表示这是一个地址,而不是一个普通的值呢?
也就是在 C 语言中如何表示地址这个概念呢?
对,就是指针,你可以这样
int *pa = &a;
pa 中存储的就是变量 a 的地址,也叫做指向 a 的指针。
在这里我想谈几个看起来有点无聊的话题:
当然可以,但是变量名是有局限的。
是变量地址的符号化,变量是为了让我们编程时更加方便,对人友好,可计算机可不认识什么变量 a,它只知道地址和指令。
所以当你去查看 C 语言编译后的汇编代码,就会发现变量名消失了,取而代之的是一串串抽象的地址。
你可以认为,编译器会自动维护一个映射,将我们程序中的变量名转换为变量所对应的地址,然后再对这个地址去进行读写。
也就是有这样一个映射表存在,将变量名自动转化为地址:
a | 0x7ffcad3b8f3cc | 0x7ffcad3b8f2ch | 0x7ffcad3b8f4c....
说的好!
可是我还是不知道指针存在的必要性,那么问题来了,看下面代码:
int func(...) { ... };int main() { int a; func(...);};
假设我有一个需求:
你说可以通过&取地址符号,将 a的地址传递进去:
int func(int address) { ....};int main() { int a; func(&a);};
这样在func里就能获取到 a的地址,进行读写了。
理论上这是完全没有问题的,但是问题在于:
编译器该如何区分一个 int 里你存的到底是 int 类型的值,还是另外一个变量的地址(即指针)。
这如果完全靠我们编程人员去人脑记忆了,会引入复杂性,并且无法通过编译器检测一些语法错误。
而通过int *去定义一个指针变量,会非常明确:这就是另外一个 int 型变量的地址。
编译器也可以通过类型检查来排除一些编译错误。
这就是指针存在的必要性。
实际上任何语言都有这个需求,只不过很多语言为了安全性,给指针戴上了一层枷锁,将指针包装成了引用。
可能大家学习的时候都是自然而然的接受指针这个东西,但是还是希望这段啰嗦的解释对你有一定启发。
同时,在这里提点小问题:
既然指针的本质都是变量的内存首地址,即一个 int 类型的整数。
解引用
上面的问题,就是为了引出指针解引用的。
pa中存储的是a变量的内存地址,那如何通过地址去获取a的值呢?
这个操作就叫做解引用,在 C 语言中通过运算符 *就可以拿到一个指针所指地址的内容了。
比如*pa就能获得a的值。
我们说指针存储的是变量内存的首地址,那编译器怎么知道该从首地址开始取多少个字节呢?
这就是指针类型发挥作用的时候,编译器会根据指针的所指元素的类型去判断应该取多少个字节。
如果是 int 型的指针,那么编译器就会产生提取四个字节的指令,char 则只提取一个字节,以此类推。
下面是指针内存示意图:
pa指针首先是一个变量,它本身也占据一块内存,这块内存里存放的就是 a变量的首地址。
当解引用的时候,就会从这个首地址连续划出 4 个 byte,然后按照 int 类型的编码方式解释。
别看这个地方很简单,但却是深刻理解指针的关键。
举两个例子来详细说明:
比如:
float f = 1.0;short c = *(short*)&f;
你能解释清楚上面过程,对于 f变量,在内存层面发生了什么变化吗?或者 c的值是多少?1 ?
实际上,从内存层面来说,f什么都没变。
如图:
假设这是f在内存中的位模式,这个过程实际上就是把 f的前两个 byte 取出来然后按照 short 的方式解释,然后赋值给 c。
详细过程如下:
&f取得f 的首地址(short*)&f
上面第二步什么都没做,这个表达式只是说 :
“噢,我认为f这个地址放的是一个 short 类型的变量”
最后当去解引用的时候*(short*)&f时,编译器会取出前面两个字节,并且按照 short 的编码方式去解释,并将解释出的值赋给 c变量。
这个过程 f的位模式没有发生任何改变,变的只是解释这些位的方式。
当然,这里最后的值肯定不是 1,至于是什么,大家可以去真正算一下。
那反过来,这样呢?
short c = 1;float f = *(float*)&c;
如图:
具体过程和上述一样,但上面肯定不会报错,这里却不一定。
为什么?
(float*)&c会让我们从c的首地址开始取四个字节,然后按照 float 的编码方式去解释。
但是c是 short 类型只占两个字节,那肯定会访问到相邻后面两个字节,这时候就发生了内存访问越界。
当然,如果只是读,大概率是没问题的。
但是,有时候需要向这个区域写入新的值,比如:
*(float*)&c = 1.0;
那么就可能发生 coredump,也就是访存失败。
另外,就算是不会 coredump,这种也会破坏这块内存原有的值,因为很可能这是是其它变量的内存空间,而我们去覆盖了人家的内容,肯定会导致隐藏的 bug。
如果你理解了上面这些内容,那么使用指针一定会更加的自如。
3、结构体和指针
结构体内包含多个成员,这些成员之间在内存中是如何存放的呢?
比如:
struct fraction { int num; // 整数部分 int denom; // 小数部分};struct fraction fp;fp.num = 10;fp.denom = 2;
这是一个定点小数结构体,它在内存占 8 个字节(这里不考虑内存对齐),两个成员域是这样存储的:
我们把 10 放在了结构体中基地址偏移为 0 的域,2 放在了偏移为 4 的域。
接下来我们做一个这样的操作:
((fraction*)(&fp.denom))->num = 5; ((fraction*)(&fp.denom))->denom = 12; printf("%d\n", fp.denom); // 输出多少?
上面这个究竟会输出多少呢?自己先思考下噢~
接下来我分析下这个过程发生了什么:
首先,&fp.denom表示取结构体 fp 中 denom 域的首地址,然后以这个地址为起始地址取 8 个字节,并且将它们看做一个 fraction 结构体。
在这个新结构体中,最上面四个字节变成了 denom 域,而 fp 的 denom 域相当于新结构体的 num 域。
因此:
((fraction*)(&fp.denom))->num = 5
实际上改变的是 fp.denom,而
((fraction*)(&fp.denom))->denom = 12
则是将最上面四个字节赋值为 12。
当然,往那四字节内存写入值,结果是无法预测的,可能会造成程序崩溃,因为也许那里恰好存储着函数调用栈帧的关键信息,也可能那里没有写入权限。
大家初学 C 语言的很多 coredump 错误都是类似原因造成的。
所以最后输出的是 5。
为什么要讲这种看起来莫名其妙的代码?
就是为了说明结构体的本质其实就是一堆的变量打包放在一起,而访问结构体中的域,就是通过结构体的起始地址,也叫基地址,然后加上域的偏移。
其实,C++、Java 中的对象也是这样存储的,无非是他们为了实现某些面向对象的特性,会在数据成员以外,添加一些 Head 信息,比如C++ 的虚函数表。
实际上,我们是完全可以用 C 语言去模仿的。
这就是为什么一直说 C 语言是基础,你真正懂了 C 指针和内存,对于其它语言你也会很快的理解其对象模型以及内存布局。
4、多级指针
说起多级指针这个东西,我以前上学的时候最多理解到 2 级,再多真的会把我绕晕,经常也会写错代码。
你要是给我写个这个:int ******p能把我搞崩溃,我估计很多同学现在就是这种情况🤣
其实,多级指针也没那么复杂,就是指针的指针的指针的指针......非常简单。
今天就带大家认识一下多级指针的本质。
首先,我要说一句话,没有多级指针这种东西,指针就是指针,多级指针只是为了我们方便表达而取的逻辑概念。
首先看下生活中的快递柜:
这种大家都用过吧,每个格子都有一个编号,我们只需要拿到编号,然后就能找到对应的格子,取出里面的东西。
这里的格子就是内存单元,编号就是地址,格子里放的东西就对应存储在内存中的内容。
假设我把一本书,放在了 03 号格子,然后把 03 这个编号告诉你,你就可以根据 03 去取到里面的书。
那如果我把书放在 05 号格子,然后在 03 号格子只放一个小纸条,上面写着:「书放在 05 号」。
你会怎么做?
当然是打开 03 号格子,然后取出了纸条,根据上面内容去打开 05 号格子得到书。
这里的 03 号格子就叫指针,因为它里面放的是指向其它格子的小纸条(地址)而不是具体的书。
明白了吗?
那我如果把书放在 07 号格子,然后在 05 号格子 放一个纸条:「书放在 07号」,同时在03号格子放一个纸条「书放在 05号」
这里的 03 号格子就叫二级指针,05 号格子就叫指针,而 07 号就是我们平常用的变量。
依次,可类推出 N 级指针。
所以你明白了吗?同样的一块内存,如果存放的是别的变量的地址,那么就叫指针,存放的是实际内容,就叫变量。
int a;int *pa = &a;int **ppa = &pa;int ***pppa = &ppa;
上面这段代码,pa就叫一级指针,也就是平时常说的指针,ppa就是二级指针。
内存示意图如下:
不管几级指针有两个最核心的东西:
指针本身也是一个变量,需要内存去存储,指针也有自己的地址
指针内存存储的是它所指向变量的地址
这就是我为什么多级指针是逻辑上的概念,实际上一块内存要么放实际内容,要么放其它变量地址,就这么简单。
怎么去解读int **a这种表达呢?
int ** a可以把它分为两部分看,即int*和 *a,后面 *a中的*表示 a是一个指针变量,前面的 int*表示指针变量a
只能存放 int*型变量的地址。
对于二级指针甚至多级指针,我们都可以把它拆成两部分。
首先不管是多少级的指针变量,它首先是一个指针变量,指针变量就是一个*,其余的*表示的是这个指针变量只能存放什么类型变量的地址。
比如int****a表示指针变量 a只能存放int***型变量的地址。
5、指针与数组
(1)一维数组
数组是 C 自带的基本数据结构,彻底理解数组及其用法是开发高效应用程序的基础。
数组和指针表示法紧密关联,在合适的上下文中可以互换。
如下:
int array[10] = {10, 9, 8, 7};printf("%d\n", *array); // 输出 10printf("%d\n", array[0]); // 输出 10printf("%d\n", array[1]); // 输出 9printf("%d\n", *(array+1)); // 输出 9int *pa = array;printf("%d\n", *pa); // 输出 10printf("%d\n", pa[0]); // 输出 10printf("%d\n", pa[1]); // 输出 9printf("%d\n", *(pa+1)); // 输出 9
在内存中,数组是一块连续的内存空间:
第 0 个元素的地址称为数组的首地址,数组名实际就是指向数组首地址,当我们通过array[1]或者*(array + 1)去访问数组元素的时候。
实际上可以看做 address[offset],address为起始地址,offset为偏移量,但是注意这里的偏移量offset不是直接和 address相加,而是要乘以数组类型所占字节数,也就是: address + sizeof(int) * offset。
学过汇编的同学,一定对这种方式不陌生,这是汇编中寻址方式的一种:基址变址寻址。
看完上面的代码,很多同学可能会认为指针和数组完全一致,可以互换,这是完全错误的。
尽管数组名字有时候可以当做指针来用,但数组的名字不是指针。
最典型的地方就是在 sizeof:
printf("%u", sizeof(array));printf("%u", sizeof(pa));
第一个将会输出 40,因为 array包含有 10 个int类型的元素,而第二个在 32 位机器上将会输出 4,也就是指针的长度。
为什么会这样呢?
站在编译器的角度讲,变量名、数组名都是一种符号,它们都是有类型的,它们最终都要和数据绑定起来。
变量名用来指代一份数据,数组名用来指代一组数据(数据集合),它们都是有类型的,以便推断出所指代的数据的长度。
对,数组也有类型,我们可以将 int、float、char 等理解为基本类型,将数组理解为由基本类型派生得到的稍微复杂一些的类型,
数组的类型由元素的类型和数组的长度共同构成。而 sizeof就是根据变量的类型来计算长度的,并且计算的过程是在编译期,而不会在程序运行时。
编译器在编译过程中会创建一张专门的表格用来保存变量名及其对应的数据类型、地址、作用域等信息。
sizeof是一个操作符,不是函数,使用 sizeof时可以从这张表格中查询到符号的长度。
所以,这里对数组名使用sizeof可以查询到数组实际的长度。
pa仅仅是一个指向 int 类型的指针,编译器根本不知道它指向的是一个整数,还是一堆整数。
虽然在这里它指向的是一个数组,但数组也只是一块连续的内存,没有开始和结束标志,也没有额外的信息来记录数组到底多长。
所以对 pa使用 sizeof只能求得的是指针变量本身的长度。
也就是说,编译器并没有把 pa和数组关联起来,pa仅仅是一个指针变量,不管它指向哪里,sizeof求得的永远是它本身所占用的字节数。
(2)二维数组
大家不要认为二维数组在内存中就是按行、列这样二维存储的,实际上,不管二维、三维数组... 都是编译器的语法糖。
存储上和一维数组没有本质区别,举个例子:
int array[3][3] = {{1, 2,3}, {4, 5,6},{7, 8, 9}};array[1][1] = 5;
或许你以为在内存中 array数组会像一个二维矩阵:
1 2 34 5 67 8 9
可实际上它是这样的:
1 2 3 4 5 6 7 8 9
和一维数组没有什么区别,都是一维线性排列。
当我们像 array[1][1]这样去访问的时候,编译器会怎么去计算我们真正所访问元素的地址呢?
为了更加通用化,假设数组定义是这样的:
int array[n][m]
访问: array[a][b]
那么被访问元素地址的计算方式就是: array + (m * a + b)
这个就是二维数组在内存中的本质,其实和一维数组是一样的,只是语法糖包装成一个二维的样子。
6、 void 指针
想必大家一定看到过 void 的这些用法:
void func();int func1(void);
在这些情况下,void 表达的意思就是没有返回值或者参数为空。
但是对于 void 型指针却表示通用指针,可以用来存放任何数据类型的引用。
下面的例子就 是一个 void 指针:
void *ptr;
void 指针最大的用处就是在 C 语言中实现泛型编程,因为任何指针都可以被赋给 void 指针,void 指针也可以被转换回原来的指针类型, 并且这个过程指针实际所指向的地址并不会发生变化。
比如:
int num;int *pi = # printf("address of pi: %p\n", pi);void* pv = pi;pi = (int*) pv; printf("address of pi: %p\n", pi);
这两次输出的值都会是一样:
平常可能很少会这样去转换,但是当你用 C 写大型软件或者写一些通用库的时候,一定离不开 void 指针,这是 C 泛型的基石,比如 std 库里的 sort 函数申明是这样的:
void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));
所有关于具体元素类型的地方全部用 void 代替。
void 还可以用来实现 C 语言中的多态,这是一个挺好玩的东西。
不过也有需要注意的,不能对 void 指针解引用
比如:
int num;void *pv = (void*)#*pv = 4; // 错误
为什么?
因为解引用的本质就是编译器根据指针所指的类型,然后从指针所指向的内存连续取 N 个字节,然后将这 N 个字节按照指针的类型去解释。
比如 int *型指针,那么这里 N 就是 4,然后按照 int 的编码方式去解释数字。
但是 void,编译器是不知道它到底指向的是 int、double、或者是一个结构体,所以编译器没法对 void 型指针解引用。
关于指针想写的内容还有很多,这其实也只算是开了个头,限于篇幅,以后有机会补齐以下内容:
二维数组和二维指针
数组指针和指针数组
指针运算
函数指针
动态内存分配: malloc 和 free
堆、栈
函数参数传递方式
内存泄露
数组退化成指针
const 修饰指针
标签:
相关推荐:
精彩放送:
- []环球今日报丨中国“北斗”卫星导航系统——定位模块需求介绍
- []世界快看:操作系统中死锁的算法——银行家算法
- []当前资讯!DirectSound能帮我们做什么?DirectSound开发指南
- []“流氓”刘邦战胜英雄项羽的因素有哪些?详情介绍
- []全球热议:广西提高服务贸易水平 推动优质桂品“出海”
- []天天精选!iOS13越狱教程:如何安装AppSync和afc2补丁?
- []全球观速讯丨st股票什么股
- []股票开户需要多少钱
- []海昌海洋公园2022年营收同比下降近七成,将持续发展顶流IP
- []链家将27座城市转为加盟模式?贝壳:消息不实,仅为小范围合伙人模式
- []当前速讯:美达股份:公司生产的部分产品可在军民融合领域进行应用,具体请以公司公告和定期报告为准
- []每日看点!国睿科技:中国的城市轨道交通全自动运行(无人驾驶)信号系统处于国际先进水平
- []【全球报资讯】悦榕集团2022财年总计63家酒店收官 计划2025年扩张至113家
- []全球看热讯:我爱我家副总裁何洋辞任
- []我爱我家:五八有限公司拟减持不超过2.74%股份 持股比例将低于5%
- []中国恒大披露重组进展
- []电科院:公司具体经营情况详见以往定期报告
- []焦点讯息:航班老是临时取消?民航局要出手了
- []环球新资讯:国泰君安医药一季报业绩前瞻:业绩复苏环比趋势明确
- []【速看料】中信建投:TOPCon电池、组件超额利润有望扩大
- []眼看AI主题基金起高楼 “消费选手”仍在默默坚守
- []天天亮点!AI+元宇宙!Meta离梦想更进一步?
- []苏州常熟2宗宅地将于5月5日出让 起价合计5.4亿元
- []昭衍新药:公司会紧跟行业技术的发展变化,学习和借鉴相关技术在安评业务中的运用
- []环球百事通!中南建设前3月合同销售额120.4亿元 同比减少26.2%
- []消息!南昌中溢置业将转让杭州通原地产40%股权 底价8031.3万元
- []亚通精工:公司未有应披露而未披露事项,股价涨跌受多种因素影响,股价波动是正常的市场交易行为
- []西安国际港务区挂牌2宗宅地面积共117亩 起始总价为7.894亿元
- []财面儿丨越秀地产1-3月累计合同销售额约人民币438.33亿元 同比上升约217.3%
- []当前视点!海容冷链:公司产品不应用于殡葬行业,公司产品应用于快速消费品行业的渠道建设
- []每日时讯!将优化调整高校两成左右学科专业布点
- []【全球报资讯】合肥放开部分区域限购! 多孩家庭可买第3套住房
- []世界今日讯!链家欲在北京、上海以外城市转为加盟模式?贝壳回应:无此计划
- []每经热评|当前并非出台房产税政策的好时机
- []天天讯息:一个月的宝宝很容易被惊吓怎么办_一个月的宝宝发育指标
- []【热闻】怎样取公积金
- []今日热门!怎么取公积金
- []天天快看:交强险怎么用
- []贝壳:链家将27座城市转为加盟模式消息不实 仅为小范围合伙人模式
- []当前消息!滕哈赫:现在才是赛季真正的开始,输给纽卡后我们要有积极回应
- []道达尔能源与伊拉克政府就100亿美元天然气开发项目达成一致
- []世界快资讯丨林斌辞任奥园美谷财务总监职务?江永标继任
- []中南建设:中南城投减持212.03万股 占所持股比例0.11%
- []天天百事通!中南建设前三月累计合同销售金额120.4亿元 同比降26.2%
- []胡泊、李强分别辞任南国置业联席总经理、副总经理
- []万达投资新增质押1930万股万达电影 累计质押6665万股
- []环球今头条!刘鑫获任荣盛发展副总裁
- []全球热文:厦门象屿与河南能源集团签订战略合作协议
- []环球最新:4月05日20时青海海东今天新增确诊名单 4月05日20时青海海东疫情防控政策最新通知
- []当前视点!一半乡土质朴,一半文艺先锋,沙漠河流共生的小城,最美季节到了
- []全球热门:户用储能系统有什么用,有哪些特点和应用?
- []全球看热讯:长久物流设立储能全资子公司!
- []天天亮点!不低于1GW!泰达股份联手千泉实业投建光伏项目
- []30万吨光伏玻璃硅砂提纯项目环评
- []天天视点!超10GW!TCL中环单月出货新突破
- []一彬科技:公司生产经营一切正常。公司对未来汽车产业的发展充满信心
- []国际油价小跌,受制于美国制造业降温,本周重头戏待上演
- []焦点要闻:深圳到九江火车时刻表查询_南昌到九江火车时刻表
- []医道彤行,厚积薄发|2021道彤投资年度合伙人大会特写
- []海淘的childlife大瓶钙含防腐剂?专家建议婴幼儿产品选购要谨慎
- []好好香锅公司怎么样
- []观察:鸿路钢构:钢结构是绿色节能产品,是国家提倡并大力推广的装配式建筑的重要组成部分
- []基金经理猛追AI 但斌却突然唱空:一旦被套 不知猴年马月解套
- []关注:难道是真的?青海发现形状怪异的遗骸,揭开大禹治水背后的真相!
- []世界微头条丨维宏股份:整个Phoenix平台包含了软件和硬件两个部分
- []简讯:拜登:人工智能是否危险还有待观察 但科技公司需为安全负责
- []世界聚焦:2023年Q1季度精选文章合集 | 商旅会奖赛道
- []观速讯丨申请破产!暴跌90%
- []【全球新要闻】2023年Q1季度精选文章合集 | 在线旅游/分销赛道
- []每日关注!四川宜宾:住房公积金最高贷款额度可达90万元
- []全球快讯:伊戈尔:公司会根据客户需求和业务开拓的情况提前布局或者调整相应的产能
- []越秀地产:一季度累计销售约438亿元
- []环球今日讯!合肥调整购房政策:部分区域放开限购
- []全球微资讯!全国春风地图出炉 看看你那儿的四月天
- []环球关注:黄金大涨近2% 逼近历史最高纪录!金价为何持续大涨?专家解读
- []当前快报:是否想念篮球?维金斯:我非常想念队友们 期待与他们并肩作战
- []外汇交易提醒:降息预期升温,美元跌创近两个月新低,新西兰联储决议来袭,纽元续涨有望
- []周鸿祎突然离婚,要AI不要爱?董秘回应来了
- []accountnumber怎么读_Accountnumber
- []4月5日财经早餐:美数据疲软强化美联储放缓加息押注,金价站上2000美元/盎司大关创三十二个月新高
- []【世界聚看点】高达65%成本节约 施耐德电气适配改造服务助企业把握“循环”机遇
- []银行信贷投放不足原因_银行信贷的作用
- []恒达集团控股2022年收入增加约3.4% 纯利减74.3%至7780万
- []环球速读:车险佣金
- []看热讯:三大保险
- []热讯:寿险功用
- []当前资讯!聚焦中概 | 小鹏汽车跌幅扩大至7% 造车新势力普跌
- []双十原则
- []当前快看:乌龟冬眠是为了放水还是放沙?
- []天天快消息!周鸿祎与胡欢离婚 后者分得三六零4.46亿股、对应市值近90亿元
- []环球观热点:周度经济观察:斜率放缓的经济复苏
- []世界观焦点:申通快递:公司与阿里云合作,通过引入云原生技术实现了技术全面升级
- []全球短讯!深交所、沪交所4月8日全面实行注册制交易业务通关测试
- []亚太药业向下修正可转债价格 律师:索赔宜趁早
- []假期安全注意事项内容图片_假期安全注意事项内容
- []香山股份:目前尚无详细的市场份额数据,更多详情敬请留意公司官网及相关公告和定期报告
- []全球快看:秦安股份:4月3日公司高管刘宏庆减持公司股份合计1.16万股
- []保利发展:房地产持续向好的基本面没有变
- []世界快资讯:越秀地产前三月销售438亿?同比上升217%
- []当前聚焦:格力地产:珠海国资委同意公司收购免税集团 并募资不超70亿元
- B站注册资本增幅400%至5亿 目前由陈睿全资持股
- 光源资本出任独家财务顾问 沐曦集成电路10亿元A轮融资宣告完成
- 巨轮智能2021年上半年营收11.24亿元 期内研发费用投入增长19.05%
- 红枣期货尾盘拉升大涨近6% 目前红枣市场总库存约30万吨
- 嘉银金科发布2021年Q2财报 期内净利润达1.27亿元同比增长208%
- 成都银行2021上半年净利33.89亿元 期内实现营收同比增长17.27亿元
- 汽车之家发布2021年第二季度业绩 期内新能源汽车品牌收入增长238%
- 中信银行上半年实现净利润290.31亿元 期末不良贷款余额706.82亿元
- 光伏概念掀起涨停潮交易价格创新高 全天成交额达1.29亿元
- 上半年生物药大增45% 关键财务指标好转营收账款持续下降
- 天天观点:保利发展:公司负债率连续三年下降 继续保持稳健财务政策
- 保利发展:灵活安排推货节奏?把握市场修复窗口
- 今日要闻!国家加强铁矿石价格形势分析研判和期现货市场监管
- 世界热资讯!宝馨科技:目前公司怀远一期2GW异质结电池及组件项目正在加速推进中,预计年内投产
- 天天观点:中交城投郑州古荥城更项目获得首笔融资
- 岭南股份:公有云是云计算的主要形态。公司已与腾讯建立云计算、数字虚拟人、大数据等方面的战略合作
- 世界短讯!西安土拍市场“活”了?
- 世界快报:湖北襄阳高新区2.08亿售出65亩宅地 竞得者为本地房企
- 今日热讯:协创数据:公司存储设备主要与联想集团合作
- 【全球播资讯】三代人七十余载接力守护156座抗美援朝烈士墓
- 全球观天下!每日互动:AIGC和ChatGPT都是融合多种AI技术的成果
- 天天滚动:神州高铁:截至2023年3月31日,公司股东人数为91207
- 【天天新要闻】昭衍新药:股价走势受多方面因素的影响,还请谨慎投资
- 世界滚动:财面儿丨建发国际:前3月权益销售额353.4亿元,同比增长63.5%
- 全球实时:土地注册处:香港3月楼宇买卖合约8599份 按年升124.6%
- 【天天新要闻】昆明公租房开发公司最终发行6亿 品种一利率6.5%、品种二未发行
- 全球观点:拼多多升级组织架构 联合创始人赵佳臻出任联席CEO搭档陈磊
- 上海3月新建商品住宅成交面积环比增长94% 均价下跌2.8%
- 天天最资讯丨迪马股份为江苏2家子公司提供融资担保 涉资8.04亿元
- 滚动:狂飙910%!德国大储市场崛起,户储地位岌岌可危?
- 新消息丨最新进展!中科云网5GW TOPCON电池项目一期签署建设施工合同
- 焦点信息:煤矸石综合利用与矿山生态修复的战略思考
- 环球观热点:年产500万吨!全球规模最大光伏砂项目成功签约
- 最大涉水750mm 北京越野BJ60新增车型上市售24.58万-27.68万元
- 【天天播资讯】晶硅组件有什么作用和特点,有哪些种类?
- 环球旅讯+WiT新加坡主题沙龙开场演讲:你好,中国!
- 天天报道:新地University Hill料最快4月底开售
- 环球速递!万通发展:万通控股解质押270万股股份 现持公司股份3.34亿股
- 全球微动态丨建发房地产:10亿元公司债券票面利率为4.25%
- 世界头条:中核钛白:公司第三期员工持股计划并未在2023年3月14日进行大宗交易
- 全球观速讯丨祥生控股首季销售额54.19亿元 同比下滑38.73%
- 国际油价走强,但多头须警惕OPEC+最新减产的潜在负效用
- 恒基达鑫:公司始终密切关注横琴粤澳深度合作区相关的措施和政策情况,望能充分利用和享受到政策带来的红利
- 当前滚动:顾家家居:截至3月末累计回购股份106.28万股 总代价4187.73万元
- 海新能科: 截至2023年03月31日,公司股东总人数为45,272名
- 中红医疗:我国丁腈手套产品与马来西亚相比有一定的成本优势
- 经纬辉开:副董事长拟减持公司不超0.39%股份
- 富力地产:2022年度净亏损157.79亿元 预计今年可售货值超1250亿元
- 全球热点!小摩增持万物云39.86万股 总金额约1406.76万港元
- 全球速讯:嵘泰股份:我公司上市公司同行有旭升集团、爱柯迪、文灿股份等
- 新大正:正积极推进收购云南沧恒投资80%股权 尚存在不确定性
- 环球要闻:航天发展:截至2023年3月31日,航天发展股东户数为179,101户
- 当前快播:NYMEX原油仍上看83.17美元
- 4月4日福晶科技涨停分析:3D感应,中科院系,光通信概念热股
- 会德丰合作盘MIAMI QUAY I暂累售49伙 套现4.8亿港元
- 环球速读:“20绿城03”将于4月13日提前摘牌 发行金额为10亿元
- 天天资讯:4月4日中储股份涨停分析:央企改革,快递物流,国企改革概念热股
- 4月4日四川黄金涨停分析:黄金概念热股
- 环球今日讯!信达证券发布金陵饭店研报 年报点评:全年业绩稳中有增 布局中高端 注重品牌打造
- 焦点!学习心得怎么写?学习心得范本?
- 怎样追女生?追女孩子的方法有哪些?
- 环球观热点:仙剑奇侠传3有哪些歌曲?仙剑奇侠传3所有歌曲汇总?
- 合山市景点有哪些?合山市景点介绍?
- 每日短讯:降雨量50毫米是怎么计算的?降雨量50毫米的计算方法?
- 当前资讯!生物圈2号为什么会失败?生物圈二号失败的重要原因?
- 中青旅2022年营收64.17亿元,旅行社业务亏损收窄
- 捷信金融怎样贷款?捷信金融贷款条件有哪些?
- 环球热议:lol英雄联盟怎么观战?观看别人的游戏战斗方法?
- 每日看点!速干衣的特点有哪些?速干衣的主要功能是什么?
- 速讯:and1鞋子怎么样?and1鞋子有哪些特点?
- 焦点简讯:北京:加大老旧平房院落、老旧小区、危旧楼房和简易楼等更新力度
- 世界热文:常青股份:年报审计工作正在进行中,年报将于2023年4月26日披露
- 天天最新:山西大同:住房公积金贷款最高额度提至100万元
- 环球今头条!国际金价跌势受限,美国数据再现疲软,FED鹰派呼声难响
- 美原油交易策略:需求预期接力,油价或延续涨势
- 环球新消息丨苏泊尔拟分红24.40亿元 控股股东SEB国际或分得20.12亿元
- 千方科技:公司未参与您所提及的业务
- 当前快播:河南新乡:住房公积金最高贷款额度升至65万元
- 全球速读:发改委:产业目录引导横琴加大对新兴产业等的培育
- 焦点消息!年报横评①| 这些物企表现最好!五大指标透视2022年指标之最
- 世界焦点!医贝云服销售总监陈小飞:医贝云服伴随着药品和耗材供应链改革而诞生
- 孕妇补钙用金丐,早吃早手艺
- 环球新资讯:甘化科工:截至2023年3月31日,公司股东人数为27,947户
- 天天动态:上海新华联国际独栋商墅第三次流拍 起始价1.29亿元
- 焦点精选!明阳智能:尊敬的公司公司对外信息披露均按照信息披露要求进行
- 环球时讯:德恩精工子公司拟与亿盛房地产合作开发“滨江一号”项目 预计总投资约1.4亿元
- 环球今日讯!二手房成交量“狂飙”,百城落地“带押过户”
- 环球焦点!国际金价短线下看1970美元
- 【天天热闻】上海钢联:根据创业板上市公司相关规则,创业板上市公司无需披露季度业绩预告
- 非凡舞蹈学院创办人Jamila 王海青,打破自我,永不设限!善济有约
- 股票进仓是什么意思
- 云南省餐饮行业协会交流座谈会在文山举行
- “AI”拼才会赢?16只基金单日飙涨超7% 公募基金开始密集大调仓
- 三围怎么量
- 当前焦点!炒外汇为什么要拉人
- 用了“借钱三巨头”之一的钱小乐,真实感受:靠谱!
- 手机炒股票用什么软件最好
- 全球信息:收购瑞信后 瑞银将取代摩根大通成为拉美最大财富管理公司
- 市场对黄金ETF和金币的兴趣激增,渣打称这还只是开始!
- 天天热点!现货黄金交易策略:美元仍存下行风险,金价或震荡上攻
- 对冲基金放弃看空押注,金银正蓄势待涨!
- 当前播报:长春城投10亿元私募债券项目状态更新为“已反馈”
- 全球看点:北京:土地出让收入用于农业农村比例不低于7.5%
- 全球最新:【BT金融分析师】同程旅行月活跃用户破2亿,分析师称其度过行业低潮
- 天天速看:【BT金融分析师】亿航智能适航认证仍无进展,分析师称其前景变得模糊
- 全球关注:央行调查:54.1%的居民预期下季度房价“基本不变”
- 世界看热讯:黑石BREIT在3月收到45亿元美元赎回请求 仅获批6.66亿美元
- 北信源:获中国石油石化行业“科技进步一等奖” 树立油库安全生产行业典范
- 要闻速递:利嘉阁:港3月整体楼宇买卖8612宗 20个月新高
- *ST科华:公司业务情况请关注公司于2022年3月23日披露的《2022年年度报告》