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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
声明,定义和初始化
3 ~4 z* i7 e1 ]( A# h; P4 }2 f. P# |/ f, N0 L0 T: i8 C# K
声明标识符iden是告诉编译器"有这么一个变量var,具体var里是什么,你自己去看"。声明只需要标识符的类型和标识符名字,C语言的任何标识符在使用前都需要声明,当然变量也不例外;如果标识符的定义代码在使用之前,那么定义的代码可以看作是声明,否则需要声明定义标识符iden是告诉编译器"这个iden是什么";
8 d" L. E6 Y( _初始化标识符iden是定义iden时给iden赋值,一个没有被赋值的iden里面存的是之前这块内存的值,就可能是任意的值,一不小心使用这样的标识符是十分危险的,所以一个好的习惯是定义一个标识符后立即初始化;另外一个原因是常量的值必须在初始化时确定,如果不进行初始化,那么这个常量以后永远都不能赋值了
! A9 p/ w7 g9 y$ v: D: m1 d通常情况下,当我们写int atom=10;时,就同时进行了变量的定义和初始化。" p* X) P# `& M# r2 n
, j4 B, v1 m1 b7 Z( U* Q
指针/ z' [  {; b+ h

4 e9 P7 Q" b5 [3 l, D+ V4 c( U% t内存就是一排大小都是一byte,且自己编号的抽屉。编号即抽屉的地址,里面的东西即抽屉的内容& ~  v& }) k/ @5 `2 D) W8 t  l
$ i3 ^; l0 S" Q5 C/ H' S/ N/ x
指针即"地址"。即抽屉的编号  k& X8 I. D0 P' z6 S0 W
8 k+ n# v; }- g% H9 O- d
指针变量即存储"标识符地址"的变量,即存放了另一个抽屉编号的抽屉,对指针变量"取值"即得到标识符的地址,即"指针的指向",对该变量"取址"即该变量本身存放的地址。当提及指针的时候,一定要注意说的是一个指针常量(一个地址), 还是一个指针变量,这是国内的教材非常差劲的一个习惯- N  E( Q. A* I) ]5 G) A
8 r- x0 |. d- P9 u% V' n
一个指针变量理论上可以存储任何标识符的地址,但是为了便于管理,C语言把指针变量也按照标识符的类型进行了划分。所以有了函数的指针,字符指针,数组指针etc. 但他们其实都一样,即虽然所有的抽屉的编号都是一张纸条,但某个抽屉只用来存储装了苹果的抽屉的编号,另一个抽屉只用来存储装了橘子的抽屉的编号。$ ?& e- Y0 E, l9 P, z
( d  q7 @5 n- K* g1 ]# G! E1 m
定义并初始化一个指针变量,由于运算符优先级的问题,并没有固定的定义格式,基本上每种不同的标识符都有自己的指针定义格式3 e6 E4 F" U0 _4 }/ Q9 P8 i
' l- Q0 G: Y$ l5 f
int* pVar=&var; //数据类型指针变量char (*ptr)[3]={'a','b','c'}; //数组指针变量,本质是指针,指向一个数组 VS char* str[10]={"this","is","a","string"};指针数组,本质是数组,每个元素都是一个指针int (*pFcn)(int x)=fcn; //函数指针变量,指向一个函数的地址,函数名就是一个指针1 F& n" \4 [% U* j# V/ Z0 l

9 Z4 _  }: K' B; \+ K/ k使用指针
4 ~% G3 z. A7 q1 q( ?% s8 E3 b9 w/ Z6 V( |; v4 \9 a
int var2=*pVar;//取值int** ppVar=*pVar;//取址,这里定义一个指向指针的指针变量
0 L, w8 _1 `( n  L9 f+ ]" W! f0 H  m& h
指针常量VS常量指针! i1 I7 b: B& F, V; R2 y. F
8 H; m# V5 l/ ~) c5 }4 O- d
指针常量const int* ptr表示不能通过指针修改指向的变量的内容( P0 @6 W5 O6 |; S- L( `: O
常量指针int* const ptr表示指针的指向不能改变。# q1 @: t7 j% I* u+ {) g) g
: P! |8 I# q# F0 E2 V; y; p! Z
基本数据类型char int etc.- [- y* j- y2 V1 ~) i
+ Y$ v# u+ U+ ^# m
基本数据类型是C语言规定好的数据类型,它们占据内存的大小,对该块内存的使用方式都是编译器规定好的,我们只能使用,不能更改。/ |# k5 N2 R" o  a/ ^4 k; `
在一个典型的32位操作系统中:  o0 R) a+ c1 o
; L2 j% m5 P" F6 y, X
数据类型占位符长度数值范围(指数表示)数值范围(数字表示)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  
# K, X" t1 u: J& u! M* I4 @. G6 h2 w3 D% Y& q! ^
Note:' d6 E: v+ v3 G9 D* n2 X
0 v& C+ k' q8 ?0 C, v1 Y
%f和%lf会保留小数点后多余的0(就算你写的5.2,也会输出5.200000),而%g和%lg不会保留哪些08 T& Z' a( ~8 I6 o
8 j, N3 L- y4 l( {
不同平台(eg:32位VS64位系统)数据类型的长度会有不同,具体需要用sizeof测,上表针对一般32位系统,以int为例,一个int占4byte,一个byte占8位,所以一个int由32位二进制表示,故int共能表示2^32个数
7 ^& ]/ g4 ]9 g5 Z8 `; ^
, q$ F9 ?1 E0 @( I  J% qfloat和double的范围是由指数的位数来决定的。float的指数位有8位,而double的指数位有11位,分布如下:8 e5 d" z/ ~1 l2 ]  s. _
float: 1bit(符号位) 8bits(指数位) 23bits(尾数位)! o* o+ c: [; K5 ~  w% J- i% V* y2 r
double: 1bit(符号位) 11bits(指数位) 52bits(尾数位)
, S# g6 Z8 K5 _: ESo,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
. Q) t* s: A1 |# I% }# p( l/ u. Wfloat的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;; i1 N; d1 I+ X, c
double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308" ~  b8 f3 v: W
0 ^5 O) v9 S! [
有符号的数据类型不是分“正数” 和 “负数”,而是 “非负数” 和 “负数”,其中的区别在于 0 是非负数里的,所以,只需要记住有多少个和有无符号就可以计算其范围& _! y# `/ m5 R4 @; R
; y6 J4 d1 @# |% a
基本数据类型与指针
  R6 F( X* r( I4 r& M
8 t( J0 F0 d( n. ^int var=10;int* pVar = &var; //定义并声明一个指向int类型变量的一个指针,并将其指向varint res=*pVar; //对一个指针取值int* pTest=pVar;; B5 U/ L9 ^' V) _
6 G; [* Z/ A+ Q$ z
字符串3 M$ z! z8 I5 M, u
$ F# A: B- C# D0 A) g, ~& Z. h4 Q
C语言中的字符串用"有效字符"来表示。7 O6 D7 G" n& U3 Y- F
C编译器会自动在有效字符之后再加一个\0(即ASCII的数字0)表示字符串的结束,所以一个字符串实际占用的byte数目是"有效字符数+1","Tom"!='T''o''m',前者是字符串,有'\0'结尾,占4byte,后者不是"字符串",而是"一串字符",没有'\0'结尾,占3byte。 有两种方式测试字符串的长度:sizeof和strlen()  F( t: Z( Q  ^0 m# c

! _5 I" f$ u6 }' C' l: U% Z2 Y: s, L! n定义一个字符串常量! g/ |/ F; T. ^3 q# ]7 z1 @
& b! w% Y, m$ n
char* str="this is a string";1 |, U9 x( l9 I$ e& q- ^
4 h& \; M% N& k- q
定义一个字符串数组% D; p4 |! |7 L& o7 \

; a7 q# E( }2 ~% g; _" w! }: Lchar str[]="this is a string";
2 V) n/ q7 ^2 n: N9 ~" R/ {
  u9 d. L" ~  z. }字符串与指针7 C9 t+ F9 s$ B" ^* X1 U4 h6 u/ }

+ d4 ?, l- q6 o* \当我们定义一个字符串常量的时候,C编译器其实干了三件事,1.找一块内存,把这个字符串的有效值放进去,2.字符串的结尾加一个'\0',3.把这个字符串的首地址放在标识符中。, b% `+ A% A% D* H( a
C语言的字符串有两种存储方式,字符串常量和字符串数组,二者存储的内容都一样,也都是一个返回字符串的首地址,区别是前者是常量,内存的内容不能修改,后者可以修改。
; V4 t. b9 y" `5 a! G
) ^' a" H7 P- l3 w数组[]
+ W) ]5 k  p" Z0 w' O2 M1 B, y6 P
& \% I5 s( P: r* P数组是在内存里一块区域里连续的存储数目固定的同一类型数据,这里的同一类型,既包括基本数据类型,也包括复合数据类型,指针等。一块数组可以用它的数组名唯一的表示,这个数组名其实就是这块内存的首地址,即第一个元素的首地址。定义数组时,元素的个数从1开始算,访问数组时,元素的个数从0开始算。所以数组名arr是第一个元素arr[0]的地址,arr+1是第二个元素arr[1]的地址,注意,arr+1不是第二个byte的地址,编译器会以一个元素所占的byte数为单位进行地址的增减。a[i]的实质就是将地址从a开始移动i个单位长度再解引用,即*(a+i)。& F( @  R7 i7 X: D+ Y+ p
定义一个一维数组$ L" [6 I# i+ r$ b  \7 j. v

2 t0 q- u& c% \: S1 U( C元素类型 数组名[元素的个数];7 l: G4 {1 s6 W+ x1 j8 x0 _

& C; X3 [; I8 m5 K; d& F# \二维(多维)数组本质上还是在一块连续的内存中存储数目确定的同一类型数据,只不过对这块数据进行了"分组",比如,同样的一块存储了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个数7 j. [$ L- m% C  g) j
, }* f  Y7 \" I) f5 Z# _5 E
定义一个二维数组' ]" y) ~7 M% m. D$ q6 V. u" A
: Q0 n( O4 K2 w3 ?5 y! N
元素类型 数组名[组数][每组元素数]
( H6 @( {- V& L8 T- ]6 [; h, W! `" a* T
5 m/ O9 f) a) ]# |0 ~0 |; S! r% J定义并初始化一个数组
1 C8 T( ^  d! g: d5 W
. I5 ?/ ~: t2 V- `char stu1Name[20]="Tom"; //定义并初始化字符数组,数组中前4byte被赋值char remark[20]={‘y‘,’e‘,’s‘}; //数组中前3byte被赋值int vector[]={1,2,3}; //如果数组元素全部列出,可以省略定义时的元素个数int vector2[][2]={1,2,3,4}; //如果没有歧义,二维数组的第一维可以省略,没有赋值的部分会被初始化为'0';2 Y3 `2 R' I7 v( P6 G5 g0 `
" d, v! c. G' Z" I
指针数组VS数组指针
" m) |3 I; @  X9 [: g: k8 d! I% x: L6 f" ?* Y
指针数组的核心词是"数组",所以指针数组表示的是里面的成员都是指针类型的数组
: U* C2 Z: H9 d2 C) q- }$ p( S
- L4 V' v1 Z3 iint* arr[10]; //arr用来存储10个指向int类型的指针char* strarr[10]; //strarr用来存储10个指向char类型的指针,因为字符串的实质就是char*,所以strarr是存储了10个字符串首地址的数组
5 j3 ~  W! A8 _1 f# u5 l* U* i3 d) F, l2 U8 H' y
数组指针的核心词是"指针",数组名本身就是一个指针常量,就是第一个元素的地址
9 D4 b( ~  ?% |. i+ @8 b3 ^1 W+ ?7 ?' Y' T0 [
int arr[10] = {1,2,34};int* pArr=arr; //将数组的地址赋值给数组指针
  C8 `0 a) ~0 S- C) X, Y' S  ^9 z7 e. ]5 L5 b+ z
但是数组指针多用在二维数组中,一个int* ptr可以指向int arr[3],但是不能指向二维数组,二维数组指针一定要除了元素类型还要至少标明数组的列数,形如int (*ptr)[3],则这个ptr才可以指向任何一个以int为元素类型,列数为3的数组,当然,也可以同时指定指向数组的行数和列数做进一步的限定。6 t% ]) r: O0 o* a8 ?; Q' ~8 i9 v
二维数组指针有行指针和列指针之分
/ w; `* {( M9 l6 k
# ~1 q( E" M& O6 f结构体struct
; x- h+ @) K3 H7 [1 |$ w/ d
) s. O4 |; ~8 `- P结构体是把不同的数据类型进行打包的一种数据类型,由程序员自己定义。既然说结构体是一种数据类型,而一个数据类型是没有值的,所以结构体在定义时不能进行赋值。
3 F6 U; s' f0 J/ ]定义一个有名结构体类型,使用变量列表创建变量,使用初始化列表进行初始化+ B' k1 ]1 C- W9 r! A2 D% m

4 L( F9 O- D# X' j& v1 B, ~7 r* astruct StuInfo{ int age; char name[20];}stu1={10,"Tom"},stu2={11,"Rendo"};* O8 q6 [( Q3 v1 R7 v

* o" X; i4 }5 P; c' u2 J( `+ ?定义一个结构体类型,习惯上将自定义的结构体类型的首字母大写,以便和变量进行区分
  E$ R" e- X4 f# _$ b, O$ x: r
3 E* w  d0 [! o8 o6 y) r( m! C0 ustruct StuInfo{ int age; char name[20];};//或typedef struct{ int age; char name[20];}StuInfo2;
. ]5 D" A  d- C$ n; l+ b' \2 w, V  ?( _2 t3 u+ I. G5 `! h
定义一个结构体类型的变量并进行列表初始化,列表初始化,即只能在初始化时使用,如果定义变量的时候不用,那么之后就只能逐个元素的赋值。
; y% v& l4 k7 T+ w
" H" r& S3 h1 ?3 l: Gstruct StudInfo stu1={10,"Tom"};//或StudInfo2 stu2={11,"Rendo"};# `5 y  A' c9 P3 d2 S9 G+ U
# `) Z/ b2 b/ C/ r" w
给结构体变量赋值
$ z  r* k& l: A4 f: p
- \, @& j# X' u, a3 g0 H' Hstu.age=10;stu.name[0]='T';stu.name[1]='o';stu.name[2]='m';stu.name[3]='\0';" ]) n# `' U+ E9 B* a3 J" _$ R
+ C. B# H/ m: [6 O* M5 h6 \( L( C1 O
结构体与指针( t& P4 r0 Q+ w* K# y, ^8 K6 U7 {
9 C- G1 Q5 b  {! h
struct StuInfo* pSt; //定义一个指向结构体StuInfo类型的指针struct StuInfo stu; //定义一个结构体StuInfo类型的变量pSt = &stu; //将结构体变量stu的地址赋给pSt
" I! }1 |/ Q0 R7 {9 `6 ?0 n
) ^& C. Q( W6 R2 {& E2 G共用体union
! P2 M4 o, [' j+ p' {0 _2 J8 Q2 i# M- [0 Q
共用体的各个成员共享同一块内存,如果各个成员的长度不同,会取最长的那个成员的长度作为共用体的长度( \# G* c0 u* e2 ?  c1 J

4 A2 ^0 U6 q- }$ w) W3 O2 I& O定义一个union3 ]+ D# T. s* S% u

4 b1 @# g6 N- A1 G- k7 h" h$ bunion Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;" L+ @. d8 Y, s
7 m# G4 s. j. d) \1 A) u
创建共用体变量. E" K( C+ i& v. J2 V& Q3 X
4 A/ m! u# u9 A& ^; z" [: G( E3 Z- p
union Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;
* D/ }  ^% O+ V3 v) |" _% k
# B1 I2 W! M8 \$ _定义一个共用体变量& }- Q: p5 U( l/ I! b. l
! t! i: R6 ], |  H' Q5 N$ V
union Data data1,data2;//或Data data1,data2;
. f) `1 @4 f1 m3 D
5 Z: I& h$ h5 o6 e使用共用体/ q* a5 ~! _) {  I3 U7 t0 l) Z- |

4 P1 c8 K8 H3 S5 Y9 ?3 edata1.num1=2;data2.num2=3.3;
$ z# U$ j5 Q6 r0 R; t/ R% H$ R, _/ G
枚举enum
5 j3 k; G" H2 P# f1 ], k) |
6 Y) A7 a2 s2 A. ~# H2 Q/ r+ A顾名思义,枚举就是一个一个的列举,枚举类型用自定义的元素来代替列举元素的编号,方便记忆,但是其本质上还是一个整数。
/ o1 D0 _9 g; W3 J: v定义一个enum类型weekday
# W- K+ V' U8 A: H! o+ R: Z  R
" g3 d2 d, p7 B/ S' X2 \enum weekday{sun,mon,tue,wed,thu,fri,sat};
0 d* _. N9 w) Q. ^" J+ O5 W
2 W& x  E# H5 k4 @' i3 O定义了一个weekday类型的变量; i+ R5 K: w3 R
# L" r6 s8 s' i4 V( D% e- X' i" r7 a# ]
enum weekday day;
: p& g5 Z: T6 S9 ~
  r( J) x/ d1 v, G, c使用day变量5 I7 H- E& N% w

  w( a9 Q9 s0 E4 L0 {) g/ lday=mon;
/ K  w# b, l0 |0 y2 q$ t, a& d! Z8 ]3 t! @
' @$ s4 K' E) e0 _
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-13 03:13 , Processed in 0.078125 second(s), 24 queries , Gzip On.

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

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

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