龙空技术网

《C语言》-(学习笔记3)

kawhi莱昂纳德 116

前言:

现时我们对“c语言移位运算符有什么用吗”大约比较注意,我们都想要学习一些“c语言移位运算符有什么用吗”的相关知识。那么小编也在网上搜集了一些有关“c语言移位运算符有什么用吗””的相关内容,希望兄弟们能喜欢,看官们快快来学习一下吧!

12.2 --随机数函数和静态变量

随机数函数:

/* rand0.c --生成随机数*/

static unsigned long int next = 1; /* 种子 */

unsigned int rand0(void)

{

next = next * 1103515245 + 12345;

return (unsigned int) (next / 65536) % 32768;

}

但是这是一种伪随机数,每次主程序运行,都开始于相同的种子1。

srand((unsigned int) time(0)); /* 随机种子 */

使用上面代码可以解决前面出现的问题

12.4 分配内存:

malloc()和free()

malloc()分配内存,但是不会为其赋名,返回动态分配内存块的首字节的地址。如果malloc()分配内存失败,将返回空指针。

举例:

double * ptd;

ptd = (double *) malloc(30 * sizeof(double));

以上代码为30个double类型的值请求存储空间,并设置ptd指向该位置。可以使用表达式ptd[0]来表达首元素。使用free(ptd)就可以把30个double大小的内存归还给内存池。

12.5.1 const类型限定符

1. 在指针和形参声明中使用const

const float * pf; /* pf 指向一个float类型的const值 */

注:创建了pf 指向的值不能被改变,而 pt 本身的值可以改变。

float * const pt; /* pt 是一个const指针 */

注:创建的指针pt本身的值不能更改。pt必须指向同一个地址,但是它所指向的值可以改变。也就是说*pt的内容可以改变。

const float * const ptr;

注:表明ptr既不能指向别处,它所指向的值也不能改变。

2. 对全局数据使用const

使用全局变量是一种冒险的方法,因为这样暴露数据,如果把数据设置成const,就可以避免这样的危险。然而在文件中共享const数据要小心。

采取策略:

第一, 遵循外部变量的常用规则,即在一个文件中使用定义式声明,再其他文件中使用引用式说明(extern关键字)。

第二,把const变量放在一个头文件中,然后在其他头文件中,包含该文件。

12.5.2—volatile类型限定符

Volatile 告诉计算机,代理可以改变该变量的值,通常,它被用于硬件地址以及在其他程序或同时运行的线程中共享数据,例如,一个地址上可能存储当前的时钟时间,无论程序做什么,地址上的值都随时间的变化而变化。或者一个地址用于接收另一台计算机传入的信息。

Volatile 涉及编译器的优化,目前的编译器在声明中没有关键字Volatile时,会假定变量的值在使用过程中不变,把变量放入高速缓冲区,这样当其再次被调用时,就可以被快速读取。但是当有关键字volatile 编译器人为该变量会被随时改变可以同时用const和volatile来限定一个值,通常用const把硬件时钟设置为程序不可以更改的变量,但是可以通过代理来改变。记住只能在声明中同时使用这两个限定符,先后顺序不重要。

volatile const int loc;

const volatile int * ploc;

12.5.3 –restrict类型限定符

Restrict 关键字允许编译器优化部分代码以更好地支持计算,它只能用于指针,表明该指针是访问数据对象的唯一且初始的方式。

举例:

int arr[10];

int * restrict restar = (int *) malloc(10 * sizeof(int));

int * par = arr;

其中指针restar 是访问由malloc()所分配内存的唯一且初始 化方式,因此可以用restrict关键字限制他,相反指针par就 没有这种特征,所有就不需使用restrict关键字。

CH14---结构和其他数据形式14.7 结构和结构指针

结构指针作为参数:执行快速,秩序传递一个参数,节省内存。缺点就是无法保护数据可以在形参前加const解决保护数据的问题。

结构作为参数:函数处理的是原数组的副本,保护了数据,并且代码 风格清晰。但是会浪费时间和存储空间,按值传递结构是处理小型结构最常用的方法。

14.7.7---结构、指针、malloc()

举例:

struct flex

{

int count;

double average;

double scores[]; // 伸缩型数组成员

};

struct flex * pf; // 声明一个指针

pf = malloc(sizeof(struct flex) + 5 * sizeof(double));

pf->count = 5; // 设置 count 成员

pf->scores[2] = 18.5; // 访问数组成员的一个元素

带伸缩型数组成员的结构有一些特殊的处理需求:

第一:不能用结构进行赋值或拷贝;这样做只能拷贝除了伸缩型数组成员以外的其他成员。

如:

struct flex * pf1, *pf2; // *pf1 和*pf2 都是结构

*pf2 = *pf1; // 不要这样做

第二:不要以按值方式把这种结构传递给结构。由于按值传递一个参数与赋值类似。而是要把结构的地址传递给函数。

第三:不要使用带伸缩型数组成员的结构作为数组成员或另一个结构的成员。

14.8---把结构内容保存到文件中

例如,可以将一个结构存储书籍的相关信息,最终要把这些信息存储在文件中,并且能再次检索。数据库文件可以包含任意数量的此类数据对象。存储在一个结构中的整套信息被称为记录(record)单独的项被称为字段(field)。

举例:

如果pbook标识一个文件流,如何把信息存储在struct book类型的结构变量primer中?

答:使用fread()和fwrite()函数读写结构大小的单元。

fwrite(&primer,sizeof(struct book),1,pbooks);

定位到primer 结构变量开始的位置,并把结构中所有的字节都拷贝到与pbooks 相关的文件中。Sizeof(struct book) 告诉函数待拷贝的一块数据的大小,1 表明一次拷贝一块数据。带相同参数的fread()函数从文件中拷贝一块结构大小的数据到&primer指向的位置。

14.10---联合简介

Union 是一种数据类型,它能在同一个内存空间中存储不同的数据类型(不是同时存储)。其典型用法是,设计一种表,存储既无规律事先也不知道顺序的混合类型。使用联合类型的数组,其中的联合都大小相等,每个联合可以存储各种数据类型。

联合模板:

union hold

{

int digit;

double bigfl;

char letter;

};

有了以上声明的结构可以定义以下变量:

union hold fit; // hold类型的联合变量

union hold save[10]; // 内含10个联合变量的数组

union hold * pu; // 指向hold类型联合变量的指针

使用联合:

fit.digit = 23; //把 23 储存在 fit,占2字节

fit.bigfl = 2.0; // 清除23,储存 2.0,占8字节

fit.letter = 'h'; // 清除2.0,储存h,占1字节

点运算符表示正在使用哪种数据类型,在联合中,一次只能存储一个值,即使有足够的空间,也不能同时存储一个char类型值和一个int值。和使用指针访问结构体的运算符->一样,用指针访问联合体也使用->运算符。

例如:

pu = &fit;

x = pu->digit; // 相当于 x = fit.digit

14.11---枚举类型

例如:声明

enum spectrum {

red,

orange,

yellow,

green,

blue,

violet

}; enum spectrum color;

第一个声明创建了spectrum 作为标记名,允许把Enum spectrum 作为一个类型名使用。第2个声明使color作为该类型的变量。可以执行以下操作:

int c;

color = blue;

if (color == yellow)

...;

for (color = red; color <= violet; color++)

...;

在枚举声明中,可以为枚举常量指定整数值:

如:enum levels {low = 100, medium = 500, high = 2000};

如果只给一个枚举常量赋值,没有对后面的枚举常量赋值,那么后面的常量会被赋予后续的值。如:

enum feline {cat, lynx = 10, puma, tiger};

那么,cat的值是0(默认),lynx、puma和tiger的值分别是10、11、 12。

14.12---typedef简介

Typedef 是一种高级数据特性,利用typedef 可以为某一类自定义名称。这与#define相同,但是依然有三处不同。

不同1:typedef创建的符号只受限于类型,不能用于值。

不同2:typedef 由编译器解释,不是预处理器。

不同3:在其首先范围内,typedef比#define更灵活。

举例:创建链表结点

Typedef struct node{

Int Data;

Struct node *Next;

}Node, *pNode;

Node 可解释成这个结构体类型的一个标识符;pNode 可解释为一种标识符,这种标识符为指向一种结构体的指针。

14.14---函数和指针

函数指针:通常,函数指针常用作另一个函数的参数,告诉该函数要使用哪个函数。

函数指针定义:由于函数也有地址,函数的机器语言是由载入内存的代码组成。故指向函数的指针中存储着函数代码的起始位置的地址。声明一个函数指针时,必须声明指针所指向的数据类型,为了指明函数类型,要指明函数声明,即函数的返回类型和形参类型

举例:

/*小写转换成大写的函数*/

void ToUpper(char *);

ToUpper()函数的类型是“带char * 类型参数、返回类型是void的函数”。

void (*pf)(char *); // pf 是一个指向该函数的指针声明了函数指针后,可以将匹配类型的函数地址赋给它。

如:pf = ToUpper;

用函数指针访问函数:

char arr[] = "tercel";

(*pf)(arr); //方法1

pf(arr); //方法2

方法1:pf指向ToUpper 函数,那么*pf就相当于ToUpper函数,即表达式(*pf)(arr)和ToUpper(arr) 相同。

方法2:由于函数名是指针,那么指针和函数名可以互换使用,所以pf(arr) 和ToUpper(arr)相同。

Typedef 和函数指针结合:

typedef void (*V_FP_CHARP)(char *);

利用这种数据类型可以声明并初始化一个函数指针的数组:

V_FP_CHARP arpf[4] = {ToUpper, ToLower, Transpose,Dummy};

CH15---位操作

15.3.1—按位逻辑运算

1---二进制反码或按位取反:~

~(10011010) == (01100101)

2---按位与:&

注:只有两个运算对象中相应的位都为1时,结果才为1。

(10010011) & (00111101) ==(00010001)

3---按位或:|

注:至少有一个为1,则为1,全为0时,才为0.

(10010011) | (00111101) == (10111111)

4---按位异或^

注:不同为1,相同为0.

(10010011) ^ (00111101) == (10101110)

15.3.2---用法:掩码

按位与运算符常用于掩码(mask)。所谓掩码指的是一些设置为开(1)或关(0)的位组合。

15.3.7---移位运算符

1---左移:<<

注:左侧运算对象溢出左末端位的值丢失,用0去填充空出的位置,举例:

(10001010) << 2 == (00101000)

2---右移:>>

注:左侧运算对象移出右末端位的值丢。对于无符号类型,用 0 填充空出的位置;对于有符号类型,其结果取决于机器。

举例1:

(10001010) >> 2 // 表达式,有符号值

(00100010) // 在某些系统中的结果值

(11100010) // 在另一些系统上的结果值

举例2:

(10001010) >> 2 // 表达式,无符号值

(00100010) // 所有系统都得到该结果值

CH16---c预处理器和c库16.1---翻译程序的第一步:

首先:编译器把源代码中出现的字符映射到源字符集。

第二:编译器定位每个反斜杠后面跟着换行符的实例,并删除他们。

第三:编译器把文本划分成预处理记号序列、空白序列和注释序列(记号是由空格、制表符或换行符分隔的项)。

16.2---明示常量:#define

#define预处理指令,以#号作为一行的开始。允许在#和指令的其余部分之间有空格。指令可以出现在源文件的任何地方,其定义从指令出现到该文 件末尾有效。

16.5---文件包含:#include

#include<stdio.h> // 查找系统目录

#include”hot.h” // 查找当前工作目录

#include "/usr/biff/p.h" //查找/usr/biff目录

注意:#define宏的作用域从它在文件中的声明处开始,直到用#

Undef指令取消宏为止,或延申至文件尾。

16.6.3---条件编译

1---#ifdef、#else和#endif指令

#ifedf指令说明,如果预处理器已定义了后面的标识符,则执行#else或#endif指令之前的所以指令并编译所有C代码(先出现那个指令就执行到哪里)。如果预处理未定义标识符,且有#else指令,则执行#else和#endif指令之间的所有代码。

16.6.7---内联函数

通常函数调用都有一定的开销,因为函数的调用过程包含建立调用

传递参数、跳转到函数代码并返回。

标签: #c语言移位运算符有什么用吗 #c语言指定位取反 #c语言 文件是否存在数据库 #未定义标识符end1怎么解决 #未定义标识符啥意思