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

C语言的数据类型及其对应变量

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
声明,定义和初始化
" y% \+ D: a; L! |/ ]6 B6 Z
. \, I( z4 ^, o声明标识符iden是告诉编译器"有这么一个变量var,具体var里是什么,你自己去看"。声明只需要标识符的类型和标识符名字,C语言的任何标识符在使用前都需要声明,当然变量也不例外;如果标识符的定义代码在使用之前,那么定义的代码可以看作是声明,否则需要声明定义标识符iden是告诉编译器"这个iden是什么";* B7 f& h$ l. e$ O& s3 l
初始化标识符iden是定义iden时给iden赋值,一个没有被赋值的iden里面存的是之前这块内存的值,就可能是任意的值,一不小心使用这样的标识符是十分危险的,所以一个好的习惯是定义一个标识符后立即初始化;另外一个原因是常量的值必须在初始化时确定,如果不进行初始化,那么这个常量以后永远都不能赋值了2 |0 ~  a9 V  d! L9 K
通常情况下,当我们写int atom=10;时,就同时进行了变量的定义和初始化。
5 |7 T; Z: l/ r7 e0 @. K7 c
% o  T- }2 T0 W指针
( A1 K" ^0 {5 N& f; M1 d8 j8 _8 z/ @
$ v3 G& _% J( I5 R. w内存就是一排大小都是一byte,且自己编号的抽屉。编号即抽屉的地址,里面的东西即抽屉的内容, P. d) Z0 `' |/ k( L$ B
6 @5 a- q" z4 M& J- l: c
指针即"地址"。即抽屉的编号4 R. F% ^; }% d
* b% R% w; v  J4 \+ q
指针变量即存储"标识符地址"的变量,即存放了另一个抽屉编号的抽屉,对指针变量"取值"即得到标识符的地址,即"指针的指向",对该变量"取址"即该变量本身存放的地址。当提及指针的时候,一定要注意说的是一个指针常量(一个地址), 还是一个指针变量,这是国内的教材非常差劲的一个习惯9 _+ d$ `! _- S# I" ^
: i0 G: f9 k4 g  `- X* E  b
一个指针变量理论上可以存储任何标识符的地址,但是为了便于管理,C语言把指针变量也按照标识符的类型进行了划分。所以有了函数的指针,字符指针,数组指针etc. 但他们其实都一样,即虽然所有的抽屉的编号都是一张纸条,但某个抽屉只用来存储装了苹果的抽屉的编号,另一个抽屉只用来存储装了橘子的抽屉的编号。9 ^6 b( B. c  ]

* v# _. E8 ?1 Y/ M  T! \8 l: F定义并初始化一个指针变量,由于运算符优先级的问题,并没有固定的定义格式,基本上每种不同的标识符都有自己的指针定义格式
: Y2 ^; @- t. b. W' j1 S
% {& S% l7 m7 D; H/ a% Oint* pVar=&var; //数据类型指针变量char (*ptr)[3]={'a','b','c'}; //数组指针变量,本质是指针,指向一个数组 VS char* str[10]={"this","is","a","string"};指针数组,本质是数组,每个元素都是一个指针int (*pFcn)(int x)=fcn; //函数指针变量,指向一个函数的地址,函数名就是一个指针  I# z7 m6 a2 j0 p7 O3 j8 C" p

* e# c! J/ e: f' n+ e& {# Y使用指针
1 j: l8 x7 q  @6 J0 v# j. r( c/ }' M
int var2=*pVar;//取值int** ppVar=*pVar;//取址,这里定义一个指向指针的指针变量* b) M) q* T5 [6 Q0 v& }' p7 g' }  s
) |0 u, i) Y1 j9 M+ p2 h
指针常量VS常量指针
  N3 w# l- U, f  C4 t- h* a( p
% R+ W0 Y. k4 r8 k8 ]. A指针常量const int* ptr表示不能通过指针修改指向的变量的内容, z2 b2 z5 d( ^% o" v
常量指针int* const ptr表示指针的指向不能改变。) o( ?, m  q8 j4 L

! ?# v  W# k4 L6 V3 [0 G1 G: K基本数据类型char int etc., S* k! e/ b* C  N
+ F) G: w7 b# {# b
基本数据类型是C语言规定好的数据类型,它们占据内存的大小,对该块内存的使用方式都是编译器规定好的,我们只能使用,不能更改。
0 d+ [$ s$ [/ X5 A( n" }7 E2 P在一个典型的32位操作系统中:9 P- }* M4 j: I! x- k  ]3 v
0 E- u# d" [$ }/ h, k7 p$ `
数据类型占位符长度数值范围(指数表示)数值范围(数字表示)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  
% [8 C; i: Z7 h0 r. g8 o& v( X% M/ }
Note:# n6 ^' Z7 i; u  }
( q6 X% |7 p6 ?, T7 o$ q
%f和%lf会保留小数点后多余的0(就算你写的5.2,也会输出5.200000),而%g和%lg不会保留哪些0" Z# f) \. E5 H
1 f7 Z, a! u( r" x9 G& _
不同平台(eg:32位VS64位系统)数据类型的长度会有不同,具体需要用sizeof测,上表针对一般32位系统,以int为例,一个int占4byte,一个byte占8位,所以一个int由32位二进制表示,故int共能表示2^32个数
& A! x+ v0 L! q: \; q( n) `7 U& x/ a  r1 k* h
float和double的范围是由指数的位数来决定的。float的指数位有8位,而double的指数位有11位,分布如下:
& X& k$ i' M$ sfloat: 1bit(符号位) 8bits(指数位) 23bits(尾数位). ^( ?1 {4 ~& U4 E0 l* o
double: 1bit(符号位) 11bits(指数位) 52bits(尾数位)
. C: T4 l5 X+ G/ ?( VSo,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。: ~* ]' X( Z$ W5 u# B, k
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
. T- L1 g8 b8 o5 b. }6 D* jdouble的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308
1 B% b/ \( ]0 Y
' N$ K, f& i3 \3 c* @有符号的数据类型不是分“正数” 和 “负数”,而是 “非负数” 和 “负数”,其中的区别在于 0 是非负数里的,所以,只需要记住有多少个和有无符号就可以计算其范围+ P% \7 B* [/ @7 |

* Y* U, n  _, W" O基本数据类型与指针
* B7 [' `2 o2 y; P
7 m* v! y, h8 pint var=10;int* pVar = &var; //定义并声明一个指向int类型变量的一个指针,并将其指向varint res=*pVar; //对一个指针取值int* pTest=pVar;
" U( O) k7 L$ y- M# N* ~
! |* c9 {3 h0 L/ e& c字符串) Z  `# L0 ]  C7 W
$ o. ~/ `6 [6 I  k/ q5 B' G
C语言中的字符串用"有效字符"来表示。
* Z5 M9 Q2 Z3 o: i+ eC编译器会自动在有效字符之后再加一个\0(即ASCII的数字0)表示字符串的结束,所以一个字符串实际占用的byte数目是"有效字符数+1","Tom"!='T''o''m',前者是字符串,有'\0'结尾,占4byte,后者不是"字符串",而是"一串字符",没有'\0'结尾,占3byte。 有两种方式测试字符串的长度:sizeof和strlen()6 Q. @' v* o3 j

8 l. |: T! j* |9 N" z- i# O定义一个字符串常量* T0 k7 ~  \8 k* k! d

1 K4 w' N8 F& J) N- fchar* str="this is a string";9 I! J9 `; B" E- `% |

4 o" X" ~# j, k1 E7 O9 u定义一个字符串数组
3 k+ v4 X" W, z( Q
( x1 Z* I, h6 j$ `char str[]="this is a string";* z9 D2 X" o8 W& i+ J( y
" J+ ]1 c9 ~' E: h/ z3 b
字符串与指针3 m3 k" W$ k  [" R5 i- o

. W5 \0 ]3 X0 w+ L; G当我们定义一个字符串常量的时候,C编译器其实干了三件事,1.找一块内存,把这个字符串的有效值放进去,2.字符串的结尾加一个'\0',3.把这个字符串的首地址放在标识符中。
9 B8 D7 q& b1 O6 n( w; H( qC语言的字符串有两种存储方式,字符串常量和字符串数组,二者存储的内容都一样,也都是一个返回字符串的首地址,区别是前者是常量,内存的内容不能修改,后者可以修改。
8 K8 h2 D6 k! N6 R( R+ q8 ]  U% V3 ]" h- s+ L
数组[]
7 v  y9 M. C1 E
3 K; e6 L: N: N) G, E9 l# d' D数组是在内存里一块区域里连续的存储数目固定的同一类型数据,这里的同一类型,既包括基本数据类型,也包括复合数据类型,指针等。一块数组可以用它的数组名唯一的表示,这个数组名其实就是这块内存的首地址,即第一个元素的首地址。定义数组时,元素的个数从1开始算,访问数组时,元素的个数从0开始算。所以数组名arr是第一个元素arr[0]的地址,arr+1是第二个元素arr[1]的地址,注意,arr+1不是第二个byte的地址,编译器会以一个元素所占的byte数为单位进行地址的增减。a[i]的实质就是将地址从a开始移动i个单位长度再解引用,即*(a+i)。6 G+ v5 M1 W6 t, l+ r
定义一个一维数组# H- f( d  S0 H

. P1 u0 q9 ?- ?/ {元素类型 数组名[元素的个数];. ], ]9 ~1 n2 B6 E) k

1 p' L9 G3 ?0 _! z' u+ D二维(多维)数组本质上还是在一块连续的内存中存储数目确定的同一类型数据,只不过对这块数据进行了"分组",比如,同样的一块存储了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个数) ~6 \" r6 R' a* N" I

/ b, A2 ^% g4 g& t% A4 V定义一个二维数组
* H0 A, l/ S4 W; x+ _, a5 R+ i, ?3 f: d& @* r9 d( ^
元素类型 数组名[组数][每组元素数]+ }& o+ L' X; W* J: G- |% d8 O" q
  n$ d- N) z$ Z) l# V
定义并初始化一个数组( y( E4 a: @, c5 f  p

- W3 z& a( e! F5 h& s( O. M. d: Fchar stu1Name[20]="Tom"; //定义并初始化字符数组,数组中前4byte被赋值char remark[20]={‘y‘,’e‘,’s‘}; //数组中前3byte被赋值int vector[]={1,2,3}; //如果数组元素全部列出,可以省略定义时的元素个数int vector2[][2]={1,2,3,4}; //如果没有歧义,二维数组的第一维可以省略,没有赋值的部分会被初始化为'0';; ~" d6 \! [! d% v* G

! y& m" b* c' w4 P5 e) [指针数组VS数组指针
* d8 L6 }" ~9 h+ c- S" n6 Z9 V$ w0 [% v
指针数组的核心词是"数组",所以指针数组表示的是里面的成员都是指针类型的数组3 T5 S: R3 F: {' P5 _. q

1 Q+ w/ [9 O8 Yint* arr[10]; //arr用来存储10个指向int类型的指针char* strarr[10]; //strarr用来存储10个指向char类型的指针,因为字符串的实质就是char*,所以strarr是存储了10个字符串首地址的数组
0 ?2 c" p: h4 z, a# ]; |/ |! \# u
" K- a3 |7 ~$ T7 f, O% G5 v数组指针的核心词是"指针",数组名本身就是一个指针常量,就是第一个元素的地址
( i1 I7 B! t) O$ s4 i( U  @- ]  L5 |
int arr[10] = {1,2,34};int* pArr=arr; //将数组的地址赋值给数组指针$ x1 f' t' ^( v2 `% N0 S1 Z

6 D+ X/ D) E8 h; v+ u6 I" w1 ~) }但是数组指针多用在二维数组中,一个int* ptr可以指向int arr[3],但是不能指向二维数组,二维数组指针一定要除了元素类型还要至少标明数组的列数,形如int (*ptr)[3],则这个ptr才可以指向任何一个以int为元素类型,列数为3的数组,当然,也可以同时指定指向数组的行数和列数做进一步的限定。
8 s2 ~( u% W7 `二维数组指针有行指针和列指针之分. Y9 ^$ L9 I- e" j6 s  H
1 K' f7 m  v; y7 Q8 x/ n; V1 \
结构体struct6 V) {9 T* ~' U; `6 q

( }" l3 A0 m1 z& H" A! t& m) }结构体是把不同的数据类型进行打包的一种数据类型,由程序员自己定义。既然说结构体是一种数据类型,而一个数据类型是没有值的,所以结构体在定义时不能进行赋值。2 }: D$ F% f: d. c- K* v
定义一个有名结构体类型,使用变量列表创建变量,使用初始化列表进行初始化) n  @2 P) U, b- g  t, V; E

, s$ M' H! a! a% l, W  rstruct StuInfo{ int age; char name[20];}stu1={10,"Tom"},stu2={11,"Rendo"};  n3 O$ c2 r+ T$ I

& Y) r5 Q/ t9 q0 K3 _) c  J/ v! L9 y0 `定义一个结构体类型,习惯上将自定义的结构体类型的首字母大写,以便和变量进行区分
3 e1 H( O; b) ^+ m& H" o$ e7 g" ], s& C1 v% a* [/ H) G. ^# j
struct StuInfo{ int age; char name[20];};//或typedef struct{ int age; char name[20];}StuInfo2;" n2 R! @# C& V( w# \- Z
! A: B4 s/ w5 Z% X. u% u, b
定义一个结构体类型的变量并进行列表初始化,列表初始化,即只能在初始化时使用,如果定义变量的时候不用,那么之后就只能逐个元素的赋值。& f9 M. Y% M# U, t
; l6 a% k3 t# ]) n; Z' L1 A
struct StudInfo stu1={10,"Tom"};//或StudInfo2 stu2={11,"Rendo"};5 @) p- V9 k* G) l" u) G

+ {( [! K+ _% B# H- g" d+ P' ?给结构体变量赋值
9 G" [2 |( E) D& ~3 T$ _4 [
% [7 d. @1 K  \; b. N, e7 y% Istu.age=10;stu.name[0]='T';stu.name[1]='o';stu.name[2]='m';stu.name[3]='\0';! N# @* y7 N* ]3 c# U- r  |! A- Z

/ @- q; B6 P1 A. B3 {5 f( @5 C) F1 V结构体与指针
) m5 W! G! ]# b1 ?0 S) `* o4 S# D4 G6 ]# ?! C$ g2 F  \9 x  E
struct StuInfo* pSt; //定义一个指向结构体StuInfo类型的指针struct StuInfo stu; //定义一个结构体StuInfo类型的变量pSt = &stu; //将结构体变量stu的地址赋给pSt
/ O  s* ]% y# a
, k% w+ L, h5 r6 c$ g共用体union
  y' W7 H- B% u: i5 a6 Z+ r6 ]/ C* q  w2 t
共用体的各个成员共享同一块内存,如果各个成员的长度不同,会取最长的那个成员的长度作为共用体的长度
1 G* Q- d! `, h' u
9 \( d- P* _. W定义一个union
6 ~- ]* S7 g: v* ~& t% `1 X- U0 T; e) X+ n* Y0 p3 ~
union Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;0 \( s$ n' ?6 Q

2 ]! Q# ]; G  h! M9 h, A创建共用体变量! _" C' P8 @( X0 M8 T4 Z8 ]  s

$ j3 j4 f* \5 A4 o2 D8 `union Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;' y, m; B4 v9 i) ~3 _; S
! N9 \! D) _. C- @1 X5 {9 I. _7 [
定义一个共用体变量6 y% @  x. p+ r2 q

& t; u6 X* V' G( r' o/ p9 ~) Yunion Data data1,data2;//或Data data1,data2;
1 H' S/ M6 p2 Y( `
+ {* i( Y: `- P- U( J使用共用体- ]( X; D) q2 n, L6 a* i5 c

. a' P$ w# c( H; Q7 a( `/ Ydata1.num1=2;data2.num2=3.3;
0 O- R$ A0 i: R1 D8 p9 W% `- N6 F& B/ u/ ~  p
枚举enum
+ U' C9 w2 ]+ N9 p  t+ c$ h) n7 z
) b% J! \5 c% F* @/ M& U顾名思义,枚举就是一个一个的列举,枚举类型用自定义的元素来代替列举元素的编号,方便记忆,但是其本质上还是一个整数。
7 f  v0 z: d: n2 k定义一个enum类型weekday7 m' P" U7 R& r. L7 }" q
& |9 M& Z3 V3 F( ?" @
enum weekday{sun,mon,tue,wed,thu,fri,sat};
3 V9 I2 P/ f: w+ u
0 {4 S' C/ i9 `2 B7 V" E定义了一个weekday类型的变量# H4 _3 w/ P4 z1 c! D  K3 V

1 \" s! ]3 }2 c. w8 Venum weekday day;' {6 q/ L- Q, G. e! `# g, z
. P  t/ H. N  u/ A+ r1 s3 ]
使用day变量* ]) r* Q* _4 ^( `7 j
8 R0 h! z% I% k- f9 ]7 m
day=mon;- ]* T8 v8 K- Y7 y) O* }/ U
+ h# `2 F( X$ x

4 X2 G* U* ?; H
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-12 11:08 , Processed in 0.093750 second(s), 24 queries , Gzip On.

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

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

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