今天我们继续来学习C语言的入门知识点
11. 作用域规则
任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:
在函数或块内部的局部变量
在所有函数外部的全局变量
在形式参数的函数参数定义中
让我们来看看什么是局部变量、全局变量和形式参数。
局部变量
在某个函数或块的内部声明的变量称为局部变量。它们只能被该函数或该代码块内部的语句使用。局部变量在函数外部是不可知的。下面是使用局部变量的实例。在这里,所有的变量 a、b 和 c 是 main() 函数的局部变量。
void main(){
//局部变量
int a, b;
int c;
//初始化局部变量
a = 10;
b = 20;
c = a + b;
//%d:以十进制形式输出带符号整数(正数不输出符号)
printf("values of a = %d,b = %d and c = %d ", a, b, c);
}
输出:values of a = 10,b = 20 and c = 30
全局变量
全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量。
全局变量可以被任何函数访问。也就是说,全局变量在声明后整个程序中都是可用的。下面是使用全局变量和局部变量的实例:
//全局变量声明
int g;
void main(){
int a, b;
//初始化局部变量
a = 10;
b = 20;
//全部变量赋值
g = a + c;
printf("values of a = %d,bc = %d and g = %d ", a, c, g);
}
输出:values of a = 10,bc = 30 and g = 40
形式参数
函数的参数,形式参数,被当作该函数内的局部变量,如果与全局变量同名它们会优先使用。下面是一个实例:
int sumA(int a, int b) {
printf("value of a in sum() = %d ", a);
printf("value of b in sum() = %d ", b);
return x + y;
}
void main(){
int a, b,c;
//初始化局部变量
a = 10;
b = 20;
c = sumA(a, b);
printf("value of c in main() = %d ", c);
}
输出:value of a in main() = 30
全局变量和局部变量的区别
(1)全局变量保存在内存的全局存储区中,占用静态的存储单元;
(2)局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
初始化局部变量和全局变量的默认值
12. 数组
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
声明数组
在 C 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
type arrayName [ arraySize ];
这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。例如,要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:
double balance[10];
初始化数组
void main(){
double balance[10] = {1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0}
}
大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果:
void main(){
double balance[] = {1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0}
}
您将创建一个数组,它与前一个实例中所创建的数组是完全相同的。下面是一个为数组中某个元素赋值的实例:
balance[1] = 50.5;
访问数组元素
//跟 Java 一样
double value = balance[1]
例子:
void main() {
//定义一个长度为 10 的整数数组
int n[10];
int i, j;
//初始化数组元素
for (i = 0; i < 10; i++) {
n[i] = 2 * i;
}
//输出元素中的数据
for (int k = 0; k < 10; ++k) {
printf("Element[%d] = %d ", k, n[k]);
}
//总的大小除以其中一个大小就得到了 数组长度
printf("整数数组 n 的长度: %d ", sizeof(n) / sizeof(n[0]));
//输出元素中的数据
for (int k = 0; k < sizeof(n) / sizeof(n[0]); ++k) {
printf("Element[%d] = %d ", k, n[k]);
}
}
输出:
Element[0] = 0
Element[1] = 2
Element[2] = 4
Element[3] = 6
Element[4] = 8
Element[5] = 10
Element[6] = 12
Element[7] = 14
Element[8] = 16
Element[9] = 18
整数数组 n 的长度: 10
Element[0] = 0
Element[1] = 2
Element[2] = 4
Element[3] = 6
Element[4] = 8
Element[5] = 10
Element[6] = 12
Element[7] = 14
Element[8] = 16
Element[9] = 18
C 中数组详解
在 C 中,数组是非常重要的,我们需要了解更多有关数组的细节。下面列出了 C 程序员必须清楚的一些与数组相关的重要概念:
13. 枚举
枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。
枚举语法定义格式为:
enum 枚举名 {枚举元素1,枚举元素2,……};
接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,我们需要使用 #define 来为每个整数定义一个别名:
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
这个看起来代码量就比较多,接下来我们看看使用枚举的方式:
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
这样看起来是不是更简洁了。
**注意:**第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
可以在定义枚举类型时改变枚举元素的值:
enum season {spring, summer=3, autumn, winter};
没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5
枚举变量的定义
前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量。
我们可以通过以下三种方式来定义枚举变量
1、先定义枚举类型,再定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
2、定义枚举类型的同时定义枚举变量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
3、省略枚举名称,直接定义枚举变量
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
14. 指针
学习 C 语言的指针既简单又有趣。通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的。
正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:
void main(){
int var1;
char var2[10];
//%p : 输出指针地址
printf("var1 变量的地址:%p ", &var1);
printf("var2 变量的地址:%p ", &var2);
}
输出:
var1 变量的地址:0x7ffee7e976b8
var2 变量的地址:0x7ffee7e976be
通过上面的实例,我们了解了什么是内存地址以及如何访问它。接下来让我们看看什么是指针。
什么是指针?
指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
type *var-name
在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:
int *i; //一个整型的指针
double *d;//double 型指针
float *f;//浮点型指针
char *ch//字符型指针
所有实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。
不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
如何使用指针?
使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:
例子:
//如何使用指针
int var = 66;//实际变量的声明
int *ip;//指针变量的声明
ip = &var; //指针变量中存储 var 的地址
printf("var 的地址 : %p ", var);
//在指针变量中存储的地址
printf("ip 的地址:%p ", ip);
//使用指针访问地址
printf("ip 指针对应的地址:%p ", *ip);
//使用指针访问地址对应的值
printf("ip 指针对应的地址:%d ", *ip);
输出:
var 的地址 : 0x42
ip 的地址:0x7ffee96eb6b4
ip 指针对应的地址:0x42
ip 指针对应的地址:66
C 中的 NULL 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
void main(){
//赋值一个 NULL 指针
int *ptr = NULL;
printf("ptr 的地址是: %p ", ptr);
//检查一个空指针
if (ptr) printf("如果 ptr 不是空指针,则执行"); else printf("如果 ptr 是空指针,则执行");
}
输出:ptr 的地址是: 0x0 ptr 是空指针
C 指针详解
在 C 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:
15. 函数指针与回调函数
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int)//声明一个指向同样参数,返回值得函数指针类型
回调函数
函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
简单讲:回调函数是由别人的函数执行时调用你实现的函数。
例子:
例子中 populate_array 函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。
实例中我们定义了回调函数 getNextRandomValue,它返回一个随机值,它作为一个函数指针传递给 populate_array 函数。
populate_array 将调用 10 次回调函数,并将回调函数的返回值赋值给数组。
#include <stdlib.h>
#include <stdio.h>
//回调函数
void populate_array(int *array, size_t arraySize, int(*getNextValue)(void)) {
printf("array 地址:%p ", array);
for (size_t i = 0; i < arraySize; i++) {
array[i] = getNextValue();
printf(" array[%d] ,存储值:%d ", i, array[i]);
}
}
//获取一个随机数
int getNextRandomValue(void) {
return rand();
}
void main() {
//回调函数
int array[10];
printf("Int array 地址:%p ", array);
populate_array(array, sizeof(array)/sizeof(array[0]), getNextRandomValue);
for (int i = 0; i < sizeof(array)/sizeof(array[0]); ++i) {
printf(" array[%d] , 对应值为:%d ", i, array[i]);
}
}
输出:
Int array 地址:0x7ffeebf1a650
array 地址:0x7ffeebf1a650
array[0] ,存储值:16807
array[1] ,存储值:282475249
array[2] ,存储值:1622650073
array[3] ,存储值:984943658
array[4] ,存储值:1144108930
array[5] ,存储值:470211272
array[6] ,存储值:101027544
array[7] ,存储值:1457850878
array[8] ,存储值:1458777923
array[9] ,存储值:2007237709
array[0] , 对应值为:16807
array[1] , 对应值为:282475249
array[2] , 对应值为:1622650073
array[3] , 对应值为:984943658
array[4] , 对应值为:1144108930
array[5] , 对应值为:470211272
array[6] , 对应值为:101027544
array[7] , 对应值为:1457850878
array[8] , 对应值为:1458777923
array[9] , 对应值为:2007237709
16. 字符串
在 C 语言中,字符串实际上是使用null字符 ' ' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 "Hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。
char ch[6] = {'H', 'e', 'l', 'l', 'o', ' '};
也可以使用以下简写模式:
char ch[6] = "Hello"
字符串在 C/C++ 中内存表示:
其实,您不需要把 null 字符放在字符串常量的末尾。C 编译器会在初始化数组时,自动把 ' ' 放在字符串的末尾。让我们尝试输出上面的字符串:
void main(){
//定义一个 char 数组
char string[6] = {'H', 'e', 'l', 'l', 'o', ' '};
//简写
char string2[6] = "Hello";
//%s:输出字符串
printf("string message : %s ", string);
}
输出:string message : Hello
C 中对字符串操作的 API
17. 结构体
C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性:
(1)Title
(2)Author
(3)Subject
(4)Book ID
定义结构
为了定义结构,您必须使用struct语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
struct name{
member-list;
member-list;
...
}name_tag,
name是结构的标签。
member-list是标准的变量定义,比如 int i;或者 float f,或者其它有效的变量定义。
name_tag结构变量,定义在结构的末尾,最后一个分号之前,你可以指定一个或多个结构变量,下面是声明 Book 的结构方式:
struct Books{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
注意:在定义结构体的时候name、member-list、name_tag 这 3 部分至少要出现 2 个。
结构体变量的初始化
和其它类型变量一样,在初始化的时候可以指定初始值。
//定义一个 Books 结构,类似于 Java 中的数据 bean
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
double rmb;
} book = {"Java", "Android", "C 语言", 666, 55.5};
void main(){
//打印 Books
printf("title : %s author: %s subject: %s book_id: %d rmb: %f ", book.title,
book.author, book.subject, book.book_id, book.rmb);
}
输出:
title : Java
author: Android
subject: C 语言
book_id: 666
rmb: 55.500000
访问结构成员
struct Books2 {
char title[50];
char author[50];
char subject[100];
int book_id;
};
void main(){
//访问 Books2 结构成员
struct Books2 Books2A;//声明 Books2A 类型为 Books2
struct Books2 Books2B;//声明 Books2B 类型为 Books2
//Books2A 详述
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 详述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
// 输出 Book1 信息
printf("Book 1 title : %s ", Books2A.title);
printf("Book 1 author : %s ", Books2A.author);
printf("Book 1 subject : %s ", Books2A.subject);
printf("Book 1 book_id : %d ", Books2A.book_id);
// 输出 Book2 信息
printf("Book 2 title : %s ", Books2B.title);
printf("Book 2 author : %s ", Books2B.author);
printf("Book 2 subject : %s ", Books2B.subject);
printf("Book 2 book_id : %d ", Books2B.book_id);
}
输出:
Book 1 title : C Plus
Book 1 author : Nuha Ali
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : DevYK
Book 2 subject : C++
Book 2 book_id : 666999
结构作为函数参数
//函数声明
void printBook(struct Books2 books2);
void main(){
//访问 Books2 结构成员
struct Books2 Books2A;//声明 Books2A 类型为 Books2
struct Books2 Books2B;//声明 Books2B 类型为 Books2
//Books2A 详述 ,将 CPlus copy 到 title 中
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 详述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
// 输出 Book1 信息
printf("Book 1 title : %s ", Books2A.title);
printf("Book 1 author : %s ", Books2A.author);
printf("Book 1 subject : %s ", Books2A.subject);
printf("Book 1 book_id : %d ", Books2A.book_id);
// 输出 Book2 信息
printf("Book 2 title : %s ", Books2B.title);
printf("Book 2 author : %s ", Books2B.author);
printf("Book 2 subject : %s ", Books2B.subject);
printf("Book 2 book_id : %d ", Books2B.book_id);
printf(" ");
//结构作为函数参数
printBook(Books2A);
printBook(Books2B);
}
void printBook(struct Books2 book) {
printf("Book title : %s ", book.title);
printf("Book author : %s ", book.author);
printf("Book subject : %s ", book.subject);
printf("Book book_id : %d ", book.book_id);
}
输出:
Book 1 title : C Plus
Book 1 author : Nuha Ali
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : DevYK
Book 2 subject : C++
Book 2 book_id : 666999
Book title : C Plus
Book author : Nuha Ali
Book subject : C
Book book_id : 666888
Book title : C++ Plus
Book author : DevYK
Book subject : C++
Book book_id : 666999
指向结构的指针
您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:
struct Books *struct_pointer;
现在,您可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:
struct_pointer = &Book1;
为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:
struct_pointer->title;
例子:
//定义指向结构的指针
void printBookZZ(struct Books2 *books2);
void main(){
//访问 Books2 结构成员
struct Books2 Books2A;//声明 Books2A 类型为 Books2
struct Books2 Books2B;//声明 Books2B 类型为 Books2
//Books2A 详述 ,将 CPlus copy 到 title 中
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 详述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
//通过内存地址传递信息,为了查找结构变量的地址,请把 & 运算符放在结构名称的前面
printBookZZ(&Books2A);
printBookZZ(&Books2B);
}
/**
* 为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:
* @param book
*/
void printBookZZ(struct Books2 *book) {
printf("Book -> title : %s ", book->title);
printf("Book -> author : %s ", book->author);
printf("Book -> subject : %s ", book->subject);
printf("Book -> book_id : %d ", book->book_id);
}
位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
典型的实例:
(1)用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
(2)读取外部文件格式——可以读取非标准的文件格式。
位域ed 定义:
struct 位域结构名称{
位域列表
};
位域列表的形式为:类型说明符 位域名:位域长度
例:
struct bean {
int a:8;
int b:4;
int c:4;
}data;
说明 data 为 bean 变量,共占 2个字节。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。
注意:
一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct bean{
unsigned a:4;
unsigned :4;//空域
unsigned b:4;//从下一个单元开始存放
unsigned c:4;
}
在这个位域定义中共占用 2 个字节,a 占第一字节的 4 位,后 4 位填 0 表示不使用,b 从第二字节开始,占用 4 位,c 占用 4 位。
由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。
位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k{
int a:1;
int :2; /* 该 2 位不能使用 */
int b:3;
int c:2;
};
从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
位域的使用
位域的使用和结构成员的使用相同,其一般形式为:
(1)位域变量名.位域名
(2)位域变量名->位域名
位域允许用各种格式输出。
18. 共用体
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
定义共同体
为了定义共用体,您必须使用union语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:
union [union tag]
{
member definition;
member definition;
...
member definition;
}[one or more union variables];
union tag是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,您可以指定一个或多个共用体变量,这是可选的。下面定义一个名为 Data 的共用体类型,有三个成员 i、f 和 str:
union Data
{
int i;
float f;
char str[20];
}
现在,Data类型的变量可以存储一个整数、一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。您可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。
共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的总内存大小:
union Data {
int i;
float f;
char str[20];
};
void main(){
union Data data;
printf("Memory size occupied by data: %d ", sizeof(data));
}
输出:Memory size occupied by data: 20
访问共同体成员
为了访问共用体的成员,我们使用成员访问运算符(.)。成员访问运算符是共用体变量名称和我们要访问的共用体成员之间的一个句号。您可以使用 union 关键字来定义共用体类型的变量。下面的实例演示了共用体的用法:
union Data {
int i;
float f;
char str[20];
};
void main() {
//1. 访问共同体 no
data.i = 10;
data.f = 1314.520;
strcpy(data.str,"C/C++");
printf( "data.i : %d ", data.i);
printf( "data.f : %f ", data.f);
printf( "data.str : %s ", data.str);
printf(" ");
//2. 访问共同体 yes
data.i = 10;
printf( "data.i : %d ", data.i);
data.f = 1314.520;
printf( "data.f : %f ", data.f);
strcpy(data.str,"C/C++");
printf( "data.str : %s ", data.str);
}
输出:
data.i : 725823299
data.f : 0.000000
data.str : C/C++
data.i : 10
data.f : 1314.520020
data.str : C/C++
在这里,我们可以看到上面注释 1 共用体的 i 和 f 成员的值有损坏,因为最后赋给变量的值占用了内存位置,这也是 str 成员能够完好输出的原因。我们看注释 2 ,这次我们在同一时间只使用一个变量成员,所以都能完好输出。
19. 位域
参考 17.(位域的介绍)
20. typedef
C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE:
typedef unsigned char BYTE;
在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:
BYTE b1, b2;
按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但您也可以使用小写字母,如下:
typedef unsigned char byte;
您也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。例如,您可以对结构体使用 typedef 来定义一个新的数据类型名字,然后使用这个新的数据类型来直接定义结构变量,如下:
typedef struct Books {
char title[50];
char author[50];
char subject[50];
int book_id;
} Book;
#define TRUE 1
#define FALSE 0
void main(){
Book book;
strcpy( book.title, "C 教程");
strcpy( book.author, "Runoob");
strcpy( book.subject, "编程语言");
book.book_id = 12345;
printf( "书标题 : %s ", book.title);
printf( "书作者 : %s ", book.author);
printf( "书类目 : %s ", book.subject);
printf( "书 ID : %d ", book.book_id);
printf( "TRUE 的值: %d ", TRUE);
printf( "FALSE 的值: %d ", FALSE);
}
输出:
书标题 : C 教程
书作者 : Runoob
书类目 : 编程语言
书 ID : 12345
TRUE 的值: 1
FALSE 的值: 0
typedef vs define
define是 C 指令,用于为各种数据类型定义别名,与typedef类似,但是它们有以下几点不同:
(1)typedef仅限于为类型定义符号名称,#define不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
(2)typedef是由编译器执行解释的,#define语句是由预编译器进行处理的。
例子可以参考上面是 #define 使用。
本节知识将会以分节的形式向大家展示,又想要学习C语言的小伙伴可以关注笔者!一起来加油呀~
自学C/C++编程难度很大,不妨和一些志同道合的小伙伴一起学习成长!
C语言C++编程学习交流圈子,【点击进入】微信公众号:C语言编程学习基地
有一些源码和资料分享,欢迎转行也学习编程的伙伴,和大家一起交流成长会比自己琢磨更快哦!