1,#和##操作符Operator,使用 首个参数返回为一个带引号的字符串
predefined variable
was not declared in the scope;
2,调试debuging program,like breakpoint;
abort();把此函数放置于你想一终端语句的下一行;
too few arguments to function;
warning:no newline at end of file;
#include <stdlibrary.h>
void abort(void);
3,char buffer[BSIZE];
strncpy(buffer,name,BSIZE);
buffer[BSIZE - 1] = '\0'; //赋值,将buffer数组的最后一个元素设置为字符串结尾的空字符
using namespace std;
using std::cout;
using std::endl;
using std::cin;
保证buffer中字符串是以NULL结尾,以后对这个数组使用strlen或不受限制的字符串函数能够正确工作;
strncat总是在结果字符串后面添加NULL字符,strncat最多向目标数组复制len字符(再加上一个NULL字符)不管除去原先dest字符串之后留下的空间;
strncmp,最多比较len个字节;
字符串查找函数
查找一个字符strchr,strrchr;
char *strchr(char const *str,int ch);
char *strrchr(char const *str,int ch);
返回指向该位置指针;
find character;
find strings
字符本身是整型类型
char *strchr(char const *str,int ch);参数类型是整型值,但是却包含了字符值,strchr在字符串str中查找字符ch第一次出现的位置,找到后函数返回一个指向该位置的指针
4,查找字符串--任何几个字符
char strpbrk(char const *str,char const *group); 函数返回一个指向str中第一个匹配group中任何一个字符的字符位置,如果未能找到匹配,函数返回NULL指针;
5,initial position
从字符串中隔离各个单独的标记(Token),丢弃分隔符separator/delimiter
char *strtok(char *str,char const *sep);
分隔符字符集,
standard library
5,内存操作函数
字符串由一个NULL字符结尾,所以字符内部不能包含任何NULL字符
void *memcpy(void *dst,void const *src,size_t length);
void *memmove(void *dst,void const *src,size_t length);
void *memcmp(void const *a,void const *b,size_t length);
void *memchr(void const *a,int ch,size_t length);
void *memset(void *a,int ch,size_t length);
每个prototype都包含一个显示的参数说明需要处理的字节数,遇到NULL字节并不会停止操作;
任何类型指针都可以转换成void*类型指针
memcpy(temp,values,sizeof(values));
对于长度大于一个bytes的bit,kb,mb.gb.tb.pb;
数据经常以成组形势存在
同类型的多个数据存储在一起-->数组
不同类型的多个数据存储在一起-->结构体
aggregate data type;能够同时存储超过一个的单独数据,C提供两种类型的聚合数据类型--数组,结构,数组是相同类型元素集合,它的每个元素是通过下标引用和指针访问;
结构也是值的集合,值称为成员member numbericalpha;一个结构的member elements可以具有不同或是相同的 数据类型record;
数组元素可以通过下标访问,因为数组的元素长度相同,结构中情况并非如此,由于一个结构的成员可能长度不同,不能使用下标访问,每个结构成员都有自己的名字,结构通过名字访问
struct declarations
struct tag {
member-lists
} variable-list;
结构体自定义数据类型,基于自定义的结构体数据类型声明 变量
struct {
int a;
char b;
float c;
} x;
variable-lists
struct {
int a;
char b;
float c;
} y[20],*z;
不同类型的数据,即使成员列表一致
某种特定类型所有结构使用一个单独声明
label(tag)字段允许为成员列表提供一个名字,在后续的声明中使用,标签允许多个变量声明使用同一个成员列表,并且创建同一种类型结构;
struct SIMPLE {
int a;
char b;
float c;
}; declared 是一个数据类型,而不是数据类型的变量
tag标签和成员列表联系在一起;
没有提供变量列表variable-list,并没有创建任何变量;
struct SIMPLE x;
struct SIMPLE y[20],*z;结构数组,结构体指针,结构体变量
同一类型结构体变量
声明结构时可以使用的另外一种好技巧是typedef 创建新的数据类型
typedef strcut {
int a;
char b;
float c;
} Simple; Simple就是新自定义 的数据类型;
struct Simple variables;
struct simple {
int a;
char b;
float c;
};
声明变量
member-lists复杂类型结构 成员,一切变量均可以作为结构体的成员
struct tag {member-list} variable-list;
直接声明结构体变量,不声明结构体数据类型
struct {
int a;
char b;
float c;
} x; 声明结构体数据类型变量
先声明结构体数据类型再 使用新声明的结构体数据类型,声明结构体数据类型的变量
给结构体数据类型取别名alias
typedef
struct SIMPLE {
int a;
char b;
float c;
};
struct SIMPLE x;
struct SIMPLE y[20];
typedef struct {
int a;
char b;
float c;
} Simple;
Simple x;
Simple y[20];
struct COMPLEX {
float f;
int a[20];
long *lp;
struct SIMPLE s;
struct SIMPLE sa[10];
struct SIMPLE *sp;
};
一个结构的成员名字可以和其他结构成员名字相同
结构成员直接访问,结构变量通过点操作符--成员访问操作符号,点操作符接受两个操作数,左操作数-结构体变量的名字,右操作数--成员名称
#include <unistd.h>
ssize_t write(int fd,const void *buf,size_t count);
srite()会把参数buf所指内存写入count个字节到参数fd所指的文件,文件读写位置随之移动
返回值:write()成功执行会返回实际写入的字节数count,当有错误发生返回-1,错误代码存入errno;
error code
eintr 调用被信号中断
eagain使用不可阻断I/O时(O_NONBLOCK),
eadf 参数fd非有效的文件描述符,或该文件已经关闭
变量所指向的结构成员
结构成员间接访问?
假设拥有一个指向结构的指针,如何访问结构成员?首先对指针执行间接访问操作
void func(struct COMPLEX *cp);
*cp 对指向结构体指针执行间接访问操作,获取结构体在内存存放地址,然后用结构体的成员访问操作符.来访问结构体成员,Note:结构体成员.操作符privilege > 间接访问操作符;
综述:箭头操作符-> 指向结构体类型变量->结构体成员Name;
结构体数据类型变量.成员Name 点操作符
箭头操作符对左操作数(指向结构体指针)执行间接访问取得指针所指向的结构,然后和点操作符一样,根据右操作数选择一个指定的结构成员;间接操作内建与箭头操作符内,所以我们不需要显示地执行间接访问or使用括号;
self-reference
结构内部包含一个类型为该结构本身
struct SELE-REFERENCE {
int a;
struct SELE-REFERENCE b;
int c;
};
struct SELE-REFERENCE {
int a;
struct SELE-REFERENCE *b; //执行自身结构体的指针;
int c;
};
结构体内部包含一个指向该结构体本身的指针;结构体内部包含一个指向该结构体本身的指针,同种类型的不同结构,更加高级数据结构,链表数,Advance
incomplete
typedef struct {
int a;
SELE- *b;
int c;
} SELE-;
struct SELE- {
int a;
struct SELE-;
int c;
};实际定义的是一个结构体数据类型,还没使用该定义的数据类型声明定义一个变量;
typedef struct {
int a;
SELE- *b;
int c;
} SELE-;使用typedef 为结构体数据类型定义了一个别名,SELF-是结构体数据类型别名;
数据类型--类型名直到声明的末尾才定义,定义一个结构标签
typedef struct SELE-TAG {
int a;
struct SELE *b; //使用结构体标签
int c;
} SELE-; 数据类型
偶尔,声明一些相互之间存在依赖的结构,至少有一个必须在另外一个结构内部以指针形式存在
declare,每个结构都引用了其他结构的他更
solution:incomplete declaration;声明一个作为结构标签label/mark/tag
identified,把标签用在不需要知道这个结构长度的声明
不完整声明
声明一些相互之间存在依赖的结构,也就是一个结构包含了另外一个结构的一个或多个成员,和自引用结构一样,至少一个结构必须在另外一个结构内部以指针形式存在;问题在于声明部分,如果每个结构都引用了其他结构标签,那个结构应该首先声明
不完整声明incomplete declaration,声明一个作为结构标签的标识符, 结构标签标识符,然后可以把这个标签用在不需要知道结构长度的声明---->声明指向这个结构的指针
struct B;
struct A {
struct B *partner;
/*other declarations*/
};
struct B {
struct A *parenter;
/*otherdeclarations*/
};
typedef struct {
int a;
short b[2];
} Ex2; //结构体数据类型alias
typedef struct EX
{
int a;
char b[2];
Ex2 c; //结构体类型数据变量
struct EX *d;//引用自身,以指针形式嵌入inset
} Ex;
->操作符对px执行间接访问操作,(*px).a
操作符先对执行结构体指针进行间接访问操作,首先得到它指向的结构,然后访问成员,拥有指向结构指针但又不知道结构名字,知道结构名字,可以使用功能相同表达式x.a;
*px,px->a;px所保存的地址都用于寻找这个结构,但结构的第一个成员是a,所以a的地址和结构的地址是一样的,
px保存的地址都用于寻找这个结构体,结构的第一个成员是a,a的地址和结构体的地址一样,px指向整个结构,同时指向结构第一个成员,尽管地址值相等,但他们的类型不同,变量px被声明为一个指向结构的指针,*px结果是整个结构,而不是它的第一个成员
*指针操作符,.结构体成员访问操作符
->结构体指针成员访问操作符
&地址操作符;
-> 优先级> &
&(px->a)先取
*px结果是整个结构,*pi单一的整型值;
Example--表达式px->b
char b[2]
下标引用 指针运算,可以访问数组的其他元素,px->b[1]
px->c.a;点操作符,箭头操作符
之所以使用箭头操作符,是因为px并不是结构,而是指向结构的指针,接下来之所以使用点操作符是因为px->的结构并不是指针,而是结构
*间接访问和指向结构体指向的间接访问->
*px->c.b首先执行箭头操作符,px->c的结果是结构体c,表达式中增加.b访问结构体c的成员b,b是一个数组,px->b.c的结果是一个(常量constent)指针,指向数组的第一个元素,最后对指针执行间接访问,表达式最终结构是数组第一个元素值
结构存储分配
struct Align {
char a; 1Byte
int b; 4Bytes
char c; 1Bytes
};定义了一个结构体数据类型;
系统禁止编译器在一个结构的起始位置跳过几个字节来满足边界要求,所以结构的起始存储位置必须是结构中边界要求最严格的数据类型所要求位置
起始存储位置必须能够被4 整除
存储成员需要满足正确broundary,成员之间才可能出现用于填充的额外内存空间;
起始存储位置必须能够被4整除,系统禁止编译器在一个结构的起始位置跳过几个字节来满足边界对齐要求,因此所有结构的起始存储位置必须是结构中边界要求最严格数据类型要求的位置
结构体数据类型声明中对结构成员列表重新排列,让那些边界要求最严格的成员首先出现,对边界要求最弱的成员最后出现,可以最大限度的减少因边界对齐而带来的空间损失
struct Align2 {
int b;
char a;
char c;
};
所包含 的成员和前面那个结构一样,但只占用8字节空间,两个字符可以紧挨着存储,只有结构最后面需要跳过的两个字节才被浪费
把相关的结构成员存储在一起,提供程序的可读性,可维护,结构的成员应该根据他们的边界进行重排,减少因边界对齐而造成 的内存损失
sizeof操作符能够得出一个结构的整体长度,包括边界对齐而跳过的字节存储,必须确定结构某个成员的实际位置,考虑边界对齐因素,offsetof
offsetof(type,member);
type就是结构类型 struct type,member就是你需要的那个成员名 表达式的结构是一个size_t,表示这个指定成员开始存储的位置距离结构开始存储的位置便宜几个字节
指定成员开始存储的位置距离结构开始存储的位置偏移
offsetof(struct Align,b);
typedef struct {
char product[PRODUCT_SIZE];
int quantity;
float unit_price;
float total_amount;
} Transaction; //声明的是一个自定义数据类型,并没有声明一个此数据类型的变量,数据类型名Transaction
void print_receipt(Transaction trans)
{
printf("%s \n",trans.product);
printf("%d @ %.2f total %.2f\n",trans.quantity,trans.unit_price,trans.total_amount);
}
current_trans是一个Transaction是一个Transaction结构,
print_receipt(current_trans);
C语义参数传值调用方式要求把参数的一份拷贝传递给函数;参数作为传递,必须把32个字节复制到堆栈,以后再丢弃
参数传值调用-->把参数一份拷贝传递给函数
void print_receipt(Transaction *trans){
printf("%s \n",trans->product);
printf("%d @ %.2f total %.2f \n",trans->quantity,trans->unit_price,trans->total_amount);
}
参数传值/传址
函数基于传地址方式调用Example
print_receipt(¤t_trans);
传递给函数的是一个指向结构的指针,指针比整个结构要小得多,把它压到堆栈上的效率提高很多,传递指针另外需要付出的代价是我们必须在函数中使用间接访问来访问结构成员,结构越大,把指向它的指针传递给函数的效率就越高;
参数声明为寄存器变量,提高指针效率;
声明在函数的起始部分需要额外指令Instructions,把堆栈中的参数(参数先传递给堆栈)复制到寄存器;