c语言学习

看W3C学ios开发,里面讲学ios开发钱必须先学会C语言开发,所以了解了一下C语言,以前上大学的时候也没学过C语言,直接学的C++;

1.简介:

C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。

优点
  • 易于学习。
  • 结构化语言。
  • 它产生高效率的程序。
  • 它可以处理底层的活动。
  • 它可以在多种计算机平台上编译。
关于 C
  • C 语言是为了编写 UNIX 操作系统而被发明的。
  • C 语言是以 B 语言为基础的,B 语言大概是在 1970 年被引进的。
  • C 语言标准是于 1988 年由美国国家标准协会(ANSI,全称 American National Standard Institute)制定的。
  • 截至 1973 年,UNIX 操作系统完全使用 C 语言编写。
  • 目前,C 语言是最广泛使用的系统程序设计语言。
  • 大多数先进的软件都是使用 C 语言实现的。
  • 当今最流行的 Linux 操作系统和 RBDMS MySQL 都是使用 C 语言编写的。
为什么要使用 C?

C 语言最初是用于系统开发工作,特别是组成操作系统的程序。由于 C 语言所产生的代码运行速度与汇编语言编写的代码运行速度几乎一样,所以采用 C 语言作为系统开发语言。下面列举几个使用 C 的实例:

  • 操作系统
  • 语言编译器
  • 汇编器
  • 文本编辑器
  • 打印假脱机
  • 网络驱动器
  • 数据库
  • 语言解释器
  • 实体工具

2.搭建开发环境

使用C语言进行开发,需要满足2个条件:文本编辑器和 C 编译器。
文本编辑器大家都有,所以最主要是C编译器。
源文件的代码是人类可读的代码,但是机器不能理解,因此需要进行编译,将源文件的代码转换为机器码,这样机器才可以理解,CPU才能执行。目前最常用的免费的C语言编译器是:GNU 的 C/C++ 编译器。

3.编译C代码

gcc xxx.c
编译后会生产a.exe
执行代码:
a.exe

4.基础语法

1.C tokens C的令牌

C程序由各种令牌组成:令牌可以是关键字、标识符、常量、字符串值、或是一个符号。

2.C 标识符内不允许出现标点字符,比如 @、$ 和 %。

C 是区分大小写的编程语言

3.保留字:这些保留字不能作为常量名、变量名或其他标识符名称
关键字 含义
auto
else
long
switch
break
enum
register
typedef
case
extern
return
union
char
float 浮点类型
short
unsigned
const
for
signed
void
continue
goto
sizeof
volatile
default
if
static
while
do
int
struct
_Packed
double

1.数据类型

分为4类:

  • 基本类型:它们是算术类型,包括两种类型:整数类型和浮点类型。
  • 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。
  • void类型: 类型说明符 void 表明没有可用的值。
  • 派生类型:它们包括指针类型、数组类型、结构类型、共用体类型和函数类型。数组类型和结构类型统称为聚合类型
2.函数的类型指的是函数返回值的类型
3.整数类型

通常是一个八位字节(一个字节)。

类型 存储大小 值范围
char 1 byte -128 到 127 或 0 到 255
unsigned char 1 byte 0 到 255
signed char 1 byte -128 到 127
int 2 或 4 bytes -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647
unsigned int 2 或 4 bytes 0 到 65,535 或 0 到 4,294,967,295
short 2 bytes -32,768 到 32,767
unsigned short 2 bytes 0 到 65,535
long 4 bytes -2,147,483,648 到 2,147,483,647
unsigned long 4 bytes 0 到 4,294,967,295

为了得到某个类型或某个变量在特定平台上的准确大小,您可以使用 sizeof 运算符。表达式 sizeof(type) 得到对象或类型的存储字节大小。

4.浮点类型:标准浮点类型的存储大小、值范围和精度的细节
类型 存储大小 值范围 精度
float 4 byte 1.2E-38 到 3.4E+38 6 位小数
double 8 byte 2.3E-308 到 1.7E+308 15 位小数
long double 10 byte 3.4E-4932 到 1.1E+4932 19 位小数
5.void类型,指定没有可用的值。它通常用于以下三种情况下:
序号 类型与描述
1 函数返回为空,C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);
2 函数参数为空,C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void);
3 指针指向 void,类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。

C变量

1.几种基本的变量类型:
类型 描述
char 通常是一个八位字节(一个字节)。这是一个整数类型。
int 对机器而言,整数的最自然的大小。
float 单精度浮点值。
double 双精度浮点值。
void 表示类型的缺失。

C 语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等

2.变量的定义

语法:type variable_list;
type 必须是一个有效的 C 数据类型,可以是 char、w_char、int、float、double、bool 或任何用户自定义的类型;

int a;
初始化:a =10;

不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的;

变量声明向编译器保证变量以给定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。
当您使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。
您可以使用 extern 关键字在任何地方声明一个变量。虽然您可以在程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。

3.左值Lvalues和右值Rvalues

C中有两种类型的表达式:
左值Lvalues:指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边。
右值Rvalues:术语右值(rvalue)指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。

变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。
int i = 90; //i 是左值,90是右值


C常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。

1.整数常量

可以是十进制、八进制、十六进制
前缀指定基数:0X,0x 十六进制,o表示八进制,无前缀表示十进制;
后缀:U、L组合(可大写可小写),U表示无符号整数,L表示长整数。

212 /* 合法的 /
215u /
合法的 /
0xFeeL /
合法的 /
078 /
非法的:8 不是八进制的数字 /
032UU /
非法的:不能重复后缀 /
各种类型的整数常量的实例:
85 /
十进制 /
0213 /
八进制 /
0x4b /
十六进制 /
30 /
整数 /
30u /
无符号整数 /
30l /
长整数 /
30ul /
无符号长整数 */

2.浮点常量

浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含小数点、指数,或同时包含两者。
当使用指数形式表示时,必须包含整数部分、小数部分,或同时包含两者。带符号的指数是用 e 或 E 引入的。
下面列举几个浮点常量的实例:
3.14159 /* 合法的 /
314159E-5L /
合法的 /
510E /
非法的:不完整的指数 /
210f /
非法的:没有小数或指数 /
.e55 /
非法的:缺少整数或分数 */

3.字符常量

字符常量是括在单引号中,例如,'x' 可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 'x')、一个转义序列(例如 '\t'),或一个通用的字符(例如 '\u02C0')。
在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。

下表列出了一些这样的转义序列码:

转义序列 含义
\ \ 字符
' ' 字符
" " 字符
? ? 字符
\a 警报铃声
退格键
\f 换页符
\n 换行符
\r 回车
\t 水平制表符
\v 垂直制表符
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数
4.字符串常量

字符串字面值或常量是括在双引号 "" 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
您可以使用空格做分隔符,把一个很长的字符串常量进行分行。
下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。
"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

5.定义常量

两种方式定义常量:
使用#define预处理器。#define identifier value
使用const关键字。const type variable = value;

请注意,把常量定义为大写字母形式,是一个很好的编程实践。


存储类
存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。
这些说明符放置在它们所修饰的类型之前。下面列出 C 程序中可用的存储类:
auto
register
static
extern

1.auto存储类

是所有局部变量默认的存储类。auto 只能用在函数内,即 auto 只能修饰局部变量。

2.register存储类

用于定义存储在寄存器中而不是 RAM 中的局部变量。
这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)。
寄存器只用于需要快速访问的变量,比如计数器。
还应注意的是,定义 'register' 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

3.static 存储类

指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。
因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
函数调用之间保持局部变量的值。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
在 C 编程中,当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。

4.extern 存储类

用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。
当您使用 'extern' 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候。


C运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 语言内置了丰富的运算符,并提供了以下类型的运算符:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 杂项运算符
    本章将逐一介绍算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和杂项运算符。
1.算数运算符

下表显示了 C 语言支持的所有算术运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 实例
+ 把两个操作数相加 A + B 将得到 30
- 从第一个操作数中减去第二个操作数 A - B 将得到 -10
* 把两个操作数相乘 A * B 将得到 200
/ 分子除以分母 B / A 将得到 2
% 取模运算符,整除后的余数 B % A 将得到 0
++ 自增运算符,整数值增加 1 A++ 将得到 11
-- 自减运算符,整数值减少 1 A-- 将得到 9

a++ 与 ++a 的区别: a++ 和 ++a的相同点都是给a+1,不同点是a++是先赋值再+1,而++a则是先+1再参赋值。

2.关系运算符

下表显示了 C 语言支持的所有关系运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:

运算符 描述 实例
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 不为真。
!= 检查两个操作数的值是否相等,如果不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 (A > B) 不为真。
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 (A >= B) 不为真。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 (A <= B) 为真。
3.逻辑运算符

下表显示了 C 语言支持的所有关系逻辑运算符。假设变量 A 的值为 1,变量 B 的值为 0,则:

运算符 描述 实例
&& 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 (A && B) 为假。
"||" 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 (A || B) 为真。
! 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 !(A && B)为真。
4.位运算符

位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011

运算符 描述 实例
& 按位与操作,按二进制位进行“与”运算。运算规则: (A & B) 将得到 12,即为 0000 1100
0&0=0;
0&1=0;
1&0=0;
1&1=1;

| 按位或运算符,按二进制位进行“或”运算。运算规则: (A | B) 将得到 61,即为 0011 1101
0|0=0;
0|1=1;
1|0=1;
1|1=1;

^ 异或运算符,按二进制位进行“异或”运算。运算规则: (A ^ B) 将得到 49,即为 0011 0001
0^0=0;
0^1=1;
1^0=1;
1^1=0

~ 取反运算符,按二进制位进行“取反”运算。运算规则: (~A ) 将得到 -61,即为 1100 0011,2 的补码形式,带符号的二进制数。
~1=0;
~0=1;

<< 二进制左移运算符。 A << 2 将得到 240,即为 1111 0000
左操作数的值向左移动右操作数指定的位数
(左边的二进制位丢弃,右边补0)。

>> 二进制右移运算符。 A >> 2 将得到 15,即为 0000 1111
左操作数的值向右移动右操作数指定的位数
(正数左补0,负数左补1,右边丢弃)。

5.赋值运算符

下表列出了 C 语言支持的赋值运算符:

运算符 描述 实例
= 简单的赋值运算符,把右边操作数的值赋给左边操作数 C = A + B 将把 A + B 的值赋给 C
+= 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 C += A 相当于 C = C + A
-= 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 C -= A 相当于 C = C - A
*= 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 C *= A 相当于 C = C * A
/= 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 C /= A 相当于 C = C / A
%= 求模且赋值运算符,求两个操作数的模赋值给左边操作数 C %= A 相当于 C = C % A
<<= 左移且赋值运算符 C <<= 2 等同于 C = C << 2
>>= 右移且赋值运算符 C >>= 2 等同于 C = C >> 2
&= 按位与且赋值运算符 C &= 2 等同于 C = C & 2
^= 按位异或且赋值运算符 C ^= 2 等同于 C = C ^ 2
= 按位或且赋值运算符 C |= 2 等同于 C = C| 2
6.杂项运算符

下表列出了 C 语言支持的其他一些重要的运算符,包括 sizeof()、&、* 和 ? :。

运算符 描述 实例
sizeof() 返回变量的大小。 sizeof(a) 将返回 4,其中 a 是整数。
& 返回变量的地址。 &a; 将给出变量的实际地址。
* 指向一个变量。 *a; 将指向一个变量。
? : 条件表达式 如果条件为真 ? 则值为 X : 否则值为 Y
7.运算符的优先级

运算符的优先级确定表达式中项的组合。
这会影响到一个表达式如何计算。某些运算符比其他运算符有更高的优先级,例如,乘除运算符具有比加减运算符更高的优先级。
例如 x = 7 + 3 * 2,在这里,x 被赋值为 13,而不是 20,因为运算符 * 具有比 + 更高的优先级,所以首先计算乘法 3*2,然后再加上 7。
下表将按运算符优先级从高到低列出各个运算符,具有较高优先级的运算符出现在表格的上面,具有较低优先级的运算符出现在表格的下面。在表达式中,较高优先级的运算符会优先被计算。

类别 运算符 结合性
后缀 () [] -> . ++ - - 从左到右
一元 + - ! ~ ++ - - (type)* & sizeof 从右到左
乘除 * / % 从左到右
加减 + - 从左到右
移位 << >> 从左到右
关系 <<= >>= 从左到右
相等 == != 从左到右
位与 AND & 从左到右
位异或 XOR ^ 从左到右
位或 OR | 从左到右
逻辑与 AND && 从左到右
逻辑或 OR || 从左到右
条件 ?: 从右到左
赋值 = += -= *= /= %=>>= <<= &= ^=|= 从右到左
逗号 , 从左到右

判断

1.判断语句

语句 描述
if 语句 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。
if...else 语句 一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。
嵌套 if 语句 您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。
switch 语句 一个 switch 语句允许测试一个变量等于多个值时的情况。
嵌套 switch 语句 您可以在一个 switch 语句内使用另一个 switch 语句。

2.? : 运算符

我们已经在前面的章节中讲解了 条件运算符 ? :,可以用来替代 if...else 语句。它的一般形式如下:
Exp1 ? Exp2 : Exp3;


循环

1.循环类型

C 语言提供了以下几种循环类型。点击链接查看每个类型的细节。
循环类型 描述
while 循环 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。
for 循环 多次执行一个语句序列,简化管理循环变量的代码。
do...while 循环 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。
嵌套循环 您可以在 while、for 或 do..while 循环内使用一个或多个循环。

2.循环控制语句

循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。
C 提供了下列的控制语句。点击链接查看每个语句的细节。

控制语句 描述
break 语句 终止 loop 或 switch 语句,程序流将继续执行紧接着 loop 或 switch 的下一条语句。
continue 语句 引起循环跳过主体的剩余部分,立即重新开始测试条件。
goto 语句 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。

3.无限循环

for( ; ; )
{
printf("This loop will run forever.\n");
}


函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
C 标准库提供了大量的程序可以调用的内置函数。函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。

在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体:函数主体包含一组定义函数执行任务的语句。

1.函数参数

如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
当调用函数时,有两种向函数传递参数的方式:

调用类型 描述
传值调用 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
引用调用 该方法把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

默认情况下,C 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的实际参数。


C 作用域规则:
任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:
在函数或块内部的局部变量
在所有函数外部的全局变量
在形式参数的函数参数定义中
让我们来看看什么是局部变量、全局变量和形式参数。

1.局部变量

在某个函数或块的内部声明的变量称为局部变量。它们只能被该函数或该代码块内部的语句使用。局部变量在函数外部是不可知的。

2.全局变量

全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量。
全局变量可以被任何函数访问。

3.形式参数

函数的参数,形式参数,被当作该函数内的局部变量,它们会优先覆盖全局变量。

4.初始化局部变量和全局变量

当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化,如下所示:

数据类型 初始化默认值
int 0
char ''
float 0
double 0
pointer NULL

正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果,因为未初始化的变量会导致一些在内存位置中已经可用的垃圾值。


数组
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。

1.数组的声明

type arrayName[arraySize]; //元素类型和数量

一维数组:double balance[10];

2.初始化数组

double balance[5] = {100.0,2.0,3.4,7.0,50.0};
大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数;
double balance[] = {1000.0,2.0,3.4,7.0,50.2,23.4};

3.数组元素赋值

balance[3] = 50.9; //为某个数组元素赋值

4.访问数组元素

double salary = balance[9]; //将数组中的第10个元素赋值给salary

5.中数组详解

在 C 中,数组是非常重要的,我们需要了解更多有关数组的细节。下面列出了 C 程序员必须清楚的一些与数组相关的重要概念:

概念 描述
多维数组 C 支持多维数组。多维数组最简单的形式是二维数组。
传递数组给函数 您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
从函数返回数组 C 允许从函数返回数组。
指向数组的指针 您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。

指针
通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的。

1.什么是指针?

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
指针变量声明的一般形式为:type *var-name

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch     /* 一个字符型的指针 */

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。
不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

2.如何使用指针?

使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符*来返回位于操作数所指定地址的变量的值。
下面的实例涉及到了这些操作:

3.NULL 指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。

int  *ptr = NULL;
printf("ptr 的值是 %x\n", ptr  );   //结果为0

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
如需检查一个空指针,您可以使用 if 语句,如下所示:

if(ptr)     /* 如果 p 非空,则完成 */
if(!ptr)    /* 如果 p 为空,则完成 */
4.指针详解

下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:

概念 描述
指针的算术运算 可以对指针进行四种算术运算:++、--、+、-
指针数组 可以定义用来存储指针的数组。
指向指针的指针 C 允许指向指针的指针。
传递指针给函数 通过引用或地址传递参数,使传递的参数在调用函数中被改变。
从函数返回指针 C 允许函数返回指针到局部变量、静态变量和动态内存分配。

字符串

1.在 C 语言中,字符串实际上是使用 null 字符 '' 终止的一维字符数组。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。
char  greeting[6] = {'H','e','l','l','o','\0'};
char  greetingT[] = "Hello";
//这两个是一样的。
index 0 1 2 3 4 5
variable H e l l o \0
Address 0X213451 0X213452 0X213453 0X213454 0X213455 0X213456

C中有大量操作字符串的函数:包含在#include头文件中

序号 函数 & 目的
1 strcpy(s1, s2);
复制字符串 s2 到字符串 s1。
2 strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾。
3 strlen(s1);
返回字符串 s1 的长度。 greeting = 5,greetingT = 5
4 strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1s2 则返回大于 0。
5 strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6 strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。结构用于表示一条记录。

1.定义结构

关键字:struct
struct 语句的格式如下:

{
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];  

structure tag 是可选的,每个 member definition 是标准的变量定义,

2.访问结构成员

为了访问结构的成员,我们使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。
您可以使用 struct 关键字来定义结构类型的变量。

* Book1 赋值 */
 strcpy( Book1.title, "C Programming");
 strcpy( Book1.author, "Nuha Ali"); 
 strcpy( Book1.subject, "C Programming Tutorial");
 Book1.book_id = 6495407;
  /* 输出 Book1 信息 */
 printf( "Book 1 title : %s\n", Book1.title);
 printf( "Book 1 author : %s\n", Book1.author);
 printf( "Book 1 subject : %s\n", Book1.subject);
 printf( "Book 1 book_id : %d\n", Book1.book_id);
3.指向结构体的指针

struct Books *struct_pointer;
struct_pointer = &Book1; //为了查找结构变量的地址,请把 & 运算符放在结构名称的前面
为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:

struct_pointer->title;
4.结构作为函数参数

eg:

void printBook( struct Books *book )
{
   printf( "Book title : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", book->book_id);
}
5.位域

C 语言又提供了一种数据结构,称为"位域"或"位段"。节省存储空间。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

A.位域的定义和位域变量的说明
struct 位域结构名
    { 位域列表 };

B.位域列表的形式为:
类型说明符 位域名: 位域长度 
eg:
    struct bs{
        int a:8;
        int b:2;
        int c:6;
    };

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。

struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;

说明 data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。

对于位域的定义尚有以下几点说明:

  1. 一个位域必须存储在同一个字节中,不能跨两个字节。
  2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
  3. 位域可以是无名位域,这时它只用来作填充或调整位置。
  4. 无名的位域是不能使用的。
    位域在本质上就是一种结构类型,不过其成员是按二进位分配的

位域的使用
位域变量名·位域名


共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。
定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。
共用体提供了一种使用相同的内存位置的有效方式。

1.定义共用体

使用union(联盟)语句定义,

union  [union tag](可选)
{

    member definition;
    member definition;
    .
    .
    .
    
}[one or more union variables];
eg:
union Data
{
    ini  i;
    float f;
    char str[20];
}data;

Data 类型的变量可以存储一个整数、一个浮点数,或者一个字符串.

2.使用共用体
union Data  data ;
3.共用体成员的访问
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");

printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);

结果:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

只有最后一个数据是有效的


位域

。。。。。


typedef

1.typedef 关键字,您可以使用它来为类型取一个新的名字。

typedef unsigned char BYTE; //为单字节数字定义了一个术语 BYTE

typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Book;

将Books这种类型的结构体更名为Book

2.typedef vs #define

#define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:
typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

eg:
#define TRUE  1
#define FALSE 0

你可能感兴趣的:(c语言学习)