博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序设计导引及在线实践--读书笔记一
阅读量:5159 次
发布时间:2019-06-13

本文共 7182 字,大约阅读时间需要 23 分钟。

第一章
 
一、知识点
1、#include是C语言的保留字,表示要把另一个文件中的内容包含在本文件中。类似的还有sizeof也是一个保留字,同时它还是一个运算符。(P12)
 
2、
变量是内存中的一块区域,在程序运行过程中可以修改这块区域中存放的数值。
变量的名称是这个内存区域的唯一标识。变量的类型决定了这个内存区域的大小、对所存数值的类型要求。(P13)
 
3、C语言中的基本数据类型及其范围、大小:(P14)

4、在赋值语句中,如果等号左边的变量类型为T1,等号右边的变量或常量类型为T2,T1和T2不相同,那么编译器会将等号右边的变量或常量的值,自动转换为一个T1类型的值,再将此值赋给等号左边的变量。这个过程叫做“自动类型转换”。比如:
int a = 9;
a = 7.3;
printf("%d", a);
输出结果是7. 自动类型转换并不改变等号右边的变量。能进行自动类型转换的前提是,T1和T2是两个兼容的类型。(P15)
 
5、对于int值赋给char的情况:
int n1 = 1378;
char c = 'a';
c = n1;
printf("c = %c\n", c);
输出结果是才变为‘b’。解释:语句执行时,先将右边的int值自动转换为一个char类型的值,再赋值给c。由于char类型的变量只要1个字节,所以自动转换的过程就是丢弃n1的高3字节(int值为4个字节),只取n1中最低的那个字节赋值给c。n1的值是1378,表示成十六进制是562,最低的字节是0x62。因此,本语句执行后,c中就存放着字母‘b’。
 
6、const与#define最大的差别,Const在堆栈分配了空间,而#define只是把具体数值直接传递到目标变量罢了。或者说,const的常量是一个Run-Time的概念,他在程序中确确实实的存在可以被调用、传递。而#define常量则是一个Compile-Time概念,它的生命周期止于编译期:在实际程序中他只是一个常数、一个命令中的参数,没有实际的存在。const常量存在于程序的数据段。#define常量存在于程序的代码段。
但是根据编译器的不同,还略有不同:
◆C编译器
在C编译下,Const常量是完全分配了内存空间的,在使用时,是像变量一样来使
◆C++编译器
为了提高程序的执行效率,c++的编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高,这时Const常量是和#define常量一样的。但是C++编译器对除了直接定义的Const常量外,都是分配内存的。所以,有以下来那个两种情况。
(1)、分配内存的情况(利用extern):
extern const int bufsz; //外部声明
(2)、不分配内存的情况:
const int bufsz = 100; //全局常量
7、C/C++语言提供了六种位运算符来进行位运算操作:(P20)

8、异或运算的特点是:如果a^b=c,那么就有c^b=a以及c^a=b。此规律可以用来进行最简单的快速加密和解密。(P21)
 
9、左移运算符“<<”是双目运算符。其计算结果是将左操作数的各二进位全部左移若干位后得到的值,右操作数指明了要左移的位数。左移时,高位丢弃,左边低位补0。左移运算符不会改变左操作数的值。实际上,左移1位,就等于是乘以2。
右移运算,对于有符号数,如long、int、short、char类型变量,在右移时,符号位(即最高位)将一起移动,并且大多数C/C++编译器规定,如果原符号位为1,则右移时右边高位就补充1,原符号位为0,则右移时高位就补充为0。对于无符号位,右移时高位总是补0。实际上,右移n位,就相当于左操作数除以2的n次方,并且将结果往小里取整。(P21)
 
10、关于优先级:(P24)

11、对于一个for循环:
for(初始条件表达式;循环控制表达式;循环操作表达式) 语句/语句组
如果循环控制表达式被省略,它的值定义为真。一个for循环语句如果没有循环控制表达式,它只有遇到break或return语句时才会结束。(P29)
 
12、在do、for或while语句中,continue语句使得其后的语句被忽略,直接回到循环的顶部,开始下一轮的循环。(P32)
 
13、数组元素的下标,可以是任何整数,可以是负数,也可以大于数组的元素个数。如果出现这种情况,编译的时候是不会出错的。例如:

上面这种情况甚至输出an[-2]的值都是正确的。但这种做法并不安全。它可能改变其他变量的值,甚至改变了程序的指令。(P43)
 
14、一个字符串常量占据的内存字节数等于字符串中字符数目加1.多出来的那个字节位于字符串的尾部,存放的是字符‘\0’。字符'\0'的ASCII码就是二进制数0。(P44)
 
15、用字符数组存放字符串时:
char a[10] = "abc";
cout << sizeof a << endl;
输出结果是10。虽然只初始化了a数组的前4个元素,但是数组的大小依然是10。(P45)
 
16、用scanf输入字符串时,输入的字符串中不能有空格,否则被读入的就是空格前面的那部分。如果想要将用户输入的包含一个甚至多个空格的一整行,都当做一个字符串读入,则应该用gets()函数,gets是一个标准库函数,它的原型是:char *gets(char *s);,功能是将用户键盘输入的一整行,当作一个字符串读入到s中。当然,会自动在s后面添加'\0'。(P45)
 
17、指针也称为“指针变量”,是一种大小为4字节的变量,其内容代表一个内存地址。p是一个指针,则表达式“*p”就代表地址p开始的若干字节。其中的“*”被称作“间接引用运算符”。不管T是什么类型,sizeof(T *)的值都是4。(P47)
 
18、指针变量可以进行一下运算:(P50)
(1)、两个同类型的指针变量,可以比较大小;
(2)、两个同类型的指针变量,可以相减;
(3)、指针变量可以和整数类型变量或常量相加;
(4)、指针变量可以和减去一个整数类型变量或常量;
(5)、指针变量还可以自增、自减。
比较大小的意思是:p1、p2是两个同类型的指针,那么,如果地址p1 < 地址p2,则表达式“p1 < p2”的值就是真,否则假。
指针相减的定义是:
如果有两个T*类型的指针p1和p2,那么表达式“p1 - p2”的类型就是int,其值可正可负,其值的绝对值
表示在地址p1和p2之间能够存放多个T类型的变量
指针和整数相加的定义是:如果p是一个T*类型的指针,而n是一个整型变量或常量,那么表达式“p+n”就是一个类型为T*的指针,该指针指向的地址是:
地址p + n * sizeof(T)。
 
19、指针变量进行自增自减:
当指针变量结合自增、自减和指针运算符时,代码不太容易理解。
自增、自减运算符和指针运算符的优先级相同,结合方向是自右向左。比如:
main()
{
     int a[5] = {10,20,30,40,50}, *p;
     p = a;
     cout << *(p++) << " ," << *p << endl;    //(1)
     cout << *(++p) << " ," << *p << endl;    //(2)
     cout << *p++ << " ," << *p << endl;    //(3)
     cout << ++*p << " ," << *p << endl;    //(4)
     cout << *(p)++ << " ," << *p << endl;    //(5)
}
在(1)中,*(p++)表达式的值就是*p;然后指针p自加1,指向下一个数组元素。
在(2)中,*(++p)表达式首先完成指针p自加1,p指向了数组的下一个数组元素;然后表达式的值是p所指的内存单元的值。
在(3)中,根据右结合的规则,表达式*p++等价于*(p++)。
在(4)中,根据右结合的规则,表达式++*p等价于++(*p),自增运算符作用于*p对应的内存单元。
 
20、可以用任何类型的指针对void指针进行赋值。但是,由于sizeof(void)是没有定义的,所以对于void*类型的指针p,表达式“*p”也是没有定义,而且指针运算对p也不能进行。void指针主要用于内存拷贝。将内存中某一块的内容拷贝到另一块去,那么源块和目的块的地址都可以用void指针表示。(P55)
 
21、程序运行期间,每个函数的函数体都会占用一段连续的内存空间。而函数名就是该函数体所占内存区域的起始地址(也称“入口地址”)。我们可以将函数体的入口地址赋给一个指针变量,使该指针变量指向该函数。然后指针变量就可以调用这个函数。这种指向函数的指针变量称为“函数指针”。例如:

int (*pf)(int, char);
表示pf是一个函数指针,它所指向的函数,返回值类型应是int,该函数应有两个参数,第一个是int型,第二个是char型。可以用一个原型匹配的函数的名字给一个函数指针赋值。(P56)
 
22、在C++中,通过“new”运算符来实现动态内存分配。(P59)
(1)、new运算符的第一种用法如下:
P = new T;
T是任意类型名,P是类型为T * 的指针。这样的语句,会动态分配出一片大小为sizeof(T)字节的内存空间,并且将该内存空间的起始地址赋值给P。
(2)、第二种用法,用来动态分配一个任意大小的数组:
P = new T[N];
T是任意类型名,P是类型为T * 的指针,N代表“元素个数”,他可以是任何为正整数的表达式,表达式可以包含变量、函数调用。
如果要求分配的空间太大,操作系统找不到足够的内存来满足,那么动态内存分配就会失败。保险的做法是在进行较大的动态内存分配时,判断一下分配是否成功。例如:
程序从操作系统动态分配所得的内存空间,使用完后应该释放。
 
23、C++提供“delete”运算符,用以释放动态分配的内存空间。delete的基本用法是:(P60)
delete 指针;
该指针必须是指向动态分配的内存空间,否则运行时很可能出错。
如果是new的第二种用法,即分配了一个数组,则用法如下:
delete [] 指针;
如果动态分配了一个数组,但是却用“delete 指针”的方式释放,则编译时没有问题,运行时也一般不会发现异常,但实际上会导致动态分配的数组没有被完全释放。
 
24、指向结构变量的指针:通过指针,访问其指向的结构变量的成员变量,写法有两种:(P65)
指针->成员变量名
或为:
(* 指针).成员变量名
 
25、用fopen打开文件:(P68)

fopen函数返回一个FILE * 类型的指针,称为文件指针。该指针指向的FILE类型变量中,存放着关于文件的一些信息。
如果试图
以只读的方式打开一个并不存在的文件、或因其他原因(比如没有权限)导致文件打开失败,则
fopen返回NULL指针。如果以
读写或者只写的方式打开一个并不存在的文件,那么
该文件就会被创建出来
对文件进行读写操作前,判断fopen函数的返回值是否是NULL,是非常重要的习惯。
 
26、打开文件,读写完毕后,一定要调用fclose函数关闭文件。fclose函数的原型是:
int fclose(FILE * stream);
stream即是先前用fopen打开文件时得到的文件指针。一个程序能同时打开的文件数目是有限的,如果总是打开文件没有关闭,那么文件打开数目到达一定限度后,就再也不能打开新文件了。(P69)
 
27、用fscanf读文件,fscanf函数原型如下:(P69)
int fscanf(FILE *stream, const char * format[, address, …]);
例如:fscanf(fp, "%s%d%s%d", szName, &nId, szGender, &nBirthYear) != EOF
fscanf函数从与stream相关联的文件中读取数据。该函数适用于读取以文本方式打开的文件。如果文件的内容读完了,那么fscanf函数返回值为EOF。
fprintf函数能用于向文件中写入数据,用法和printf、fscanf类似。其原型是:
int fprintf(FILE *stream, const char *format[, argument, …]);
 
28、用fgetc函数读文件。fgetc函数原型如下:(P70)
int fgetc(FILE *stream);
它用于从文件中读取一个字节,返回值即是所读取的字节数。每个字节都被当作一个无符号的8位(二进制位)数,因此每个被读取字节的取值范围都是0-255。反复调用fgetc函数可以读取整个文件。如果读到文件尾,则fgetc函数返回EOF。
用fputc写文件。fputc函数原型如下:
int fputc(int c, FILE *stream);
它将一个字节写入文件。参数c即是要被写入的字节。虽然c是int类型的,但实际上只有其低8位才被写入文件。写入失败则返回EOF。
 
29、用fgets函数读文件。fgets函数原型如下:(P71)
char *fgets(char *s, int n, FILE *stream);
它一次从文件中读取一行,包括换行符,放入字符串s中,并且加入字符串结尾标识符‘\0’。参数n代表缓冲区s中最多能容纳多少个字符(不算结尾标识符'\0')。
fgets函数的返回值是一个char*类型的指针,和s指向同一个地方。如果再没有数据可以读取,那么函数的返回值就是NULL。
用fputs函数写文件。fputs函数原型如下:
int fputs(const char *s, FILE *stream);
它往文件中写入字符串s。注意,写完s后它并不会再自动向文件中写换行符。
 
30、用fread读文件,用fwrite写文件。fread函数原型如下:(P72)
unsigned fread(void *ptr, unsigned size, unsigned n, FILE  *stream);
该函数从文件中读取n个大小为size字节的数据块,总计n*size字节,存放到地址ptr开始的内存中。返回值是读取的字节数。如果一个字节也没有读取,返回值就是0。
fwrite函数原型如下:
unsigned fwrite(const void *ptr, unsigned size, unsigned n, FILE *stream);
该函数将内存中从地址ptr开始的n*size个字节的内容,写入到文件中去。
这两个函数的返回值,表示成功读取或写入的“项目”数。每个“项目”的大小是size字节。
使用fread和fwrite函数读写文件,文件必须用二进制方式打开。
 
31、保存学生信息时,可以使用文本文件,也可以使用记录文件。但是通常使用记录文件更好。记录文件可以按名字或学号等关键值排序,排序后可以用折半查找算法快速查找,这样在一个有N个记录的文件进行查找,最多只需读取log2(N)次。而用文本文件的格式存放信息,由于每行长度都不一样,所以要查找某一信息时,只能从头按顺序往下找直到找到为止。那么平均要读取整个文件的一半,才能找到。另外,用记录方式保存信息,比用文本方式通常能节省空间。文本方式中有很多空格、换行符是冗余的。(P74)
 
32、用fseek改变文件当前位置:(P75)

注意,文件开头的“当前位置”值是0,而不是1。fseek函数就起到随意改变文件的“当前位置”的作用。函数原型如下:
int fseek(FILE *stream, long offset, int whence);
该函数将于stream关联的文件的“当前位置”设为距whence处offset字节的地方。whence可以有以下三种取值,这三种取值都是在stdio.h中定义的标识符:

例如:

 
33、C语言标准库函数:
(1)、数学函数

其中floor(x)应该是求不大于x的最大整数。
(2)、字符处理函数:

(3)、字符串和内存操作函数:

(4)、字符串转换函数:

 
34、在程序中如何知道用户输入的命令行参数呢?要做到这一点,main函数的写法须和以往的不同,要增加两个参数:(P79)
int main(int argc, char *argv[])
{
     ……
}
参数argc就代表启动程序时,命令行参数的个数。C/C++语言规定,
可执行程序程序本身的文件名,也算一个命令行参数,因此,argc的值至少是1。argv是一个数字,其中的每个元素都是一个char*类型的指针,该指针指向一个字符串,这个字符串里就存放着命令行参数。
 
35、标识符命名注意事项:(P80)
(1)、为全局变量取长的,描述信息多的名字,为局部变量取稍短的名字;
(2)、对于返回值为真或假的函数,加“Is”前缀如:
int isalpha();
 
二、问题
1、

2、二进制反码?

3、

4、了解C++中的qsort的使用方式?
 
5、C++动态分配了一个数组,却用“delete 指针”的方式释放,有什么后果?
 
6、fputc的使用?

转载于:https://www.cnblogs.com/lydf-2012/archive/2012/05/01/2477672.html

你可能感兴趣的文章
常用的正则表达式
查看>>
华为EC169在MAC 10.9.6下的安装方法
查看>>
easy_install和Pip
查看>>
Mysql ==》 文件夹(库)
查看>>
主攻ASP.NET.3.5.MVC3.0架构之重生:用户角色与用户增删改查(十)
查看>>
简单的Ubuntu16.04 tensorflow, keras环境配置
查看>>
Django RedirectView
查看>>
jenkins配置自动发送邮件,抄送
查看>>
线段树区间修改,区间求和,区间求平方和,最大最小值
查看>>
struts2请求过程源码分析
查看>>
黑马day14 过滤器概述&amp;生命周期&amp;运行过程
查看>>
SVN文件排除
查看>>
CF Gym 100637G \#TheDress (水)
查看>>
live555源码研究(四)------UserAuthenticationDatabase类
查看>>
C#net多线程多文件压缩下载
查看>>
maven:pom.xml 搭建spring框架基本配置
查看>>
[Python Study Notes]CS架构远程访问获取信息--SERVER端v2.0
查看>>
基于OpenStack构建企业私有云(4-2)Nova_计算节点
查看>>
linux 查看系统信息命令(比较全)
查看>>
Linux Makefile 教程(转)
查看>>