第一章初识C语言
重点内容
起源:1972,贝尔实验室。继承B语言。
特点:功能强大,应用范围广泛。
设计步骤:1.定义程序目标2.设计程序3.编写代码4.编译5.运行程序6.测试和调试程序7.维护和修改程序
本章小结
C 是强大而简洁的编程语言。它之所以流行,在于自身提供大量的实用编程工具,能很好地控制硬件。而且,与大多数其他程序相比,C程序更容易从一个系统移植到另一个系统。
C是编译型语言。C编译器和链接器是把C语言源代码转换成可执行代码的程序。
用C语言编译可能费力、困难,让你感到沮丧,但是它可以激发你的兴趣,让你兴奋、满意。我们希望你在愉快的学习过程中爱上C。
复习题
对于编程而言,可移植意味着什么?
解释源代码文件、目标代码文件和可执行文件有什么区别?
编程的7个主要步骤是什么?
编译器的任务是什么?
链接器的任务是什么?
编程练习
1.略
第二章 C语言概述
重点内容
first.c:
#include<stdio.h>//#include预处理指令
int main(void) {//main第一个被调用的函数
int num; //定义变量
num = 1;
//给变量赋值
printf("I am a simple");//调用库函数
printf("computer \n");
printf("My favorite number is %d because it is first \n ",num);
return 0;
}
注释:
/* 这是一条c注释 */
// 这是注释、
变量命名规则:
可以用小写字母、大写字母、数字和下划线,第一个字符必须是字母或下划线,不能是数字开头。
fathm_ft.c
#include<stdio.h>
int main(void) {
int feet, fathoms;//等于int feet; int fathoms;
fathoms = 2;
feet = 6 * fathoms;//6乘以fathoms *==乘
printf("There are %d feet in %d fathoms!\n",feet,fathoms);
return 0;
}
two_func.c
#include<stdio.h>
void butler(void);//函数声明
int main(void) {
printf("I will summon the butler function. \n ");
butler();//调用函数
printf("Yes,Bring me some tea and writeable DBDs. \n");
return 0;
}
void butler(void) {//函数定义
printf("You rang,sir?\n");
}
错误写法:
int n,int n2,int nn3;
本章小结
C程序由一个或多个函数组成。每个C程序必须包含一个main()函数,这是C程序要调用的第1个函数。
第三章 数据和C
scanf() 函数读取用户输入。
数据类型关键字:
int long short unsigned char float double
C90: signed void
C99: _Bool _Complex _Imaginary
划分为两大基本类型: 整数类型浮点数类型
位、字节、字:
计算机最小存储单元(bit) 可以存储0或1。
字节(byte)最常用单位,1字节=8位
1 byte = 00000000(8个bit)
那么二进制 00000000到11111111 转换十进制就是 0到255
字(word)自然存储单位, 对于8位微型计算机,一个字相当于8位 , 而对于现在的32,64位计算机, 会增至32,64位
进制转换:
十进制111= (1*10^2 + 1*10^1 +1*10^0) = (100+10+1) =111
二进制111= (1*2^2 +1*2^1 +1*2^0 ) = (4+2+1) =7
初始化变量:
int dogs,cats=94; //有效, 但是容易产生误解, 不要这样写
格式化输出,
%d对应int类型 ,八进制方式显示: %o, 十六进制方式显示:%x
整数类型:
shortint ;long int ; long long int ; unsigned int; signed ;
c标准对基本数据类型只规定了允许的最小大小。
print2.c
#include<stdio.h>
int main(void) {
unsigned int un = 3000000000;
short end = 200;
long big = 65537;
long long verybig = 12345678908642;
printf("un =%u and not %d \n", un, un);
printf("end=%hd and %d \n ",end,end);
printf("big = %ld and not %hd\n",big,big);
printf("verybig =%lld and not %ld \n ",verybig,verybig);
return 0;
}
char 类型:
1字节,8位,也就是可以表示0到255 个数;
标准ASCII码范围:0到127 ,也就是一个char就可以表示的范围。 ASCII 编码的‘A’对应整数就是65 ;char A='A' 与char A=65 等价;
非打印字符
\a 警报\b 退格\f 换页\n 换行\r 回车\t 水平制表符\v 垂直制表符\\反斜杠\‘ 单引号\" 双引号\? 问号
\0oo八进制\xhh 十六进制
浮点型变量:
float
double
打印输出格式:%f 十进制计数法打印。 %e 指数计数法打印。
long double 对应 %Lf %Le
浮点数舍入错误:
#include<stdio.h>
int main(void) {
float a, b;
b = 2.0e20 + 1.0;
a = b - 2.0e20;
printf("%f \n",a);
return 0;
}
没有得到正确的输出:计算机缺少足够的小数位来完成正确的运算。
类型大小:
#include<stdio.h>
int main(void) {
printf("Type int has a size of %zd bytes \n",sizeof(int));
printf("Type char has a size of %zd bytes \n ", sizeof(char));
printf("Type long has a size of %zd bytes \n ", sizeof(long));
printf("Type long long has a size of %zd bytes \n ", sizeof(long long));
printf("Type double has a size of %zd bytes \n ", sizeof(double));
printf("Type long double has a size of %zd bytes \n ",sizeof(long double));
return 0;
}
第四章 字符串和格式化输入/输出
talkback.c:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define DENSITY 62.4
int main() {
float weight, volume;
int size, letters;
char name[40];
printf("Hi! What`s your first name? \n");
scanf("%s", name);//%s:字符串
printf("%s ,what`s your weight in pounds?\n ",name);
scanf("%f", &weight);//接收键盘输入
size = sizeof(name);//占用内存大小
letters = strlen(name);//strlen 计算字符串长度 , 忽略 结束字符'\0'
volume = weight / DENSITY;
printf("Well , %s, your volume is %2.2f cubic feet.\n ",name,volume);
printf("and we have %d bytes to store it.\n ", size);
printf("strlen size is %d.\n ", letters);
return 0;
}
C中的字符串一定以空字符结束,'\0' 代表空字符 , 是非打印字符,ASCII码为 0 ,不是数字0;
const 只读。
limits.h
常量
常量 |
含义 |
CHAR_BIT |
char类型的位数 |
CHAR_MAX |
char类型的最大值 |
CHAR_MIN |
char类型的最小值 |
SCHAR_MAX |
signed char 类型的最大值 |
SCHAR_MIN |
signed char 类型最小值 |
UCHAR_MAX |
unsigned char 类型的最大值 |
SHRT_MAX |
short类型的最大值 |
SHRT_MIN |
short类型的最小值 |
USHRT_MAX |
unsigned short 类型的最大值 |
INT_MAX |
int类型的最大值 |
INT_MIN |
int类型的最小值 |
UINT_MAX |
unsigned int 的最大值 |
LONG_MAX |
long类型的最大值 |
LONG_MIN |
long类型的最小值 |
ULONG_MAX |
unsigned long 类型的最大值 |
LLONG_MAX |
long long类型的最大值 |
LLONG_MIN |
long long类型的最小值 |
ULLONG_MAX |
unsigned long long 类型的最大值 |
float.h:
常量 |
含义 |
FLT_MANT_DIG |
float类型的尾数位数 |
FLT_DIG |
float类型的最少有效数字位数 |
FLT_MIN_10_EXP |
带全部有效数字的float类型的最小负指数(以10为底) |
FLT_MAX_10_EXP |
float类型的最大正指数(以10为底) |
FLT_MIN |
保留全部精度的float类型最小正数 |
FLT_MAX |
float类型的最大正数 |
FLT_EPSILON |
1.00和比1.00大的最小float 类型值之间的差值 |
width.c
#include<stdio.h>
#define PAGES 959
int main(void){
printf("*%d*\n",PAGES);
printf("*%2d*\n",PAGES);//占2个宽度
printf("*%10d*\n",PAGES);//占10个右对齐
printf("*%-10d*\n",PAGES);//占10个左对齐
return 0;
}
float类型值作为参数时,会被转换成double
第五章 运算符、表达式和语句
指数增长:
wheat.c
#include<stdio.h>
#define SQUARES 64
int main(void) {
const double CROP = 2E16;
double current, total;
int count = 1;
printf("squaregrainstotal");
printf("fraction of \n ");
printf("addedgrains");
printf("world total \n ");
total = current = 1.0;
printf("%4d %13.2e %12.2e %12.2e\n",count,current,total,total/CROP);
while (count<SQUARES)
{
count = count + 1;
current = 2.0 * current;
total = total + current;
printf("%4d %13.2e %12.2e %12.2e\n",count,current,total,total/CROP);
}
printf("That`s all\n");
return 0;
}
除法运算符:/
浮点数除法的结果是浮点数,整数除法的结果是整数。整数没有小数部分,整数除法中结果小数直接被丢弃(截断)。
混合整数和浮点数除法,结果是浮点数(会把俩个数都当作浮点数来计算)。
运算符优先级:
从高到低
运算符 |
结合律 |
() |
从左往右 |
+-(一元) |
从右往左 |
* / |
从左往右 |
+ - (二元) |
从左往右 |
= |
从右往左 ---》 a=b=c=3 先给c赋值 |
当运算符共享一个运算对象时,(1+2*3)+和*共享2,优先级决定求值顺序 。1*2+3*4,*号并没有共享一个运算对象,先算第一个1*2还是第二个3*4, 这个跟编译器有关, 不属于结合律。1*2/3 ,*和/ 运算符优先级相同,共享运算符对象3,因此根据结合律, 从左往右。
sizeof运算符:
size_t intsize=sizeof(int);
求模运算符:%
13%5=3;
min_sec.c:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define SEC_PER_MIN60
int main(void) {
int sec, min, left;
printf("Convert seconds to minutes and seconds ! \n ");
printf("Enter the number of seconds (<0 to quit):\n ");
scanf("%d",&sec);
while (sec>0)
{
min = sec / SEC_PER_MIN;
left = sec % SEC_PER_MIN;
printf("%d seconds is %d minutes,%d seconds . \n ",sec,min,left);
printf("Enter next value (<=0 to quit):\n ");
scanf("%d", &sec);
}
printf("Done!\n");
return 0;
}
递增、递减运算符:++--
int i=0;
++i;//前缀模式 先增加1 后使用i
i++;//后缀模式 先使用i 在自增加1
只有“()”比递增递减运算符优先级高,因此,x*y++ ,相当与(x )*(y++) ,而y是先使用, 后递增
表达式与值:
表达式 -4+6 得到值 2;c=3+8 得到值 11 ;5>3 得到值 1 ; 6+(c=3+8) 得到值17
副作用:
可以理解为,代码最后都会编译转换为2进制, 每一行二进制代码,cpu当作一个运算或者表达式去计算值。
states=50; 求得值为 50 , 副作用将states值改为50 ;
序列点:
每行代码执行完(“;”结束),就是一个序列点,cpu执行二进制代码时,每次读取都会按一行代码的量去读取并执行, 该行执行完后,在读取下一行(序列点)时, 所有副作用也都生效完成。
类型转换:
convert.c
#include<stdio.h>
int main(void) {
char ch;
int i;
float fl;
fl = i = ch = 'C';
printf("ch=%c , i=%d , fl=%2.2f\n",ch,i,fl);//ch=C i=67(字符C的ascii码值) fl=67.00 (int转float)
ch = ch + 1;// 67+1 对应ascii码68, 对应char(1字节)‘D’
i = fl + 2 * ch;//i=67.00+2*68 67.00+136 203.00f 转int =203
fl = 2.0 * ch + i;//fl=2.0*68+203 136.00+203 = 339.00
printf("ch=%c ,i=%d,fl=%2.2f\n",ch,i,fl);//ch=D i=203 fl=339.00
ch = 1107;//ch的大小是1字节八位,范围是0到255 1107超出范围 1107的二进制(10001010011) ch只能容纳8位,
//-----截断后就是01010011(十进制83),对应字符‘S’,也可以1107%256=83, 255 二进制(11111111) 在加1 , 就溢出变为0 。
printf("Now ch=%c \n",ch);
ch = 80.89;//截断后=80, 对应‘P’
printf("Now ch=%c \n",ch);
return 0;
}
强制类型转换:
int a=(int)5.44+(int)4.3;
第六章 C控制语句:循环
cmpflt.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
int main(void) {
const double ANSWER = 3.14159;
double response;
printf("What is the value of pi ?\n");
scanf("%lf",&response);
while (fabs(response-ANSWER)>0.0001)//fabs返回绝对值 。
{
printf("Try again!\n");
scanf("%lf",&response);
}
printf("Close enough!\n");
return 0;
}
truth.c:
#include<stdio.h>
int main(void) {
int n = 3;
while (n)//所有非0值 视为真
{
printf("%2d is true \n",n--);//执行3次
}
printf("%2d is false \n ",n);
n = -3;
while (n)
{
printf("%2d is true\n ",n++);//执行3次
}
printf("%2d is false \n ",n);
return 0;
}
运算符优先级:
运算符(优先级由高到低) |
结合律 |
() |
从左往右 |
- + ++ -- sizeof |
从右往左 |
* / % |
从左往右 |
+ - |
从左往右 |
< > <= >= |
从左往右 |
== != |
从左往右 |
= |
从右往左 |
其他赋值运算符:
+= 、-=、*=、/=、%=
逗号运算符:
for(int i=1,b=2;i<10;i++,b++){
}
第七章 C控制语句:分支和跳转
cypher1.c
#include<stdio.h>
#define SPACE ' '
int main(void) {
char ch;
while ((ch=getchar())!='\n')
{
if (ch == SPACE)
putchar(ch);
else
putchar(ch + 1);
}
putchar(ch);
return 0;
}
ctype.h
函数名 |
如果是下列参数, 返回真 |
isalnum() |
字母或数字 |
isalpha() |
字母 |
isblank() |
空格、水平制表符或换行符或其他任何空白字符 |
iscntrl() |
控制字符,Ctrl+B |
isdigit() |
数字 |
isgraph() |
除空格之外的任意可打印字符 |
islower() |
小写字母 |
isprint() |
可打印字符 |
ispunct() |
标点符号(除空格或字母数字字符以外的任何可打印字符) |
isspace() |
空白字符(空格、换行符、换页符、回车符、垂直制表符、水平制表符) |
isupper() |
大写字母 |
isxdigit() |
十六进制字符 |
tolower() |
如果是大写字母,返回小写,否则返回原参数 |
toupper() |
如果是小写,返回大写, 否则返回原参数 |
wordcnt.c:
#include<stdio.h>
#include<ctype.h>
#include<stdbool.h>
#define STOP '|'
int main(void) {
char c;
char prev;
long n_chars = 0L;
int n_lines = 0;
int n_words = 0;
int p_lines = 0;
bool inword = false;
printf("Enter text to be analyzed (| to terminate ):\n");
prev = '\n';
while ((c=getchar())!=STOP)
{
n_chars++;
if (c == '\n') {
n_lines++;//遇到换行+1
}
if (!isspace(c) && !inword) {//如果c不是空格, 并且inword等于false
inword = true;
n_words++;//第一次执行从0 变为1, 下一次遇到空格才会+1
}
if (isspace(c) && inword) {
inword = false;
}
prev = c;//如果在行的开头就输入了’|‘ 那么上一个字符一定是’\n‘ ,如果不是’\n‘,说明’|‘没有在一行中的开头位置
}
if (prev != '\n')p_lines = 1;
printf("Characters =%ld, words=%d ,lines=%d ,",n_chars,n_words,n_lines);
printf("partial lines=%d \n",p_lines);
return 0;
}
条件运算符:
?:
循环辅助:
continue 和 break
animals.c
#include<stdio.h>
#include<ctype.h>
int main(void) {
char ch;
printf("Give me a letter of the alphabet,and I will give");
printf("an animal name \n beginning with that letter\n");
printf("Please type in a letter ; type # to end my act.\n");
while ((ch=getchar())!='#')
{
if ('\n' == ch) continue;
if (islower(ch)) {
switch (ch)
{
case 'a':
printf("argali, a wild sheep of Asia\n");
break;
case 'b':
printf("babirusa,a wild pig of Malay \n");
break;
case 'd':
printf("desman,aquatic,molelike critter \n");
break;
case 'e':
printf("echidna,the spiny anteater\n ");
break;
case 'f':
printf("fisher,brownish \n");
break;
default:
printf("That`s a stumper!\n");
}
}else {
printf("I recognize only lowercase letters.\n");
while (getchar()!='\n')
{
continue;
}
printf("Please type another letter or a #.\n");
}
}
printf("Bye\n");
}
swich case 多重标签:
case 'a':
case 'A':
.....break;
第8章 字符输入/输出和输入验证
缓冲区:
完全缓冲I/O:当缓冲区被填满时,才刷新缓冲区。
行缓冲I/O:出现换行符,刷新缓冲区。
scanf()会把换行符留在缓冲区,而getchar()不会跳过换行符。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void display(char cr, int lines, int width);
int main(void) {
int ch;
int rows, cols;
printf("Enter a character and two integers:\n");
while ((ch=getchar())!='\n')
{
if (scanf("%d %d", &rows, &cols) != 2) {
break;
}
while (getchar()!='\n')//会排除后边一些无效输入,还会将scanf留在缓冲区的换行读取了
{
continue;
}
display(ch, rows, cols);
printf("Enter a character and two integers:\n");
printf("Enter a newline to quit:\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr, int lines, int width) {
int row, col;
for ( row = 1; row <= lines; row++)
{
for ( col = 1; col <= width; col++)
{
putchar(cr);
}
putchar('\n');
}
}
第九章 函数
recur.c:
#include<stdio.h>
void up_and_down(int);
int main(void) {
up_and_down(1);
return 0;
}
void up_and_down(int n) {
printf("Level %d : n location %p \n",n,&n);
if (n < 4)
up_and_down(n + 1);
printf("LEVEL %d:n location %p\n", n, &n);
}
递归图示:
factor.c:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
long rfact(int n);
int main(void) {
int num;
printf("This program calclates factorials \n ");
printf("Enter a value in the range 0-12 (q to quit):\n");
while (scanf("%d",&num)==1)
{
if (num < 0) {
printf("No negative numbers,please \n");
}
else if (num > 12) {
printf("Keep input under 13.\n");
}
else {
printf("recursion:%d factorial=%ld\n",num,rfact(num));
}
printf("Enter a value in the range 0-12(q to quit):\n");
}
printf("Bye. \n");
return 0;
}
long rfact(int n) {
long ans;
if (n > 0)
ans = n * rfact(n - 1);
else
ans = 1;
return ans;
}
假如n=4
递归缺点会消耗计算机内存资源,会有大量push、 pop;
第10章 数组和指针(重要)
数组初始化:
int ary1[]={1,2,3};
int ary2[4]={1};
int ary3[3]={1,2,3};
int ary4[3]={1,[2]=2};
int n=3;
int ary5[n]={0};
数组名=数组首元素地址
指针:
int * intptr; 指向int 类型的指针。intptr+1,指向的地址增加一个(int)大小;
order.c:
#include<stdio.h>
int data[2] = { 100,200 };
int moredata[2] = { 300,400 };
int main(void) {
int* p1, * p2, * p3;
p1 = p2 = data;
p3 = moredata;
printf(" *p1=%d ,*p2=%d *p3=%d \n",*p1,*p2,*p3);
printf("*p1++=%d,*++p2=%d,(*p3)++=%d\n",*p1++,*++p2,(*p3)++);
printf("*p1=%d,*p2=%d,*p3=%d \n",*p1,*p2,*p3);
return 0;
}
指针表示法和数组表示法:
ar[i]和*(ar+i)是等价的,无论ar是指针还是数组。但是只有指针变量时才可以使用++ ,-- 运算符。
ptr_ops.c:
#include<stdio.h>
int main(void) {
int urn[5] = { 100,200,300,400,500 };
int* ptr1, * ptr2, * ptr3;
ptr1 = urn;
ptr2 = &urn[2];//指向元素300
printf("pointer value,dereferenced pointer,pointer addredd:\n");
printf("ptr1=%p,*ptr1=%d,&ptr1=%p\n", ptr1, *ptr1, &ptr1);//元素100的地址,100,ptr1指针的地址
ptr3 = ptr1 + 4;//ptr3指向元素500
printf("\n adding an int to a pointer: \n");
printf("ptr1+4=%p,*(ptr1+4)=%d\n",ptr1+4,*(ptr1+4));//元素500的地址, 500
ptr1++;//指向元素200
printf("\nvalues after ptr1++:\n");
printf("ptr1=%p,*ptr1=%d,&ptr1=%p\n",ptr1,*ptr1,&ptr1);//元素200的地址,200,ptr1指针的地址
ptr2--;//指向元素200
printf("\n values after --ptr2:\n");
printf("ptr2=%p,*ptr2=%d,&ptr2=%p\n",ptr2,*ptr2,&ptr2);//元素200的地址, 200,ptr2指针地址
--ptr1;//指向100
++ptr2;//指向300
printf("\nPointers reset to original values:\n");
printf("ptr1=%p,ptr2=%p\n",ptr1,ptr2);//100元素的地址 300元素的地址
printf("\n subtracting one pointer from another:\n");
printf("ptr2=%p,ptr1=%p,ptr2-ptr1=%td\n,",ptr2,ptr1,ptr2-ptr1);//指针相减得到它俩之间的元素个数 2
printf("\n subtracting an int from a pointer : \n ");
printf("ptr3=%p,ptr3-2=%p\n",ptr3,ptr3-2);//元素500的地址, 元素300的地址
return 0;
}
指针和多维数组:
int zippo[4][2];
zippo=&zippo[0] 数字组首元素地址, 首元素l类型是 int[];
&zippo[0]=&zippo[0][0] , zippo[0]相当于int类型的指针 ,所以zippo[0]+1,指向下一个int元素 , 而zippo 相当于指向俩个int元素的数组的指针,zippo+1指向的是第三个int(zippo[1][0])元素.
zippo1.c:
#include<stdio.h>
int main(void) {
int zippo[4][2] = {
{2,4},
{6,8},
{1,3},
{5,7}
};
printf("zippo=%p,zippo+1=%p\n",zippo,zippo+1);//数组首元素(int[])地址,+1跳过第一个元素{2,4},指向{6,8};
printf("zippo[0]=%p, zippo+1=%p \n",zippo[0],zippo[0]+1);//数组首元素(int)地址,+1 跳过元素2,指向元素4;
printf("*zippo=%p,*zippo+1=%p\n",*zippo,*zippo+1);//同上
printf("zippo[0][0]=%d\n",zippo[0][0]);//2
printf("*zippo[0]=%d\n", *zippo[0]);//2
printf("**zippo=%d\n",**zippo);//2
printf("zippo[2][1]=%d\n",zippo[2][1]);//3
printf("*(*(zippo+2)+1)=%d\n", *(*(zippo + 2) + 1));//3
return 0;
}
指向数组的指针:int ary[]={1,2,3};int * arptr=ary;
指向多维数组的指针: int ary[][2]={{1,2},{3,4}}; int (*arptr)[]=ary;
复合字面量:
int *pt1=(int [2]){10,20};
第11章 字符串和字符串函数
字符串以空字符(\0)结尾。
puts()函数:输出字符串,并在末尾加上换行。
字符串字面量(字符串常量)自动在末尾增加‘\0’,表示结束。 属于静态存储,相当于(char*) 指针。
strptr.c:
#include<stdio.h>
int main(void){
printf("%s ,%p, %c\n","We","are",*"space farers");
return 0;
}
addresses.c:
#define MSG "I`m special"
#include<stdio.h>
int main() {
char ar[] = MSG;
const char* pt = MSG;
printf("address of \"I`m special\":%p \n","I`m special");//地址与MSG一致,字符串常量在内存中只保存一份
printf("address ar:%p\n", ar);//复制了一份给了char数组。 所以地址不一样
printf("address pt:%p\n", pt);//指针地址也与MSG一致
printf("address pt:%p\n",MSG);//同上
printf("address of \"I`m special\":%p \n", "I`m special");//同上
}
scanf()的“%s” 只能读取一个单词, 有时候需要读取一整行,这时候可以用gets()函数。gets()读取整行输入,直到遇到换行符,然后丢弃换行符,存储其余的字符,并在末尾增加一个空字符。
经常和puts()组合使用。puts()用于显示字符,并在末尾增加换行符。
gets()函数存在的问题: 不会检查接受字符数组的长度是否足够, 输入的字符过长会导致缓冲区溢出,从而会引起程序异常。
gets()的替代品:
fgets(),C11新增gets_s() 也可以替代。
fgets()和fputs()经常在一起使用。fgets()接受3个参数, 第2个表明读入的最大数量,第3个参数知名要写入的文件,如果是显示器, 使用stdout。读入错误返回null,成功返回第一个参数的地址。fgets()会保存换行。
fputs()不会在字符串末尾增加换行符。
fgets1.c:
#include<stdio.h>
#define STLEN 10
int main() {
char words[STLEN];
int i;
puts("Enter strings(empty line to quit):");
while (fgets(words,STLEN,stdin)!=NULL&&words[0]!='\n')
{
i = 0;
while (words[i]!='\n'&&words[i]!='\0')//读取的字符最后如果是换行,那说明读取了一整行,如果是‘\0’,那就是没有读完。
{
i++;
}
if (words[i] == '\n')//如果整行读完,把换行替换结束符。
words[i] = '\0';
else
while (getchar()!='\n')//如果没读取完, 那就继续读取, 直到遇到换行。
{
continue;
}
puts(words);
}
puts("done");
return 0;
}
gets_s()与fgets()的区别:
gets_s()只从标准输入中读取数据,不需要第3个参数.
如果gets_s()读到换行符,会丢弃它而不是存储它。
如果gets_s()读到最大字符没有读到换行符,会执行一下几步。首页把目标数组中的首字符设置空字符,读取并丢弃随后的输入,直至读到换行符或文件结尾,然后返回空指针。接着调用依赖实现的“处理函数”,可能会中止或退出程序。
scanf() 函数返回一个整数值,该值等于scanf()成功读取的项数或EOF.
fputs()和puts()区别:
fputs()函数的第2个参数指明要写入数据的文件。 如果要打印在显示器上,可以stdout作为参数。
fputs()不会在输出的末尾增加换行符。
字符串函数:
strlen()计算字符串长度, 不包含‘\0’;
strcat()拼接字符串,接受2个字符串作为参数,把第2个字符串的备份附加在第1个字符串末尾,并把拼接后的新字符串作为第1个字符串,第2个字符串不变。
strcat()无法检查第1个数组是否能容纳第2个字符串。如果第一个参数空间不够大,多出来的字符就会溢出,造成程序异常。
strncat()接受3个参数, 第3个参数指定了最大添加字符数。
strcmp()函数比较的是字符串,不是整个数组。如果第一个字符串位于第2个字符串的前面,strcmp返回负数;反之返回正数;相同返回0;
strncmp()第3个参数指定字符数。
strcpy(),strncpy() 拷贝字符串,strcpy和strcat都有同样的问题,它们都不能检查目标空间是否能容纳源字符串的副本。strncpy()更安全。
sprintf() 将数据写入字符串。
还有很多....
第12章 存储类别、链接和内存管理
作用域:
块作用域、函数作用域、函数原型作用域或文件作用域。
链接:
外部链接、内部链接或无链接。
存储期:
静态存储期、线程存储期、自动存储期、动态分配存储期。
分配内存:
malloc()和free()
calloc()
const类型限定符:
const float * pf;//pf是一个const指针。
float const pfc;//与const float *pfc;相同
第13章 文件输入/输出
标准文件:
c程序会自动打开3个文件,它们被称为标准输入、标准输出和标准错误输出。
fopen()函数:
模式字符串 |
含义 |
r |
以读模式打开文件 |
w |
以写模式打开文件,把现有文件长度截为0,如果文件不存在,则创建一个新文件 |
a |
以写模式打开文件,在现有文件末尾添加内容,如果文件不存在,则创建一个新文件 |
r+ |
以更新模式打开文件(读、写) |
w+ |
以更新模式打开文件(读、写),如果文件存在,则将其长度截为 0;如果文件不存在,则创建一个新文件 |
a+ |
以更新模式打开文件(读、写),在现有文件的末尾添加内容,如果文件不存在则创建一个新文件;可以读整个文件,但是只能从末尾添加内容。 |
rb wb ab rb+ r+b wb+ w+b ab+ a+b |
与上一个模式类似,但是以二进制模式而不是文件模式打开文件 |
wx wbx w+x wb+x w+bx |
独占模式 |
以 ”w"模式打开,该文件内容都会被删除。
getc()和putc():
getc()和putc()与getchar()、putchar()类似,不同的是,getc和putc需要文件指针参数。
fclose()关闭文件。
文件I/O:
fprintf() 、fscanf()、fgets()、 fputs().
随机访问:
fseek()打开文件指针直接移动到任意字节处、ftell()返回long类型值,表示文件当前位置;
SEEK_SET 文件开始处;SEEK_CUR:当前位置;SEEK_END 文件末尾;
fseek(fp,0L,SEEK_SET) //定位至文件开始处
fseek(fp,10L,SEEK_SET)//定位至文件中第10个字节
fseek(fp,2L,SEEK_CUR);//从文件当前位置前移2个字节
fseek(fp,0L,SEEK_END);定位至文件结尾
fseek(fp,-10L,SEEK_END);//从文件结尾处回退10个字节
fgetpos()和fsetpos()函数:
fseek()和tell()的问题是,把文件大小限制在Long类型能表示的范围。而fgetpos()和fsetpos()使用fpos_t类型,它不是基本类型,是文件定位类型。
成功返回0 , 失败返回非0.
ungetc(int c ,FILE *fp)函数:
把c指定的字符放回输入流中。
fflush()函数,刷新缓冲区
setvbuf()函数,创建缓冲区
fread()、fwrite()
第 14 章 结构和其他数据形式
book.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
char* s_gets(char* st, int n);
#define MAXTITL 41
#define MAXAUTL 31
struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int main(void) {
struct book library;
printf("Please enter the book title \n");
s_gets(library.title,MAXTITL);
printf("Now enter the author.\n");
s_gets(library.author,MAXAUTL);
printf("Now enter the value \n");
scanf("%f",&library.value);
printf("%s by %s:$%.2f\n", library.title, library.author, library.value);
printf("%s:\"%s\"($%.2f)\n",library.author,library.title,library.value);
printf("Done.\n");
return 0;
}
char* s_gets(char* st, int n) {
char* ret_val;
char* find;
ret_val = fgets(st,n,stdin);
if (ret_val) {
find = strchr(st, '\n');
if (find)
*find = '\0';
else
while (getchar()!='\n')
{
continue;
}
}
return ret_val;
}
联合:
union,能在同一个内存中存储不同的数据类型(不是同时存储)。
枚举:
enum,实际上,enum常量是int类型。
typedef:
为某一类型自定义名称。
函数指针:
void ToUpper(char *);
void (*pf)(char *);
pf=ToUpper;
第 15 章 位操作
取反: ~
按位与:&
按位或:|
按位异或:^
左移:<<
右移:>>
第 16 章 c预处理器和c库
预处理指令:
#define、#include、#ifdef、#else、#endif、#ifndef 、#if、#elif、#line、#error、#pargma
#define 中使用参数:
#define SQUARE(X) X*X
int x=5;
int z;
z=SQUARE(x);//替换为 z=5*5;
SQUARE(x+2);//替换为 x+2*x+2
预定义宏:
宏 |
含义 |
__DATE__ |
预处理的日期 |
__FILE__ |
表示当前源代码文件名的字符串字面量 |
__LINE__ |
表示当前源代码文件中行号的整型常量 |
__STDC__ |
设置为1时,表示实现遵循C标准 |
__STDC_HOSTED__ |
本机环境设置为1;否则设置为0 |
__STDC_VERSION__ |
支持C99标准,设置为199901L;支持C11标准,设置为201112: |
__TIME__ |
翻译代码的时间,格式为:“hh:mm:ss” |
string.h中的memcpy()和memove():
void* memcpy(void restrict s1,const void * restict s2,size_t n);
void* memmove(void *s1,const void *s2,size_t n);
都是从s2指向的位置拷贝n字节到s1 指向的位置,而且返回s1的值。不同的是:memcpy()的参数带关键在restrict,即假设着来个内存区域之间没有重叠,memmove()没有这样的假设。
可变参数:stdarg.h
void f1(int n,...);
va_list ap;声明一个存储参数的对象
va_arg(ap,double);//检索第一个参数
va_end(ap);//清理工作
第 17 章 高级数据表示
链表
struct film{
char title[100];
int rating;
struct film * next;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#define TSIZE 45
struct film
{
char title[TSIZE];
int rating;
struct film* next;
};
char* s_gets(char* st, int n);
int main(void) {
struct film* head = NULL;
struct film* prev, * current;
char input[TSIZE];
puts("Enter first movie title:");
prev = NULL;
while (s_gets(input,TSIZE)!=NULL&&input[0]!='\0')
{
current = (struct film*)malloc(sizeof(struct film));
if (head == NULL) {
head = current;
}
else {
prev->next = current;
}
current->next = NULL;
strcpy(current->title,input);
puts("Enter your rating <0-10> :");
scanf("%d", ¤t->rating);
while (getchar()!='\n')
{
continue;
}
puts("Enter next movie title(empty line to stop):");
prev = current;
}
if (head == NULL) {
printf("no data entered.");
}
else {
printf("Here is the movie list :\n");
}
current = head;
while (current!=NULL)
{
printf("Movie :%s Rating:%d\n", current->title, current->rating);
current = current->next;
}
current = head;
while (current!=NULL)
{
head = current->next;
free(current);
current = head;
}
printf("Bye!\n");
return 0;
}
char* s_gets(char* st, int n) {
char* ret_val;
char* find;
ret_val = fgets(st, n, stdin);
if (ret_val) {
find = strchr(st, '\n');
if (find)*find = '\0';
else
while (getchar()!='\n')
{
continue;
}
}
return ret_val;
}
list.h
#ifndef LIST_H_
#define LIST_H_
#include<stdbool.h>
#define TSIZE 45
struct film {
char title[TSIZE];
int rating;
};
typedef struct film Item;
typedef struct node {
Item item;
struct node* next;
}Node;
typedef Node* List;
//初始化链表
void InitializeList(List* plist);
//确定链表是否为空
bool ListIsEmpty(const List* plist);
//确定链表是否已满
bool ListIsFull(const List* plist);
//确定链表中的项数,plist指向一个已初始化的链表
unsigned int ListItemCount(const List* plist);
//在链表的末尾添加项
bool AddItem(Item item, List* plist);
//把函数作用于链表中的每一项
void Traverce(const List* plist, void(*pfun)(Item item));
//释放已分配的内存(如果有的话)
void EmptyThenList(List* plist);
#endif // !LIST_H_
list.c
#include<stdio.h>
#include<stdlib.h>
#include"list.h"
static void CopyToNode(Item item, Node* pnode);
//初始化链表
void InitializeList(List* plist) {
*plist = NULL;
}
//确定链表是否为空
bool ListIsEmpty(const List* plist) {
if (*plist == NULL) {
return true;
}
return false;
}
//确定链表是否已满
bool ListIsFull(const List* plist) {
Node* pt;
bool full;
pt = (Node*)malloc(sizeof(Node));
if (pt == NULL) {
full = true;
}
else {
full = false;
}
free(pt);
return full;
}
//确定链表中的项数,plist指向一个已初始化的链表
unsigned int ListItemCount(const List* plist) {
unsigned int count = 0;
Node* pnode = *plist;
while (pnode!=NULL)
{
++count;
pnode = pnode->next;
}
return count;
}
//在链表的末尾添加项
bool AddItem(Item item, List* plist) {
Node* pnew;
Node* scan = *plist;
pnew = (Node*)malloc(sizeof(Node));
if (pnew == NULL)return false;
CopyToNode(item, pnew);//将item的值赋给Node结构的pnew
pnew->next = NULL;
if (scan == NULL) {//如果是第一次添加,将pnew当作头节点
*plist = pnew;
}
else {//不是第一次添加,将pnew添加到最后
while (scan->next!=NULL)
{
scan = scan->next;
}
scan->next = pnew;
}
return true;
}
//把函数作用于链表中的每一项
void Traverce(const List* plist, void(*pfun)(Item item)) {
Node* pnode = *plist;
while (pnode!=NULL)
{
(*pfun)(pnode->item);
pnode = pnode->next;
}
}
//释放已分配的内存(如果有的话)
void EmptyThenList(List* plist) {
Node* psave;
while (*plist!=NULL)
{
psave = (*plist)->next;
free(*plist);
*plist = psave;
}
}
static void CopyToNode(Item item, Node* pnode) {
pnode->item = item;
}
films3.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"list.h"
void showmives(Item item);
char* s_gets(char * st,int n);
int main(void) {
List movies;
Item temp;
InitializeList(&movies);
if (ListIsFull(&movies)) {
fprintf(stderr, "No memory available!Bye!\n");
exit(1);
}
puts("Enter first movie title:");
while (s_gets(temp.title,TSIZE)!=NULL&& temp.title[0]!='\0')
{
puts("Enter your rating<0-10>:");
scanf("%d",&temp.rating);
while (getchar()!='\n')
{
continue;
}
if (AddItem(temp, &movies) == false) {
fprintf(stderr, "Problem allocating memory\n");
break;
}
if (ListIsFull(&movies)) {
puts("The list is now full.");
break;
}
puts("Enter next movie title(empty line to stop):");
}
if (ListIsEmpty(&movies)) {
printf("No data entered.");
}
else {
printf("Here is the movie list :\n");
Traverce(&movies, showmives);
}
printf("You entered %d movies.\n", ListItemCount(&movies));
EmptyThenList(&movies);
printf("Bye!\n");
return 0;
}
void showmives(Item item) {
printf("Movie:%s Rating: %d \n", item.title, item.rating);
}
char* s_gets(char* st, int n) {
char* ret_val;
char* find;
ret_val = fgets(st, n, stdin);
if (ret_val) {
find = strchr(st, '\n');
if (find)
*find = '\0';
else
{
while (getchar()!='\n')
{
continue;
}
}
}
return ret_val;
}
队列:
新项只能添加到链表的末尾。只能从开头移除项,先进先出。
queue.h:
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include<stdbool.h>
typedef int Item;
#define MAXQUEUE 10
typedef struct node {
Item item;
struct node* next;
}Node;
typedef struct queue {
Node* front;
Node* rear;
int items;
}Queue;
//初始化队列
void InitializeQueue(Queue* pq);
//检查队列是否已满
bool QueueIsFull(const Queue* pq);
//检查队列是否为空
bool QueueIsEmpty(const Queue* pq);
//确定队列中的项数
int QueueItemCount(const Queue* pq);
//在队列末尾添加项
bool Enqueue(Item item, Queue* pq);
//从队列的开头删除项
bool DeQueue(Item* pitem, Queue* pq);
//清空队列
void EmptyTheQueue(Queue* pq);
#endif // !_QUEUE_H_
queue.c:
#include<stdio.h>
#include<stdlib.h>
#include"queue.h"
static void CopyToNode(Item item, Node* pn);
static void CopyToItem(Node* pn, Item* pi);
//初始化队列
void InitializeQueue(Queue* pq) {
pq->front = pq->rear = NULL;
pq->items = 0;
}
//检查队列是否已满
bool QueueIsFull(const Queue* pq) {
return pq->items == MAXQUEUE;
}
//检查队列是否为空
bool QueueIsEmpty(const Queue* pq) {
return pq->items == 0;
}
//确定队列中的项数
int QueueItemCount(const Queue* pq) {
return pq->items;
}
//在队列末尾添加项
bool Enqueue(Item item, Queue* pq) {
Node* pnew;
if (QueueIsFull(pq)) {
return false;
}
pnew = (Node*)malloc(sizeof(Node));
if (pnew == NULL) {
fprintf(stderr, "Unable to allocate memory!\n");
exit(1);
}
CopyToNode(item, pnew);
pnew->next = NULL;
if (QueueIsEmpty(pq)) {
pq->front = pnew;
}
else {
pq->rear->next = pnew;
}
pq->rear = pnew;
pq->items++;
return true;
}
//从队列的开头删除项
bool DeQueue(Item* pitem, Queue* pq) {
Node* pt;
if (QueueIsEmpty(pq)) {
return false;
}
CopyToItem(pq->front, pitem);
pt = pq->front;
pq->front = pq->front->next;
free(pt);
pq->items--;
if (pq->items == 0) {
pq->rear = NULL;
}
return true;
}
//清空队列
void EmptyTheQueue(Queue* pq) {
Item dummy;
while (!QueueIsEmpty(pq))
{
DeQueue(&dummy, pq);
}
}
static void CopyToNode(Item item, Node* pn) {
pn->item = item;
}
static void CopyToItem(Node* pn, Item* pi) {
*pi = pn->item;
}
use_q.c:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include"queue.h"
int main(void) {
Queue line;
Item temp;
char ch;
InitializeQueue(&line);
puts("Testing the Queue interface.Type a to add a value,");
puts("type d to delete a value , and type q to quit.");
while ((ch=getchar())!='q')
{
if (ch != 'a' && ch != 'd') {
continue;
}
if (ch == 'a') {
printf("Integer to add:");
scanf("%d", &temp);
if (!QueueIsFull(&line)) {
printf("Putting %d into queue \n", temp);
Enqueue(temp, &line);
}
else
puts("Queue is full!");
}
else {
if (QueueIsEmpty(&line)) {
puts("Nothing to delete!");
}
else {
DeQueue(&temp, &line);
printf("Removing %d from queue\n", temp);
}
}
printf("%d items in queue \n ", QueueItemCount(&line));
puts("Type a to add ,d to delete , q to quit :");
}
EmptyTheQueue(&line);
puts("Bye!");
return 0;
}
标签:return,int,代码,汇总,char,cprimerplus,printf,include,void From: https://www.cnblogs.com/hkf100/p/17985841