《C程序设计语言》笔记(三)
六:结构
1:结构体声明中,比如:
struct point{
int x;
int y;
};
struct后面的名字是可选的,称为结构标记。结构成员、结构标记和普通变量可以采用相同的名字,它们之间不会冲突,因为通过上下文分析,总可以对他们进行区分。
2:结构体的初始化,可以在定义的后面使用初值表进行。初值表中同每个成员对应的初值必须是常量表达式,例如: struct point
maxpt = {320, 200};
3:结构体的合法操作只有几种:作为一个整体复制和赋值,通过&运算符取地址,访问其成员。其中,复制和赋值包括向函数传递参数,以及从函数返回值。结构体之间不可以进行比较。
4:在表达式(*pp).x中的圆括号是必须的,因为结构成员运算符”.”的优先级要比”*”额优先级高。表达式*pp.x等价于*(pp.x),因为x不是指针,所以这种表达式是非法的。
个运算符的优先级最高:结构运算符”.”和”->”,用于函数调用的”()”以及用于下标的”[]”。它们的结合顺序是从左向右的。比如,对于下面的结构体:
struct {
int len;
char *str;
} *p;
表达式++p->len,将增加len的值,而不是增加p的值,这是因为该表达式等价于++(p->len);
表达式(++p)->len,将先执行p+1,然后在对len执行操作。
表达式(p++)->len,将先对len进行操作,然后执行p+1.
表达式*p->str,读取的是指针str所指向的对象的值,也就是str指向的字符串的第一个字符。
表达式*p->str++,先读取指针str指向的对象的值,然后在将str+=1;
;
表达式*p++->str,先读取指针str指向对象的值,然后在将p加1.
5:结构体数组的初始化可以如下:
struct key{
char *word;
int count;
}keytab[] = {
“auto”,0,
“break”,0,
“case”,0
};
更精确的做法是,将每一行的初值都括在花括号内,比如:
{{“auto”, 0},{“break”,0},{“case”,0}}
6:sizeof是一个编译时一元运算符,像下面的形式都是合法的:
sizeof 0; sizeof(0); sizeof(int);
但是,像sizeof int;就是非法的。
7:如果low和high都是指针,对于数组a[n]来说,low指向a[0],high指向a[n](最后一个元素的后一个元素),为了得到指向中间元素的指针mid,可以根据指针的减法运算得到:
mid = low + (high - low)/2;
8:向下面这样的声明称为自引用:
struct node{
int num;
struct node *next;
}
在结构体声明的内部,引用到了结构体本身的指针,这是合法的。偶尔也会见到自引用结构的一种变体,就是两个结构体相互引用:
struct t{
struct s *p;
}
struct s{
struct t*q;
}
9:联合可以在不同时刻,保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对齐要求。比如:
union u_tag{
int ival;
float fval;
char *sval;
}u;
中类型中最大的一种。这些类型中的任何一种类型的对象,都可以赋值给u。但必须保证是一致的:读取的类型必须是最近一次存入的类型。程序员负责跟踪当前保存在联合中的类型。如果保存的类型与读取的类型不一致,其结果取决于具体的实现。
,下列语句:flags
&= ~(EXTERNAL|STATIC); 该语句将flags中的相应位置为0.
:C语言提供了,直接定义和访问一个字中的位字段的能力。这就是位字段,或简称字段。它是字中相邻为的集合。比如:
struct{
unsigned int is_keyword : 1;
unsigned int is_extern : 1;
unsigned int is_static : 1;
}flags;
个一位的字段。冒号后面的数字表示字段的宽度(二进制位数)。字段被声明为unsigned
int 类型。可以这样的使用字段:
flags.is_extern= 0;
flags.is_keyword= 1;
flags.is_static= 1;
表明强制在下一个字边界上对齐。
某些机器上,字段的分配是从字的左端到右端进行的,而某些机器上则相反。
字段不是数组,并且没有地址,因此对它们不能使用&运算符。比如&(flags.is_keyword)就是一种语法错误。
七:输入与输出
1:C标准库包含:输入输出函数、字符串处理函数、存储管理函数、数学函数等。ANSI标准精确定义了这些库函数,所以,在任何系统中都有这些函数的兼容形式。
2:最简单的输入函数是使用getchar函数从标准输入中,一般为键盘,一次读取一个字符:int getchar(void);getchar函数在每次调用时返回下一个输入字符。若遇到文件结尾,则返回EOF。符号常量EOF在头文件<stdio.h>中定义。
可以使用符号”<”实现输入重定向,他把键盘输入替换为文件输入,比如prog
< infile,将使程序prog从输入文件infile,而不是键盘中读取字符。
输入也可以通过管道机制来自于另一个程序,比如:otherprog|prog,将运行两个程序otherprog和prog,并将程序otherprog的标准输出通过管道,重定向到prog的标准输入上。
3:int putchar(int)用于输出数据。putchar(c)将字符c输出到标准输出,默认情况下,标准输出为屏幕显示。如果没有出错,则putchar返回输出的字符;如果发生了错误,则返回EOF。
可以使用符号”>”将标准输出重定向到文件中,比如prog>outfile,将把prog的输出重定向到outfile中。
命令prog|antherprog,将把prog的标准输出,通过管道重定向到anotherprog的标准输入中。
4:格式化输出—printf
intprintf(char *format, arg1, arg2,...);该函数的返回值是打印的字符数。比如语句:
,包括换行符。
格式字符串包含两种类型的对象:普通字符和转换说明。在输出时,普通字符将原样不同的复制到输出流中,而转换说明并不直接输出到输出流中,而是用于控制printf中参数的转换和打印。每个转换说明都由一个百分号字符“%”开始,并以一个转换字符结束。在字符“%”和转换字符中间可能依次包含下列组成部分:
负号,用于指定被转换的参数按照左对齐的形式输出。
数,用于指定最小字段宽度。转换后的参数将打印不小于最小字段宽度的字段。如果有必要,字段左边(如果使用左对齐的方式,则为右边)多余的字符位置用空格填充以保证最小字段宽。
小数点,用于将字段宽度和精度分开。
数,用于指定精度,即指定字符串中要打印的最大字符数、浮点数小数点后的位数、整型最少输出的数字数目。
字母h或l,字母h表示将整数作为short类型打印,字母l表示将整数作为long类型打印。
下表列出了所有的转换字符。如果%后面的字符不是一个转换说明,则该行为是未定义的。
在转换说明中,宽度或精度可以用星号*表示,这时,宽度或精度的值通过转换下一参数(必须为int类型)来计算。例如,为了从字符串s中打印最多max个字符,可以使用下列语句:printf(“%.*s\n”,
max, s); 更多的例子如下:
char *s = "0123456789";
printf("str is %.*s(end)\n", 3,s); //输出:str is 012(end)
printf("str is %.*s(end)\n", 0, s); //输出:str
is (end)
printf("str is %.*s(end)\n", 100, s); //输出:str
is0123456789(end)
下表说明了在打印字符串”hello,world”(12个字符)时,根据不同的转换说明产生的不同结果。在每个字段的左边和右边加上冒号,这样可以清晰地表示出字段的宽度,对于字符串来说,宽度意味着最小宽度,精度意味着最大输出字符数,也就是说,宽度不会截断字符串,有可能会扩展输出字符串;精度不会扩展输出字符串,而有可能截断字符串。
printf(":%s:\n",str); // :hello, world:
printf(":%10s:\n",str); // :hello, world:
printf(":%.10s:\n",str); // :hello, wor:
printf(":%-10s:\n",str); // :hello, world:
printf(":%.15s:\n",str); // :hello, world:
printf(":%-15s:\n",str); // :hello, world :
printf(":%15.10s:\n", str); // : hello, wor:
printf(":%-15.10s:\n",str); // :hello, wor :
。
int b = 12345;
printf(":%d:\n",b); // :12345:
printf(":%3d:\n",b); // :12345:
printf(":%10d:\n",b); // : 12345:
printf(":%.3d:\n",b); // :12345:
printf(":%.10d:\n",b); // :0000012345:
printf(":%.0d:\n",b); // :12345:
printf(":%-3d:\n",b); // :12345:
printf(":%-15.10d:\n",b); // :0000012345 :
下表说明了,宽度和精度,对于浮点数1.2345678的作用,可见,对于浮点数来说,宽度意味着最小宽度,精度意味着精确的数字数目。也就是说宽度不会截断数字,有可能会扩展输出字符串;精度就是小数点后的位数。
double d =1.2345678;
printf(":%f:\n",d); // :1.234568:
printf(":%3f:\n",d); // :1.234568:
printf(":%10f:\n",d); // : 1.234568:
printf(":%.3f:\n",d); // :1.235:
printf(":%.10f:\n",d); // :1.2345678000:
printf(":%.0f:\n",d); // :1:
printf(":%-3f:\n",d); // :1.234568:
printf(":%-15.10f:\n",d); // :1.2345678000 :
综上所述,宽度对于字符串、整型、浮点型来说,都不会截断输出的字符串,而有可能会以空格扩展输出的字符串;
填充数字;精度对于浮点数来说,就是精确的小数点位数。
函数printf使用第一个参数判断后面参数的个数和类型。如果参数的个数不够或类型错误,则将得到错误的结果。
sprintf与printf类似,但她将输出保存到一个字符串中,而不是标准输出中。
:变长参数表
printf的声明为: int printf(char
*fmt, ...);
其中,省略号表示参数表中参数的数量和类型是可变的。标准头文件<stdarg.h>中包含一组宏定义,它们对如何遍历参数表进行了定义。该头文件的实现因不同的机器而不同,但提供的接口是一致的。
宏va_list类型用于声明一个变量,该变量将依次引用各参数;
宏va_start将ap初始化为指向第一个无名参数的指针;
宏va_arg,将返回一个参数,并将ap指向下一个参数。va_arg使用一个类型名来决定返回的对象类型、指针移动的步长。
宏va_end,完成一些必要的清理工作。
利用这些宏,实现简单的printf例子如下:
voidminprintf(char *fmt, ...)
{
va_list ap;
char *p, *sval;
int ival;
double dval;
va_start(ap,fmt);
for(p = fmt; *p; p++)
{
if(*p != '%')
{
putchar(*p);
continue;
}
switch(*++p)
{
case 'd':
ival = va_arg(ap, int);
printf("%d",ival);
break;
case 'f':
dval = va_arg(ap, double);
printf("%f",dval);
break;
case 's':
for(sval =va_arg(ap, char*); *sval; sval++)
{
putchar(*sval);
}
break;
default:
putchar(*p);
break;
}
}
va_end(ap);
}
:格式化输入—scanf函数
scanf函数声明:int scanf(char *format,
...);
scanf中,除了format之外,其他所有的参数必须是指针,用于指定经格式转换后的相应输入保存的位置。
当scanf扫描完其格式串(输入字符串中),或者碰到某些输人无法与格式控制说明匹配的情况时,该函数将终止。同时,成功匹配并赋值的输人项的个数将作为函数值返回。如果到达文件的结尾,该函数将返回EOF。下一次调用scanf函数的时候,将在输入字符串上,从上一次转换的最后一个字符的下一个字符开始继续搜索。
格式串通常都包含转换说明,用于控制输入字符串的转换。格式串可能包含下列部分:
空格或制表符,在处理过程中将被忽略;
普通字符(不包括%〕,用于匹配输人流中下一个非空白符字符;
转换说明,依次由一个%、一个可选的赋值禁止字符*、一个可选的数值(指定最大字段 宽度)、一个可选的h,l或L字符以及一个转换字符组成。
如果转换说明中有赋值禁止字符*,则跳过该输入字段,不进行赋值。比如:
res = scanf("%d %*d %d",&a, &b, &c);
printf("a, b, c is %d, %d,%d\n", a, b, c);
printf("res is %d\n", res);
输入“1 2 3”,得到输出结果为:
a, b, c is 1, 3, -1077261788
res is 2
输人字段定义为一个不包括空白符的字符串,其边界定义为到下一个空白符或达到指定的字段宽度。空白符包括空格符、横向制表符、换行符、回车符、纵向制表符以及换页符。包含宽度的例子如下:
res = scanf("%2d %2d %2d",&a, &b, &c);
printf("a, b, c is %d, %d,%d\n", a, b, c);
printf("res is %d\n", res);
输入“1234567”,得到结果:
a, b, c is 12, 34, 56
res is 3
输入“1 2 3456”,得到结果:
a, b, c is 1, 2, 34
res is 3
转换字符如下表:
转换说明d,i,o,u及x的前面可以加上字母h或l。前缀h表明参数表的相应参数是一个指向short类型而非int类型的指针,前缀l表明参数表的相应参数是一个指向long类型的指针。类似地,转换说明e,f和g的前面也可以加上前缀l,它表明参数表的相应参数是一个指向double类型而非float类型的指针。
字符字面值也可以出现在scanf的格式串中,它们必须与输入中相同的字符匹配。因此,我们可以使用下列scanf语句读入形如mm/dd/yy的日期数据:
int day, month,year;
scanf(“%d/%d/%d”,&month, &day, &year);
如果要读取格式不固定的输人,最好每次读人一行,然后再用sscanf将合适的格式分离出来读人。例如,假定我们需要读取一些包含日期数据的输人行,可以这样编写程序:
while (getline(line, sizeof(line)) >0) {
if (sscanf(line, "%d %s%d", &day, monthname, &year) == 3)
printf("valid:%s\n", line); /* 25 Dec 1988 form */
else if (sscanf(line,"%d/%d/%d", &month, &day, &year) == 3)
printf("valid:%s\n", line); /* mm/dd/yy form */
else
printf("invalid:%s\n", line); /* invalid form */
}
:库函数fopen可以打开文件,并返回一个随后可用于文件读写操作的指针。该指针称为文件指针,它指向一个包含文件信息的结构。这些信息包括:缓冲区的位置、缓冲区中当前字符的位置、文件的读或写状态、是否出错或是否已经到达文件结尾等等。在<stdio.h>中定义了一个包含这些信息的结构FILE。在程序中可以这样使用:
FILE *fp;
FILE *fopen(char*name, char *mode);
如果打开一个不存在的文件用于写或追加,该文件将被创建(如果可能的话)。当以写方式打开一个已存在的文件时,该文件原来的内容将被覆盖。但是,如果以追加方式打开一个文件,则该文件原来的内容将保留不变。读一个不存在的文件会导致错误,其他一些操作也可能导致错误,比如试图读取一个无读取权限的文件。如果发生错误,fopen将返回NULL。
个文件分别是标准输人、标准输出和标准错误,相应的文件指针分别为stdin,stdout和stderr,它们在<stdio.h>中声明。在大多数环境中,stdin指向键盘,而stdout和stderr指向显示器。stdin和stdout可以被重定向到文件或管道。
函数 int fclose(FILF*fp);它执行和fopen相反的操作,它释放文件指针以供其他文件使用。因为大多数操作系统都限制了一个程序可以同时打开的文件数,所以,当文件指针不再需要时就应该释放,这是一个好的编程习惯。对输出文件执行fclose还有另外一个原因:它将把缓冲区中由putc函数正在收集的输出写到文件。当程序正常终止时,程序会自动为每个打开的文件调用fclose函数。
值。int
ferror(FILE *fp)值:int
feof(FILE *fp);
:内存管理(stdlib.h)
void*calloc(size_t nobj, size_t size)
。
void*malloc(size_t size)
mallflc函数为长度为size的对象分配内存,并返回指向分配区域的指针;若无法满足要求,则返回NULL。该函数不对分配的内存区域进行初始化。
void *realloc(void*p, size_t size)
realloc函数将p指向的对象的长度修改为size个字节。如果新分配的内存比原内存大,则原内存的内容保持不变,增加的空间不进行初始化。如果新分配的内存比原内存小,则新分配内存单元不被初始化。realloc函数返回指向新分配空间的指针,若无法满足要求,则返回NULL,在这种情况下,原指针p指向的单元内容保持不变。
void free(void*p)
free函数释放p指向的内存空间。当p的值为NULL时,该函数不执行任何操作。p必须指向先前使用动态分配函数mallac,
realloc或calloc分配的空间。
八:其他
1:空白符包括空格、横向制表符、纵向制表符、换行符、换页符。
2:注释以/*开始,以*/结束。注释不能嵌套。
3:指向任何对象的指针都可以转换为void *类型,且不会丢失信息。如果将结果再次转换为初始指针类型,则可以恢复初始指针。
4:运算符的优先级和结合性有明确的规定,但是,除少数例外情况外,表达式的求值次序没有定义。也就是说,除非运算符的定义保证了其操作数按某一特定顺序求值,否则,具休的实现可以自由选择任一求值次序,甚至可以交换求值次序。
版中,通过指向函数的指针调用函数时必须有一个显式的*运算符。ANSI标准允许现有的一些编译器用同样的语法进行函数调用和通过指向函数的指针进行函数调用。旧的语法仍然有效。
6:指向数组中某个对象的指针可以和一个任何整型的值相加,后者将通过乘以所指对象的长度被转换为地址偏移量。相加得到的和是一个指针,它与初始指针具有相同的类型,并指向同一数组中的另一个对象,此对象与初始对象之间具有一定的偏移量。因此,如果P是一个指向数组中某个对象的指针,则表达式P+1是指向数组中下一个对象的指针。如果相加所得的和对应的指针不在数组的范围内,且不是数组末尾元素后的第一个位置,则结果没有定义。
。比如:
p = a;
q = &a[3];
printf("q - p is %d\n", q-p); // 3
可以对指向同一类型的对象的指针进行比较,其结果依赖于所指对象在地址空间中的相对位置。指针比较只对相同对象才有意义:
如果两个指针指向同一个简单对象,则相等;
如果指针指向同一个结构的不同成员,则指向结构中后声明的成员的指针较大;如果指针指向同一个联合的不同成员,则相等;
如果指针指向一个数组的不同成员,则它们之间的比较等价于对应下标之间的比较。如果指针P指向数组的最后一个成员,尽管P+1已指向数组的界外,但P+1仍比P大;
其他情况下指针的比较没有定义。
:由逗号分隔的两个表达式的求值次序为从左到右。右操作数的类型和值就是结果的类型和值。
《C程序设计语言》笔记(三)的更多相关文章
- 基于C#程序设计语言的三种组合算法
目录 基于C#程序设计语言的三种组合算法 1. 总体思路 1.1 前言 1.2 算法思路 1.3 算法需要注意的点 2. 三种组合算法 2.1 普通组合算法 2.2 与自身进行组合的组合算法 2.3 ...
- python程序设计语言笔记 第一部分 程序设计基础
1.1.1中央处理器(CPU) cpu是计算机的大脑,它从内存中获取指令然后执行这些指令,CPU通常由控制单元和逻辑单元组成. 控制单元用来控制和协调除cpu之外的其他组件的动作. 算数单元用来完成数 ...
- C程序设计语言笔记-第一章
The C Programming language notes 一 基础变量类型.运算符和判断循环 char 字符型 character ...
- 《javascript高级程序设计》笔记三
第三章 基本概念 任何语言的核心必然会描述这门语言最基本的工作原理.这部分内容对我们来说,读起来很乏味,甚至会产生困意,但这部分内容却是重要的!我有幸拜读<JavaScript高级程序设计> ...
- [C程序设计语言]第三部分
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 精读《javascript高级程序设计》笔记三——面向对象的程序设计
重点来了,我认为这一章值得好好地反复地看.看第一遍 还是懵懵懂懂,现在看第二遍,终于能看出点意思了. 创建对象 工厂模式 function createPerson(name, age, job){ ...
- 《程序设计语言——实践之路(英文第三版)》【PDF】下载
<程序设计语言--实践之路(英文第三版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382234 内容简介 <程序设计语 ...
- 北京大学Cousera学习笔记--6-计算导论与C语言基础--计算机的基本原理-认识程序设计语言 如何学习
1.是一门高级程序语言 低级语言-机器语言(二进制) 汇编语言-load add save mult 高级语言:有利于人们编写理解 2.C语言的规范定义非常的宽泛 1.long型数据长度不短于int型 ...
- C语言程序设计I—第三周教学
由于本课程是从教学周的第二周开始上课,所以第二次授课是发生在第三周,为了让PTA.云班课和博客能统一,所以将教学周作为随笔的标题.本周由于处理外聘教师随意退课等事情,总结有些延后了. 第三周教学安排 ...
- Go语言学习笔记三: 常量
Go语言学习笔记三: 常量 定义常量 常量就是在声明后不能再修改的量. const x int = 100 const y string = "abc" const z = &qu ...
随机推荐
- linux下用eclipse开发mapreduce遇到的问题
Unable to create the selected preference page.org/apache/hadoop/eclipse/preferences/MapReducePrefere ...
- there is no permission with id `12`
Laravel 本地环境添加菜单之后, 线上报错, 线上线上用同一个数据库, 原因是缓存问题, 解决方法: php artisan cache:clear 如果缓存有重要数据的, 那就要清除对应的缓存 ...
- 01Redis入门指南笔记(简介、安装、配置)
一:简介 Redis是一个开源的高性能key-value数据库.Redis是Remote DIctionary Server(远程字典服务器)的缩写,它以字典结构存储数据,并允许其他应用通过TCP协议 ...
- LUOGU P3708 koishi的数学题
传送门 解题思路 发现当x+1时,有的x%i会+1,有的会变成0,而变成0的说明是x的约数,就可以nlogn预处理出每个约数的贡献,然后每次用n-约数. 代码 #include<iostream ...
- ModelAndView返回mav时,报404
报404的可能性太多了 简单来看,404后边有信息,说明请已经分配到了控制器 经过调试发现,mav已经分配到了页面 原因,modelandview的包导入错误,正确的包是 import org.spr ...
- Binder对象死亡通知机制
本文參考<Android系统源码情景分析>,作者罗升阳. 一.Binder库(libbinder)代码: ~/Android/frameworks/base/libs/bin ...
- python无法启动火狐浏览器且报错“selenium.common.exceptions.WebDriverException: Message: Unable to find a matching set of capabilities”
安装了python2,使用pip安装了selenium,但是在使用时,报了“selenium.common.exceptions.WebDriverException: Message: 'gecko ...
- webpack 4.X 创建 react项目
1. 新建一个文件夹2. 运行 npm init -y 快速初始化项目3. 在跟目录创建src文件夹 dist文件夹4. 在src下创建 index.html main.js // index.htm ...
- 【JZOJ5081】【GDSOI2017第三轮模拟】Travel Plan 背包问题+双指针+树的dfs序
题面 100 注意到ban的只会是一个子树,所以我们把原树转化为dfs序列. 然后题目就转化为,询问一段ban的区间,之后的背包问题. 比赛的时候,我想到这里,于是就开始想区间合并,于是搞了线段树合并 ...
- 【《Objective-C基础教程 》笔记】(八)OC的基本事实和OC杂七杂八的疑问
一.疑问 1.成员变量.实例变量.局部变量的差别和联系,在訪问.继承上怎样表现. 2.属性@property 和 {变量列表} 是否同样.有什么不同. 3.类方法.类成员.类属性:实例方法.实例变量. ...