找回密码
 注册
关于网站域名变更的通知
查看: 28|回复: 0
打印 上一主题 下一主题

C语言常用数据类型及

[复制链接]

该用户从未签到

跳转到指定楼层
1#
 楼主| 发表于 2024-7-31 17:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
7 x. K8 S% ]1 f

) x9 J2 d% J3 j8 F2 e3 k6 }声明,定义和初始化
6 G) B8 S7 ~( d8 a5 M! X' E; V4 j; @) W. S5 ]/ N/ D
声明标识符iden是告诉编译器"有这么一个变量var,具体var里是什么,你自己去看"。声明只需要标识符的类型和标识符名字,C语言的任何标识符在使用前都需要声明,当然变量也不例外;如果标识符的定义代码在使用之前,那么定义的代码可以看作是声明,否则需要声明定义标识符iden是告诉编译器"这个iden是什么";6 ?1 Q9 K# g/ F# ~/ o, m
初始化标识符iden是定义iden时给iden赋值,一个没有被赋值的iden里面存的是之前这块内存的值,就可能是任意的值,一不小心使用这样的标识符是十分危险的,所以一个好的习惯是定义一个标识符后立即初始化;另外一个原因是常量的值必须在初始化时确定,如果不进行初始化,那么这个常量以后永远都不能赋值了
2 R: R  Z! q$ l" S2 H4 Y8 S  k通常情况下,当我们写int atom=10;时,就同时进行了变量的定义和初始化。8 g" r$ g3 y6 c" z

6 s( E, q! `1 ~6 F; G指针
7 R- B$ _0 w- l# z  j3 Q% q- a( W' Y, H6 k6 o) a9 N* V
内存就是一排大小都是一byte,且自己编号的抽屉。编号即抽屉的地址,里面的东西即抽屉的内容
0 t) y4 f" t, ]" u# }: ^- r& x! x( X/ i" f2 l) v% c
指针即"地址"。即抽屉的编号% y1 y( C% a7 [3 |

# u$ V; k' A) T% D7 Z/ w指针变量即存储"标识符地址"的变量,即存放了另一个抽屉编号的抽屉,对指针变量"取值"即得到标识符的地址,即"指针的指向",对该变量"取址"即该变量本身存放的地址。当提及指针的时候,一定要注意说的是一个指针常量(一个地址), 还是一个指针变量,这是国内的教材非常差劲的一个习惯
* m' O( e: X# S, g3 w7 T: R4 o* k7 w0 q" m0 `6 E$ F' Z; K9 C7 u# j, ]: F
一个指针变量理论上可以存储任何标识符的地址,但是为了便于管理,C语言把指针变量也按照标识符的类型进行了划分。所以有了函数的指针,字符指针,数组指针etc. 但他们其实都一样,即虽然所有的抽屉的编号都是一张纸条,但某个抽屉只用来存储装了苹果的抽屉的编号,另一个抽屉只用来存储装了橘子的抽屉的编号。9 Q9 {# Y  R- w

0 x' s! u) e# Y  w% j# Q2 |定义并初始化一个指针变量,由于运算符优先级的问题,并没有固定的定义格式,基本上每种不同的标识符都有自己的指针定义格式
0 g- h3 e! z3 W, R8 Z& ]+ y" a  H  V$ t$ u9 I
int* pVar=&var; //数据类型指针变量char (*ptr)[3]={'a','b','c'}; //数组指针变量,本质是指针,指向一个数组 VS char* str[10]={"this","is","a","string"};指针数组,本质是数组,每个元素都是一个指针int (*pFcn)(int x)=fcn; //函数指针变量,指向一个函数的地址,函数名就是一个指针6 i8 W; Q! A6 t. ~& t2 [
: t* R1 b- ~$ I3 O+ m/ c
使用指针/ {# h. u; V% O

* |. h! g  ^+ k& `; B3 e' z! [' Iint var2=*pVar;//取值int** ppVar=*pVar;//取址,这里定义一个指向指针的指针变量2 ^  P  S8 E8 m9 J

9 G  {% h, N( Y1 t0 g9 K# |指针常量VS常量指针
. y% }  U3 [, N  N8 _; \8 ]; o- K
6 v+ [- p6 H/ F3 I, m; S0 `1 E指针常量const int* ptr表示不能通过指针修改指向的变量的内容/ U+ |7 M% k. g3 N1 c4 ~
常量指针int* const ptr表示指针的指向不能改变。
0 `% I4 [7 m1 h0 O* G% @
% N* a; [2 z/ ]& X" \* ]基本数据类型char int etc.
) a& L2 q+ ~2 A5 I; _0 S" c+ }; @; r9 ~: u6 q! g
基本数据类型是C语言规定好的数据类型,它们占据内存的大小,对该块内存的使用方式都是编译器规定好的,我们只能使用,不能更改。8 G0 O5 A1 k1 k5 }
在一个典型的32位操作系统中:
. j" i$ H: \) O/ o- A$ D% k, {( g
数据类型占位符长度数值范围(指数表示)数值范围(数字表示)char%c1-2^7~2^7-1-128~127unsigned char%c10~2^8-10~255short%hd2-2^15~2^15-1-32768~32767unsigned short%hu20~2^16-10~65535int%d4-2^31~2^31-1-2147483648~2147483647unsigned int%u40~2^32-10~4294967295long%ld4-2^31~2^31-1-2147483648~2147483647unsigned long%lu40~2^32-10~4294967295float%f或%g4  double%lf或%lg8  ) H/ \6 A6 B% [6 V* K5 U
8 \& _5 r  w0 y( A+ t! s
Note:" _% i1 \* Z# p& Y# F2 A
7 \/ t) T3 n0 w: u* }3 W
%f和%lf会保留小数点后多余的0(就算你写的5.2,也会输出5.200000),而%g和%lg不会保留哪些0
7 {& O# {+ |2 s5 @2 X" H, R. L. n0 ]* q2 e$ _" s. o
不同平台(eg:32位VS64位系统)数据类型的长度会有不同,具体需要用sizeof测,上表针对一般32位系统,以int为例,一个int占4byte,一个byte占8位,所以一个int由32位二进制表示,故int共能表示2^32个数
! ?+ U4 Y8 B4 X' j, p3 W
1 d: G4 k* f+ H' x$ [- jfloat和double的范围是由指数的位数来决定的。float的指数位有8位,而double的指数位有11位,分布如下:
* J0 g( L  m8 C& ^& s' R8 K, Cfloat: 1bit(符号位) 8bits(指数位) 23bits(尾数位)
* Z0 s9 {  q% F+ n' ndouble: 1bit(符号位) 11bits(指数位) 52bits(尾数位)- O! K: z% K5 x  R; d
So,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
' b/ \- Y1 R/ s: o3 \float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
0 J' X1 ?" w* E( f, Kdouble的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+3087 d2 ?# Z' t6 H  ]; O, S+ ~+ A
+ Z8 k5 ?. Z, t
有符号的数据类型不是分“正数” 和 “负数”,而是 “非负数” 和 “负数”,其中的区别在于 0 是非负数里的,所以,只需要记住有多少个和有无符号就可以计算其范围8 s6 v3 W, g2 b& n/ R' k

# k1 g6 A* K3 N; a9 J基本数据类型与指针
0 v6 o  }5 t1 k5 U9 V' P: }5 `
/ ]8 M5 P9 e9 w& q  M+ J- Fint var=10;int* pVar = &var; //定义并声明一个指向int类型变量的一个指针,并将其指向varint res=*pVar; //对一个指针取值int* pTest=pVar;
2 u  l. R0 p9 Y& T/ k1 }4 |1 r7 g) i+ N7 B/ k
字符串/ R; z, Z6 N  r9 v) P# A; r7 Q) n# D1 S

- l; h  }8 d* lC语言中的字符串用"有效字符"来表示。+ _' V( q7 j+ V: \8 A' C* q# p
C编译器会自动在有效字符之后再加一个\0(即ASCII的数字0)表示字符串的结束,所以一个字符串实际占用的byte数目是"有效字符数+1","Tom"!='T''o''m',前者是字符串,有'\0'结尾,占4byte,后者不是"字符串",而是"一串字符",没有'\0'结尾,占3byte。 有两种方式测试字符串的长度:sizeof和strlen()
7 S) ?  Y$ T9 Z' f" b( {  g
9 W3 p2 u9 B) s# X4 U/ E$ ~) V定义一个字符串常量8 h# r$ f2 ?* C
; `4 m# O9 j2 R: ]
char* str="this is a string";4 ]9 r4 e- R" u! @$ G
* V( G! K) m1 A3 [$ Q& I
定义一个字符串数组
% [: g; e3 Y! R4 ?) O5 |! F
) Q; h1 r$ A7 X% Ychar str[]="this is a string";
; ]7 {% |1 `" J1 p
/ b+ }% y3 r# g, s3 u9 d字符串与指针
5 s: M6 X2 J4 I. w. b6 T# v
7 J% w6 S' ^$ V8 E# W当我们定义一个字符串常量的时候,C编译器其实干了三件事,1.找一块内存,把这个字符串的有效值放进去,2.字符串的结尾加一个'\0',3.把这个字符串的首地址放在标识符中。: E5 I5 e2 W; C5 P9 ?7 l
C语言的字符串有两种存储方式,字符串常量和字符串数组,二者存储的内容都一样,也都是一个返回字符串的首地址,区别是前者是常量,内存的内容不能修改,后者可以修改。# N$ E* p8 U. N  N; H
; L& F) N- u% G
数组[]
  U5 b+ `: G- Q3 ~7 H+ K. R+ L4 G% m
数组是在内存里一块区域里连续的存储数目固定的同一类型数据,这里的同一类型,既包括基本数据类型,也包括复合数据类型,指针等。一块数组可以用它的数组名唯一的表示,这个数组名其实就是这块内存的首地址,即第一个元素的首地址。定义数组时,元素的个数从1开始算,访问数组时,元素的个数从0开始算。所以数组名arr是第一个元素arr[0]的地址,arr+1是第二个元素arr[1]的地址,注意,arr+1不是第二个byte的地址,编译器会以一个元素所占的byte数为单位进行地址的增减。a的实质就是将地址从a开始移动i个单位长度再解引用,即*(a+i)。
1 }+ G9 q7 f" ]# H; J定义一个一维数组
7 J9 P5 H, d& j- E5 C9 o
9 v8 }/ U! L( b4 _" v5 |9 O5 ]# [+ Z元素类型 数组名[元素的个数];* G0 k4 ?3 i4 b# @
3 c' g. w" p, u- v. \9 }
二维(多维)数组本质上还是在一块连续的内存中存储数目确定的同一类型数据,只不过对这块数据进行了"分组",比如,同样的一块存储了1,2,3,4...,9,10的内存,用一维数组表示是int num[10]={1,2,3,4,5,6,7,8,9,10};,而用二维数组表示是int num[2][5]={1,2,3,4,5,6,7,8,9,10};,内存还是那块内存,只不过表达方式变了,二维数组相当于把这10个数分成了两组,每组5个数" I! o9 c% `0 `3 L

- [- X- y4 F0 f0 P. H定义一个二维数组
* o% `4 x$ J, }3 K
3 m+ P; A: B3 K- o0 w7 J元素类型 数组名[组数][每组元素数]
* v* v7 @" T# {$ D7 v5 ^( n. m6 d8 V6 v: V% }
定义并初始化一个数组4 P  Z1 W( E" g& H

) k9 B* s) F0 hchar stu1Name[20]="Tom"; //定义并初始化字符数组,数组中前4byte被赋值char remark[20]={‘y‘,’e‘,’s‘}; //数组中前3byte被赋值int vector[]={1,2,3}; //如果数组元素全部列出,可以省略定义时的元素个数int vector2[][2]={1,2,3,4}; //如果没有歧义,二维数组的第一维可以省略,没有赋值的部分会被初始化为'0';8 L% o$ v" \2 p+ A

, K. J6 R; W' Z! v2 V$ g/ ?  K: A指针数组VS数组指针! U0 w' U1 C+ ]5 B$ Q8 A; _
* U: \- v3 ~6 H
指针数组的核心词是"数组",所以指针数组表示的是里面的成员都是指针类型的数组* c, Z9 }% R' P

& ~. h2 r% ~: Y3 C6 h# J, }: vint* arr[10]; //arr用来存储10个指向int类型的指针char* strarr[10]; //strarr用来存储10个指向char类型的指针,因为字符串的实质就是char*,所以strarr是存储了10个字符串首地址的数组
# d2 _: F7 I; A0 ?' X4 b0 s% W  ?/ X+ i" I. S( z5 Z- l; K
数组指针的核心词是"指针",数组名本身就是一个指针常量,就是第一个元素的地址
! @. G1 P  o* |' o! V
4 i/ ~' j- d# ^0 \int arr[10] = {1,2,34};int* pArr=arr; //将数组的地址赋值给数组指针
0 \3 T& X9 _% p1 Q7 U
4 H8 B9 S3 Y3 H6 @; a但是数组指针多用在二维数组中,一个int* ptr可以指向int arr[3],但是不能指向二维数组,二维数组指针一定要除了元素类型还要至少标明数组的列数,形如int (*ptr)[3],则这个ptr才可以指向任何一个以int为元素类型,列数为3的数组,当然,也可以同时指定指向数组的行数和列数做进一步的限定。, Z; J* `) a7 B
二维数组指针有行指针和列指针之分5 y! U" c1 q0 @0 u* f

3 k4 j; i; K6 [5 u4 R# b# E结构体struct
* K; E. [! g- o$ R. Y2 @# [  y9 N; M6 z- h* v- W3 @4 j
结构体是把不同的数据类型进行打包的一种数据类型,由程序员自己定义。既然说结构体是一种数据类型,而一个数据类型是没有值的,所以结构体在定义时不能进行赋值。
+ F' v+ C' A+ y; P3 t: o定义一个有名结构体类型,使用变量列表创建变量,使用初始化列表进行初始化) D7 j( H8 r! H0 H! \8 r, M  n
5 F+ k3 v6 f3 Y7 s
struct StuInfo{ int age; char name[20];}stu1={10,"Tom"},stu2={11,"Rendo"};
7 v- a- V9 Y1 `' L: N- Q4 ]7 N1 P) f5 f
定义一个结构体类型,习惯上将自定义的结构体类型的首字母大写,以便和变量进行区分
7 R3 {- [2 ]) N, `
$ G! ]& Z3 y) a& vstruct StuInfo{ int age; char name[20];};//或typedef struct{ int age; char name[20];}StuInfo2;9 o, L/ G( }& }& W

& t4 I2 ]- \/ V! X定义一个结构体类型的变量并进行列表初始化,列表初始化,即只能在初始化时使用,如果定义变量的时候不用,那么之后就只能逐个元素的赋值。2 Y0 A  q+ l- x% P& w4 Z

, K* j3 A' L+ T, u; Xstruct StudInfo stu1={10,"Tom"};//或StudInfo2 stu2={11,"Rendo"};; S0 E" \+ [6 j- y2 f
5 S, F8 u2 Q! c$ y4 W4 [# [9 O* f
给结构体变量赋值# C2 T+ l" w* A! i% a3 _0 A2 @

5 j! k& K  F5 X' Xstu.age=10;stu.name[0]='T';stu.name[1]='o';stu.name[2]='m';stu.name[3]='\0';
/ ~  `- U, [& P9 d  a
  x4 N$ \8 Q% \& T3 t结构体与指针
+ `) R0 B9 `8 d# |1 U
; F! ]3 d, F- N$ Mstruct StuInfo* pSt; //定义一个指向结构体StuInfo类型的指针struct StuInfo stu; //定义一个结构体StuInfo类型的变量pSt = &stu; //将结构体变量stu的地址赋给pSt
6 }# F' Y% t) V& k( }
7 H0 }# Q8 p9 Y4 H( R4 k共用体union
' [* y$ D( _- Z4 n5 J
0 R/ l$ {' V9 I1 q" z! @. m( q共用体的各个成员共享同一块内存,如果各个成员的长度不同,会取最长的那个成员的长度作为共用体的长度- Y" y0 j6 o  J) I+ K
# M+ m$ c2 m, t& j
定义一个union  Y; W* q) u4 k$ y: H6 I% C
& l9 A7 R+ q/ M+ x# H5 Z3 V; F
union Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;" m( D6 Y& q) Z! h+ b$ J
$ X3 R( b7 @, q! V
创建共用体变量6 {% ^# s; ~1 n: R& S# q
" z6 G  A' s4 y+ v5 B5 v0 |1 K
union Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;& u7 m! g, r: T6 w/ N: u2 D

* z* f* V4 K2 c定义一个共用体变量
: d5 C6 p+ U; T' b0 {$ b: `% M  C* e. W
union Data data1,data2;//或Data data1,data2;$ S  g. K" Y; V& P" R

6 p0 ?7 F" d& V  p! I. P, }使用共用体
% O* o- E- w5 H# B' K$ i# ?3 i" n# |! w) O
data1.num1=2;data2.num2=3.3;
5 T, V3 U$ l$ Z  C" y5 H" T# ^; X, n  s  J6 b) E( G$ ]% s
枚举enum
: p: h$ |7 J. c0 t
( B1 k9 I, X3 V顾名思义,枚举就是一个一个的列举,枚举类型用自定义的元素来代替列举元素的编号,方便记忆,但是其本质上还是一个整数。
4 O" @; r7 N2 }* Z定义一个enum类型weekday6 K6 G. U  s- @# V2 a2 S9 a
$ n4 z1 z' h1 }2 x, a; @# |# `) w
enum weekday{sun,mon,tue,wed,thu,fri,sat};+ `4 c3 L! \, {& ?8 u( \! o

- t" B" I/ R% Z2 m定义了一个weekday类型的变量' u* m9 d# B% Z  n2 C/ W

( g; U0 }- P; f0 [enum weekday day;% Y2 M5 F/ @* R- P, R
# {0 z, t$ e( m1 t
使用day变量$ l2 Q* W5 Z! }

8 g, k$ N* x4 C) ?day=mon;
3 @. l' u8 r7 z0 {; O$ {
8 M: S; Q  j+ O: a5 s- |, F  @
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-19 10:59 , Processed in 0.109375 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表