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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
声明,定义和初始化
3 ]- a0 o7 w! I2 D- g3 \6 A! R
$ `3 u* f. l( o- M. D声明标识符iden是告诉编译器"有这么一个变量var,具体var里是什么,你自己去看"。声明只需要标识符的类型和标识符名字,C语言的任何标识符在使用前都需要声明,当然变量也不例外;如果标识符的定义代码在使用之前,那么定义的代码可以看作是声明,否则需要声明定义标识符iden是告诉编译器"这个iden是什么";2 y. b9 X+ i$ d" e. m, ]
初始化标识符iden是定义iden时给iden赋值,一个没有被赋值的iden里面存的是之前这块内存的值,就可能是任意的值,一不小心使用这样的标识符是十分危险的,所以一个好的习惯是定义一个标识符后立即初始化;另外一个原因是常量的值必须在初始化时确定,如果不进行初始化,那么这个常量以后永远都不能赋值了
1 Y4 E( q" J; \通常情况下,当我们写int atom=10;时,就同时进行了变量的定义和初始化。
4 R5 p6 F, |% ]. M  ^! D4 V
1 R. H( r8 N; H1 n" D指针
0 \/ T# Z9 p; g* v$ I. S# g% P& h8 c' c$ F3 b
内存就是一排大小都是一byte,且自己编号的抽屉。编号即抽屉的地址,里面的东西即抽屉的内容1 X2 |  d; `( X5 \

: ~' f& x# h5 ?# Z. K指针即"地址"。即抽屉的编号6 y' s  Y! _& f2 u* P& [
5 {1 y- l! D  D0 a
指针变量即存储"标识符地址"的变量,即存放了另一个抽屉编号的抽屉,对指针变量"取值"即得到标识符的地址,即"指针的指向",对该变量"取址"即该变量本身存放的地址。当提及指针的时候,一定要注意说的是一个指针常量(一个地址), 还是一个指针变量,这是国内的教材非常差劲的一个习惯4 _* v; J, a% ]

) c9 a4 K& _8 Z8 Z1 p% B一个指针变量理论上可以存储任何标识符的地址,但是为了便于管理,C语言把指针变量也按照标识符的类型进行了划分。所以有了函数的指针,字符指针,数组指针etc. 但他们其实都一样,即虽然所有的抽屉的编号都是一张纸条,但某个抽屉只用来存储装了苹果的抽屉的编号,另一个抽屉只用来存储装了橘子的抽屉的编号。: s7 M) u2 j, A8 [" u
7 a; w2 S. N6 f
定义并初始化一个指针变量,由于运算符优先级的问题,并没有固定的定义格式,基本上每种不同的标识符都有自己的指针定义格式; z% Q, Q. L" o7 n' D* T
2 z  E+ X  y& h( \3 J5 ^
int* pVar=&var; //数据类型指针变量char (*ptr)[3]={'a','b','c'}; //数组指针变量,本质是指针,指向一个数组 VS char* str[10]={"this","is","a","string"};指针数组,本质是数组,每个元素都是一个指针int (*pFcn)(int x)=fcn; //函数指针变量,指向一个函数的地址,函数名就是一个指针
6 X1 g5 J7 j  w, q8 K
+ f8 Q2 n1 M6 _# F& W6 c2 _使用指针. q: K/ @2 b$ \: y3 j- }% p
& ?+ B/ G1 ]; W
int var2=*pVar;//取值int** ppVar=*pVar;//取址,这里定义一个指向指针的指针变量
: }- @0 y( h) A" B; S# b& ?6 M9 D) y. l% C0 b
指针常量VS常量指针
. m' T( o8 Z' j& I2 `* o- i6 m( Q# [) V! {
指针常量const int* ptr表示不能通过指针修改指向的变量的内容6 \# V* J7 {0 U& U! g& g
常量指针int* const ptr表示指针的指向不能改变。
! X& f) [3 U$ ^1 b& W2 B+ L4 r- _+ q2 n
基本数据类型char int etc.$ t7 J$ C4 I) B/ _

3 v- _2 a- L; c' e6 }  F" Z基本数据类型是C语言规定好的数据类型,它们占据内存的大小,对该块内存的使用方式都是编译器规定好的,我们只能使用,不能更改。
# R6 E( B; z  l5 T在一个典型的32位操作系统中:8 C  i- d# q% f1 ~3 a: B
' Z9 s* x2 n1 b$ y" I
数据类型占位符长度数值范围(指数表示)数值范围(数字表示)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  
& A% y) [, {, ]- Z& e+ o
% F/ \5 t" c( O1 y* e0 I/ hNote:
* T, G) N  ~' W+ }9 M( g7 G
) Z2 o4 {3 Z/ S7 [8 y0 ?%f和%lf会保留小数点后多余的0(就算你写的5.2,也会输出5.200000),而%g和%lg不会保留哪些0
$ G4 I) @! @- i/ \; n. @7 E! M& G1 Z' c0 f( J2 G& j# }" p
不同平台(eg:32位VS64位系统)数据类型的长度会有不同,具体需要用sizeof测,上表针对一般32位系统,以int为例,一个int占4byte,一个byte占8位,所以一个int由32位二进制表示,故int共能表示2^32个数
9 f; K: h- K" a3 I( o
2 G! P& ?' `7 Y- Jfloat和double的范围是由指数的位数来决定的。float的指数位有8位,而double的指数位有11位,分布如下:* C+ X/ |' x6 Q! A6 t+ `
float: 1bit(符号位) 8bits(指数位) 23bits(尾数位)4 ~3 B) Y7 H8 e9 E# f
double: 1bit(符号位) 11bits(指数位) 52bits(尾数位)
1 S. \  j* n( `So,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。9 _5 B* C) e+ g0 o5 n
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
( K% z3 M8 H1 Q! r9 `" o7 `9 p& xdouble的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308
8 r* I" S& o; F. f! T% E' W; q; G$ S7 Q) w
有符号的数据类型不是分“正数” 和 “负数”,而是 “非负数” 和 “负数”,其中的区别在于 0 是非负数里的,所以,只需要记住有多少个和有无符号就可以计算其范围5 q: x! H) y, G2 i

8 }) e/ [8 F9 j基本数据类型与指针- r  N$ Y/ V8 J* c; c5 Z# K4 N
$ p. u) N. ]! ~- w
int var=10;int* pVar = &var; //定义并声明一个指向int类型变量的一个指针,并将其指向varint res=*pVar; //对一个指针取值int* pTest=pVar;; V: H. g4 O  [
6 F9 @+ ?! o, n' f6 W( B& O: Z
字符串9 V: L; D  a4 n' f: y

7 N9 q* _5 |3 `C语言中的字符串用"有效字符"来表示。
  C* _0 e; l% LC编译器会自动在有效字符之后再加一个\0(即ASCII的数字0)表示字符串的结束,所以一个字符串实际占用的byte数目是"有效字符数+1","Tom"!='T''o''m',前者是字符串,有'\0'结尾,占4byte,后者不是"字符串",而是"一串字符",没有'\0'结尾,占3byte。 有两种方式测试字符串的长度:sizeof和strlen(): L3 c0 N% O* Z  L7 q/ [6 A
- H! e, X/ `  A( f2 ?% F5 q
定义一个字符串常量; c& {$ H* d& {2 V6 f* ?! M

, S% e, B# o, c6 {5 E# i& u: lchar* str="this is a string";; E) U1 l6 A' C

3 h% e" _/ ]/ O7 f定义一个字符串数组
) M  I) ]1 R9 O9 a3 n. E. d3 h- C
char str[]="this is a string";" g( W! `& T+ o' z/ `1 ?  u* ~

* f4 n* ^3 x9 t) {( w. O字符串与指针- G& G4 b+ u7 L. P6 _6 a9 d
& t" a" V- F- f0 a
当我们定义一个字符串常量的时候,C编译器其实干了三件事,1.找一块内存,把这个字符串的有效值放进去,2.字符串的结尾加一个'\0',3.把这个字符串的首地址放在标识符中。2 p6 m* q, C* [# F
C语言的字符串有两种存储方式,字符串常量和字符串数组,二者存储的内容都一样,也都是一个返回字符串的首地址,区别是前者是常量,内存的内容不能修改,后者可以修改。! R0 B2 _( i, l* |0 V& w5 @
: K+ e' r5 P3 R
数组[]
+ a9 ~5 \' {$ T8 b
4 X$ w) z5 @7 W9 {$ s数组是在内存里一块区域里连续的存储数目固定的同一类型数据,这里的同一类型,既包括基本数据类型,也包括复合数据类型,指针等。一块数组可以用它的数组名唯一的表示,这个数组名其实就是这块内存的首地址,即第一个元素的首地址。定义数组时,元素的个数从1开始算,访问数组时,元素的个数从0开始算。所以数组名arr是第一个元素arr[0]的地址,arr+1是第二个元素arr[1]的地址,注意,arr+1不是第二个byte的地址,编译器会以一个元素所占的byte数为单位进行地址的增减。a[i]的实质就是将地址从a开始移动i个单位长度再解引用,即*(a+i)。8 h2 i$ i! Q2 r, S* Z$ o
定义一个一维数组
0 Z* E. O7 {$ o1 x
- D8 T' x) U& h" P1 O元素类型 数组名[元素的个数];7 I; m: o! [# H* K# F5 u
1 g, s& C3 H2 x3 E& n8 p
二维(多维)数组本质上还是在一块连续的内存中存储数目确定的同一类型数据,只不过对这块数据进行了"分组",比如,同样的一块存储了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个数
  u6 z6 q0 K! O0 |" h; i8 @' C; u9 W# Q! ~) q
定义一个二维数组1 O& a7 ]0 ~3 S1 y4 c* s) o
% K3 P+ h/ r" K0 c% K8 Q# d, U6 k% W
元素类型 数组名[组数][每组元素数]
$ \2 G% W8 o, K# j% ^) j% v3 A0 d1 H& s0 k
定义并初始化一个数组$ m* y( L% Y2 a4 p6 ], m6 l

% ~0 x1 q2 y& K9 Z+ M* k8 Z: M, g2 N/ Lchar stu1Name[20]="Tom"; //定义并初始化字符数组,数组中前4byte被赋值char remark[20]={‘y‘,’e‘,’s‘}; //数组中前3byte被赋值int vector[]={1,2,3}; //如果数组元素全部列出,可以省略定义时的元素个数int vector2[][2]={1,2,3,4}; //如果没有歧义,二维数组的第一维可以省略,没有赋值的部分会被初始化为'0';4 H8 M3 a% \) O/ q* m! e3 Q
) U6 i# i* y( k7 _, l) k8 E
指针数组VS数组指针
- Q& o4 |3 A, T; k# |( m7 x+ z& Q- W9 a0 |# R$ N2 `
指针数组的核心词是"数组",所以指针数组表示的是里面的成员都是指针类型的数组
3 b) X/ [4 q1 Q' a- O( o! m
3 W& k9 q; L, oint* arr[10]; //arr用来存储10个指向int类型的指针char* strarr[10]; //strarr用来存储10个指向char类型的指针,因为字符串的实质就是char*,所以strarr是存储了10个字符串首地址的数组
2 T; B3 `1 P+ k6 v3 y2 s' `1 I
; M, U# D' ^9 b) M数组指针的核心词是"指针",数组名本身就是一个指针常量,就是第一个元素的地址1 x: B4 p, ^3 i( U# m. q5 h

' n0 X$ J; p& d3 X# h$ N- h) U, u# c+ iint arr[10] = {1,2,34};int* pArr=arr; //将数组的地址赋值给数组指针
0 H# ^! h1 M1 n/ X5 ^
. s6 C9 T1 }- n1 ]% h0 p; q$ n但是数组指针多用在二维数组中,一个int* ptr可以指向int arr[3],但是不能指向二维数组,二维数组指针一定要除了元素类型还要至少标明数组的列数,形如int (*ptr)[3],则这个ptr才可以指向任何一个以int为元素类型,列数为3的数组,当然,也可以同时指定指向数组的行数和列数做进一步的限定。
9 S% \2 g/ x& k- w4 U0 j+ s6 l二维数组指针有行指针和列指针之分
% K% z3 g: H( c+ }  W0 C3 U; c8 b
) x7 T9 v7 X0 O+ u0 a3 L* P' K# a结构体struct
) G( g+ \: N  M2 o
7 u8 H' m  x6 e/ u* X3 M8 E( Q; S结构体是把不同的数据类型进行打包的一种数据类型,由程序员自己定义。既然说结构体是一种数据类型,而一个数据类型是没有值的,所以结构体在定义时不能进行赋值。
6 J% }; o7 U6 |; g& R定义一个有名结构体类型,使用变量列表创建变量,使用初始化列表进行初始化
! Q% [# O7 w: `7 z/ k9 w/ k7 ~
# X" y* I6 S# }$ z  ~1 {struct StuInfo{ int age; char name[20];}stu1={10,"Tom"},stu2={11,"Rendo"};
$ m; G$ }& q5 W/ p+ \( B3 z$ e
" o' I7 M6 V& B1 a# `) i定义一个结构体类型,习惯上将自定义的结构体类型的首字母大写,以便和变量进行区分8 A: e# s  T$ S( W9 ]# C% d8 {) L
% L  S4 S' V' W$ m% K
struct StuInfo{ int age; char name[20];};//或typedef struct{ int age; char name[20];}StuInfo2;
  _% o, p+ F& x4 E9 `
2 V* L" h* i$ c' }% P3 Y定义一个结构体类型的变量并进行列表初始化,列表初始化,即只能在初始化时使用,如果定义变量的时候不用,那么之后就只能逐个元素的赋值。5 ^/ G) o2 s7 w  w  Z" V

; X! b; r8 K. G7 x/ Wstruct StudInfo stu1={10,"Tom"};//或StudInfo2 stu2={11,"Rendo"};
! |8 ]& u) m: N7 A5 }. L6 [2 L+ q7 a  W" K6 V
给结构体变量赋值
+ `, S, L5 |& j' R1 H; D. t" W# {& b6 \% J5 K: U9 z! g3 V
stu.age=10;stu.name[0]='T';stu.name[1]='o';stu.name[2]='m';stu.name[3]='\0';' d7 |9 T& @& X$ D

6 t) [- _* o, b结构体与指针* V( h2 s" P  j% G- B. u3 t

. O4 y) ~1 P/ @+ E7 zstruct StuInfo* pSt; //定义一个指向结构体StuInfo类型的指针struct StuInfo stu; //定义一个结构体StuInfo类型的变量pSt = &stu; //将结构体变量stu的地址赋给pSt
. O  i0 @, Q5 [
/ n' f2 X3 h8 W2 i0 P' K9 Q& h共用体union  _  l9 s& L, l; ~+ x

2 s) d) Y$ x9 Y: l共用体的各个成员共享同一块内存,如果各个成员的长度不同,会取最长的那个成员的长度作为共用体的长度. L" F* J# c4 o, c" H

# N) a7 V% Q5 v$ S. t" u1 z. O定义一个union& H3 J9 O# D2 O/ m

, l0 w2 {" |1 q4 X$ Wunion Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;
9 X! y" P7 _. ?, |; m9 h' F
! r" d6 z$ v/ |, P% Z创建共用体变量; n4 V* P) o: _% `

' a/ }" U( P  m8 n# w. vunion Data{ int num1; double num2;};//或typedef union{ int num1; double num2;}Data;
4 J. B: @& V" w" n4 w. w
5 |/ k3 I3 x# M: w% u6 N3 h定义一个共用体变量
+ k$ q; w% e# W$ c" w! R2 @6 Y7 N2 ?/ k- H% k! q, R2 b: w
union Data data1,data2;//或Data data1,data2;
$ U- u( G6 Q" T7 |! d& L$ m* _; I
使用共用体' X* n2 \0 h! o; I! f
& m% j' b+ J2 J1 N
data1.num1=2;data2.num2=3.3;4 Y6 S5 z' x" \# Z5 C/ P
6 U( X9 ]& e  g5 N8 |6 e& I9 f) e
枚举enum
, d8 I9 X4 s, A+ [# F, x& [5 ?" ?
顾名思义,枚举就是一个一个的列举,枚举类型用自定义的元素来代替列举元素的编号,方便记忆,但是其本质上还是一个整数。
( W8 Q, {5 W0 P; z, @定义一个enum类型weekday
3 {: {* B. W( f( g  ^& I
1 ^4 ]3 w# s5 _% v2 venum weekday{sun,mon,tue,wed,thu,fri,sat};# O: i3 x( n: r

! J8 Q4 h0 U; p0 D( D& c0 S: e定义了一个weekday类型的变量
9 j7 Q3 [* T* R, g8 I6 G: u( t: C. g1 \; m7 _2 V6 X
enum weekday day;+ p' D5 d/ J& R2 b! V5 `4 V2 I
! @1 T& ^, p- N8 M
使用day变量
, Y7 B3 ]; E- N# d* G2 S' B, w+ _* e' G3 Z2 D: x7 x: l& c
day=mon;
. F$ t8 ]# i. ~$ E; g8 f/ |1 F4 ?: f+ j2 a) v  |3 u
2 s& z3 T: ?! n% D
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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