c语言笔记

a = 5*(b-32)/9
在该语句中,之所以要把表达式先写成乘5然后在除以9二不是直接写成5/9,其原因是在C语言以及许多其他语言中,整数除法操作将执行舍位,结果中的任何小数都会被舍弃。由于5和9都是整数,5和9直接相除会得到0所得的结果也都为0

32位四个字节 一个字节八位 这里的位是指二进制的时候 2的八次幂正好是256 所以可以用两位16进制数来表示
一版情况数组存储的元素是整型,则每个元素4个字节,每个字节用两个16进制数表示 而bytes[3]指向当前元素,而bytes[4]-bytes[7]指向下一个元素

为什么十六进制的(两位数字)是1个字节。说好的1个数字1个字节呢
两个16进制数! 一个字节八个比特,就是八个二进制位 四个二进制数最大表示为15,就是一个16进制数,所以八位可以表示成两个16进制的数!

联合
union u_tag
{
int ival;
float fval;
char *sval;
}u;
实际上,联合就是一个结构,它的所有成员相对于基地址的偏移量都为0,此结构空间要达到足够容纳最宽的成员,并且,其对齐方式要适合于联合中所有类型的成员。对联合允许的操作与对结构允许的操作相同:作为一个整体单元进行赋值,复制,取地址及访问其中一个成员。

结构是一个或多个变量的集合,这些变量可能为不同类型,为了处理方便而将这些变量组织在一个名字之下。由于结构将一组相关的变量看作是一个单元而不是各自独立的实体,因此结构有助于组织复杂的数据,特别是在大型程序中。

struct point
{
int x;
int y;
}
关键字struct引入结构声明。结构声明由包含在花括号内的一系列声明组成,关键字strucrt后面的名字是可选的,称为结构标记(这里是point)。结构标记用于为结构命名,在定义之后,结构标记就代表花括号内的声明,可以用它作为该声明的简写形式。

结构中定义的变量称为成员。

struct声明定义了一种数据类型。在标志结构成员表结束的右花括号之后可以跟一个变量表,这与其他基本类型的变量声明是相同的。例如
struct{…}x,y,z;
从语法角度来说,这种方式的声明与
声明 int x,y,z;具有类似意义。这两个声明都将x,y,z声明为指定类型的变量,并且为它们分配存储空间。 如果结构声明的后面不带变量表,则不需要为它分配存储空间,它仅仅描述了一个结构的模版或轮廓。但是如果结构的声明中带有标记,那么在以后定义结构实例时便可以使用该标记定义。
例如上面给出的结构声明point,语句
struct point pt;
定义了一个struct point类型的变量pt。结构的初始化可以在定义的后面使用初值表进行。初值表中同每个成员对应的初值必须是常量表达式。例如
struct point maxpt = {320,200};

在表达式中,可以通过下列形式引用某个特定结构中的成员:
结构名.成员
其中结构成员运算符“.”将结构名与成员名连接起来。

结构可以嵌套。
struct rect
{
struct point pt1;
struct point pt2;
};
结构rect包含两个point类型的成员.如果按照下列方式声明screen变量:
struct rect screen;
则可以使用语句
screen.pt1.x
引用screen的成员pt1的x坐标。

结构的合法操作只有几种:作为一个整体复制和赋值,通过&运算符取地址,访问其成员。其中,复制和赋值包括向函数传递参数以及从函数返回值。结构之间不可以进行比较。可以用一个常量成员值列表初始化结构,自动结构也可以通过赋值进行初始化。

struct point addpoint(struct point p1,struct point p2)
{
p1.x += p2.x;
p1.y += p2.y;

return p1;

}
其中函数的参数和返回值都是结构类型。之所以直接将相加所得的结果赋值给p1,而没有使用显式的临时变量存储,是为了强调结构类型的参数和其他类型的参数一样,都是通过值传递的。

结构指针
如果传递给函数的结构很大,使用指针的方式的效率通常比赋值整个结构的效率要高。结构指针类似于普通变量指针。
声明
struct point pp;
将pp定义为一个指向struct point类型对象的指针,如果pp指向一个point结构,那么
pp即为该结构,而(*pp).x和(*pp).y则是结构成员。
例如
struct point origin,*pp;
pp = &origin;
printf(“origin is (%d,%d)\n”,(pp).x,(pp).y);
其中,(pp).x中的括号是必需的,因为结构成员运算符".“的优先级比”"的优先级高。表达式
pp.x的含义等价于
(pp.x),又因为x不是指针,所以该表达式是非法的。

结构指针的使用频率很高,为了使用方便,C语言提供了另一种简写方式.假定p是一个指向结构的指针,可以用
p->结构成员
这种形式引用相应的结构成员。这样可以改写代码
printf(@“origin is (%d%d)\n”,pp->x,pp->y);
运算符.和->都是从左至右结合的。

stuct rect r,*rp = &r;
下面4个表达式等价
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).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所指向的对象的值;p->str++先读取指针str指向的对象的值,然后再将str加1(与s++);(*p->str)++将指针str指向的对象的值加1;*p+±>str先读取指针str指向的对象的值,然后再将p加1。

结构数组
struct key
{
char *word;
int count;
} keytab[NKEYS];
声明了一个结构类型key,并定义了该类型的结构数组 keytab,同时也为其分配存储空间。数组keytab的每一个元素都是一个结构。
也可以写成这种形式
struct key
{
char *word;
int count;
};

struct key keytab[NKEYS];
结构数组初始化
在定义的后面通过一个用大括号括起来的初值表进行初始化。
struct key
{
char word;
int count;
} keytab[] = {
“auto”,0,
“break”,0,
“case”,0,
/
…*/
“void”,0
};
与结构成员相对应,初值也要按照成对的方式列出。更精确的方法是,将每一行(即每一个成员也是每一个结构)的初值都括在花括号内,如下所示
{“auto”,0},
{“break”,0},
{“case”,0},

通常情况下,如果初值存在并且方括号[]中没有数值,编译程序将计算数组keytab中的项数。

sizeof运算符
C语言提供了一个编译时(compile-time) 一元运算符sizeof,它可用来计算任一对象的长度。
表达式
sizof 对象
以及
sizeof (类型名)

将返回一个整型值,它等于指定对象或类型占用的存储空间字节数.(严格的说,sizeof的返回值是无符号整型值,其类型为size_t,该类型在头文件<stddef.h>中定义),其中对象可以是变量,数组或结构;类型可以是基本类型如int,double,也可以是派生类型,如结构类型或指针类型。
strlen计算不包含终止null字节的字符串长度,而sizeof则计算包括null字节的缓冲区长度


有一个数组,low和high的初值分别是指向表头元素的指针和指向表尾元素后面的一个指针
这样我们无法简单地通过下列表达式计算中间元素的位置:
mid = (low + high)/2; //错误
这是因为两个指针之间的加法运算是非法的。但是指针的减法运算是合法的high-low的值就是数组元素的个数
mid = low + (high - low)/2;
将mid设置为指向位于high和low之间的中间元素的指针。
千万不要认为结构的长度等于各成员长度的和。因为不同的对象有不同的对齐要求,所以结构中可能会出现未命名的“hole”(洞穴)。
例如:假设char类型占用一个字节,int类型占用4个字节,则下列结构
struct
{
char c;
int i;
};
可能需要8个字节的存储空间,而不是5个字节。使用sizeof运算符可以返回正确的对象长度。

自引用结构(一般指递归)
例子二叉树
struct tnode //树的节点
{
char *word; //指向单词的指针
int count; //单词出现的次数
struct tnode *left; //左子节点
struct tnode *right; //右子节点
};
一个包含其自身的实例的结构是非法的,但是struct tnode *left; 这句声明是合法的,它将left声明为指向tnode的指针,而不是tnode实例本身。

指针是一种保存变量地址的变量。在c语言中,指针的使用非常广泛,原因之一是,指针常常是表达某个计算的唯一途径,另一个原因是同其他方法比较,使用指针通常可以生成更高效更紧凑的代码。

指针是能够存放一个地址的一组存储单元(通常是两个或4个字节)
一元运算符"&"可用于取一个对象的地址。
p = &c;
把c的地址赋值给变量p,我们称p为"指向"c的指针。地址运算符&只能应用于内存中的对象,即变量与数组,它不能作用于表达式,常量或register类型的变量。

一元运算符"*"是间接寻址或间接引用运算符.当它作用于指针时,将访问指针所指向的对象。
指针的声明
int *ip;

指针只能指向某种特定类型的对象,也就是说每个指针必须指向某种特定的数据类型。(一个例外是指向void类型的指针可以存放指向任何类型的指针,但它不能间接引用其自身)

一元运算符*与&优先级比算术运算符的优先级高(加减乘除)

由于指针也是变量,所以在程序中可以直接使用,而不必通过间接引用的方法使用
例如 iq ip是指针
iq = ip;
将把ip中的值拷贝到iq中,这样指针iq也将指向ip指向的对象。

由于C语言是以传值的方式将参数值传递给被调用函数,因此被调用函数不能直接修改主调函数中变量的值。
void swap(int x,int y) //错误的定义
{
int temp;

temp = x;
x = y;
y =temp;

}
swap(a,b);
这个函数的调用无法达到目的。由于参数传递采用传值的方式,因此上述的swap函数不会影响到调用它的例程中的参数的a与b的值。该函数仅仅交换了a与b的副本的值。

那么如何实现呢,可以使主调程序将指向所要交换的变量的指针传递给被调函数。
swap(&a,&b);
由于一元运算符&用来取变量的地址,这样&a就是一个指向变量a的指针。swap函数的所有参数都声明为指针,并且可以通过这些指针来间接访问它们指向的操作数。
void swap(int *px,int *py)
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
指针参数使得被调用函数能够访问和修改主调函数中对象的值。

指针与数组
通过数组下标所能完成的任何操作都可以通过指针来实现。一般来说用指针编写的程序比用数组下标编写的程序执行速度快

int a[10];
定义了一个长度为10的数组a。换句话说它定义了一个由10个对象组成的集合,这十个对象存储在相邻的内存区域中,名字分别为,a[0],a[1]…a[9].
a:| | | | | | | | | | |
a[0] a[9]
a[i]表示该数组的第i个元素。
int *pa;
pa = &a[0];
将指针指向数组a的第0个元素,也就是说pa的值为数组元素a[0]的地址。

x = pa;
则是把数组元素a[0]中的内容复制到变量x中
那么根据指针运算的定义pa+1将指向下一个元素,pa+i将指向pa所指向数组元素之后的第i个元素,而pa-i
将指向pa所指向数组元素之前的第i个元素。那么
(pa + 1),(pa + i),(pa - i)的意义就是对应指向数组元素的内容。
无论数组a中元素的类型或数组长度是什么,上面的结论都成立,"指针+1"就意味着pa+1指向pa所指向的对象的下一个对象。相应的pa+i指向pa所指向的对象之后的第i个对象。

根据数组的定义,数组类型的变量或表达式的值是该数组第0个元素的地址。
pa = &a[0];
因为数组名所代表的就是该数组最开始的一个元素的地址,所以赋值语句pa = &a[0]也可以写成
pa = a;
对数组元素a[i]的引用也可以写成*(a+i)这种形式。
在计算数组元素a[i]的值的时候,c语言实际上先将其转换为*(a+i)的形式,然后载求值,因此在程序中这两种形式是等价的.&a[i]和a+i的含义也是相同的。
但是必须记住,数组名和指针之间有一个不同之处,指针是一个变量,因此在c语言中,语句pa = a和pa++都是合法,但数组名不是变量,因此,类似于a=pa和a++形式的语句是非法的。

当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。在被调用的函数中,该参数是一个局部变量,因此数组名参数必须是一个指针,也是一个存储地址值的变量。

对指针有意义的初始化的值只能是0或者是表示地址的表达式,对后者来说表达式所代表的地址必须是在此前已定义的具有适当类型数据的地址。

指针于整数之间不能相互转换,但0是唯一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较,程序中经常用常量NULL代替常量0,这样便于更清晰的说明常量0是指针的一个特殊值。

有效的指针运算包括 相同类型指针之间的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针之间的减法或比较运算;将指针赋值为0或指针与0之间的比较运算。其他所有形式的指针运算都是非法的

某些条件指针可以进行比较运算
例如:指针p和q指向同一个数组的成员,那么他们之间就可以进行类似于==,!=,<,>=的关系比较运算。如果p指向的数组元素的为之在q指向的数组元素位置之前,那么关系表达式
p < q
的值为真(true)。任何指针与0进行相等或不等的比较运算都有意义。但是指向不同数组的元素的指针之间的算术运算或比较运算没有意义。

指针之间的减法运算的意义:如果p和q指向相同数组中的元素,切p<q那么q-p+1就是位于p和q指向的元素之间的元素数目。可以用来表示字符串的长度

字符指针与函数
printf(“hello ,world\n”)
在上述语句中,printf接受的是一个指向字符数组第一个字符的指针。也就是说字符串常量可以通过一个指向其第一个元素的指针访问。

cahr *pmessage;

语句pmessage = “now is the time”;
将一个指向该字符数组的指针赋值给pmessage。该过程中并没有进行字符串复制,而只涉及到了指针的操作。c语言没有提供将整个字符串作为一个整体进行处理的运算符。
下面这两个定义有很大差别
char amessage[] = “now is the time”;
char *pmessage = “now is the time”;
上述中,amessage是一个仅仅足以存放初始化字符串以及空字符’\0’的一维数组,数组中单个字符可以修改,但amessage始终指向同一个存储位置。另一方面pmessage是一个指针,其初值指向一个字符串常量,之后pmessage可以被修改指向其他地址,但如果修改字符串的内容,结果是未定义的。

strcmp(s,t),该函数比较字符串s和t,并且根据s按照字典顺序小于,等于或大于t的结果分别返回负整数,0或正整数。该返回值是s与t由前向后逐字符比较时遇到的第一个不相等字符处的字符的差值。

char lineptr[MAXLINES]
它表示lineptr是一个具有MAXLINES个元素的一位数组,其中数组的每个元素是一个指向字符类型对象的指针。lineptr[i]是一个字符指针,而
lineptr[i]是该指针指向的第i 个文本行的首字符。

指针数组最频繁的用处是存放具有不同长度的字符串。(指针数组的重要优点就是每一行的长度可以不同,也就是说指针数组的元素不必都指向相同的向量)
二维数组和指针数组是不同的
例如
int a[10][20];
int *b[10];
从语法角度讲,a[3][4]和b[3][4]都是对一个int对象的合法引用,但a是一个真正的二维数组,它分配了200个int类型长度的存储空间,并且通过常规的矩阵下标计算公式20xrow+col(其中,row表示行col表示列)计算得到元素a[row][col]的位置。但是对b来说,该定义仅仅分配了10个指针,并没有对他们初始化,它们的初始化必须以显示的方式进行,比如静态初始化或者通过代码初始化。假定b的每个元素都指向一个具有20个元素的数组,那么编译器就要为它分配200个int类型长度的存储空间以及10个指针的存储空间。

指针数组的声明和图形化描述
cahr *name[] = {“allen”,“forest”,“coldzero”,“rain”}
[ptr0]->“allen\0”
[ptr1]->“forest\0”
[ptr2]->“coldzero\0”
[ptr3]->“rain\0”

二维数组的声明和图形化描述
char aname[][15] = {“allen”,“forest”,“coldzero”,“rain”}
aname:
[allen forest\0 coldzero\0 rain\0]
0 15 30 45

main函数的参数
main(int argc,char *argv[])
argc:值表示运行程序时命令行中参数的数目
argv:是一个指向字符串数组的指针,其中每一个字符对应一个参数。通常通过多级指针处理这些字符。

按照C语言的约定,argv[0]的值是启动该程序的程序名,因此argc最少是1.
*++argv
因为argv是一个指向参数字符串数组起始位置的指针,所以自增运算(++argv)将使得它在最开始指向argv[1]而不是argv[0].每执行一次自增运算,就是的argv指向下一个参数,*argv就是指向那个参数的指针(argv[0]指向的是程序名的指针所以要先++argv才是argv1

注意,++argv是一个指向参数字符串的指针,因此(++argv)[0]是它的第一个字符(另一种有效的形式是**++argv).因为[]与操作数的结合优先级比和++高,所以在上述表达式中必须使用(),否则编译器就会把该表达式当作++(argv[0])。表达式*++argv[0]也就是*++(argv[0]),其目的是遍历argv[0]这个参数字符串,++目的是读取argv[0]代表的字符串中下一个字符。

UNIX系统中的C语言程序有一个公共的约定:以负号开头的参数表示一个可选的标志或参数。

指针函数
由于任何类型的指针都可以转换为void *类型,并且在将它转换回原来的类型时不会丢失信息。这种转换通常不会影响到实际数据的表示,但要确保编译器不会报错。

int (*comp)(void *,void *)
"(comp)"它表明comp是一个指向函数的指针,该函数具有两个void类型的参数,其返回值类型为int

if((*comp)(v[i],v[lef]) < 0)
comp的使用和其声明是一致的,comp是一个指向函数的指针,*cmop代表一个函数。下列语句是对函数的调用
(*comp)(v[i],v[lef])
其中括号是必须的,这样才能保证各个部分正确结合。
如果没有括号
int *comp(void *,void *)//错误的写法
则表明comp是一个函数,该函数返回一个指向int类型的指针。与原意不符

#include指令 用于在编译期间把指定文件的内容包含进当前文件中
#define指令 用任意字符序列代替一个标记
#define 名字 替换文本
通常情况下#define指令占一行,替换文本是#define指令行尾部的所有剩余部分内容,但也可以把一个较长的宏定义分成若干行,这时需要在待续的行莫为加上一个反斜杠
替换只对记号进行,对括在引号中的字符串不起作用。

#ifndefine HDR
#define HDR
/*
hdr.h文件的内容放在这里
*/
#endif
类似方式可以用来避免多次重复包涵统一文件,如果头文件能一致的使用这种方式,那么每个头文件都可以将它所依赖的任何头文件包含进来,用户不必考虑和处理头文件之间的各种依赖关系。

如果初始化表达式的个数比数组元素少,则对外部变量,静态变量和自动变量来说,没有初始化的表达式的元素将被初始化为0.如果初始化表达式的个数比数组元素多,则是错误的。不能一次将一个初始化表达式指定给多个数组元素,也不能跳过前面的数组元素而直接初始化后面的数组元素

字符数组的初始化比较特殊:可以用一个字符串来代替用花括号括起来并用逗号分隔的初始化表达式序列。
例如
char pattern[] = “ould”;
等价于下面的声明:
char pattern[] = {‘o’,‘u’,‘l’,‘d’,’\0’}
这种情况下数组的长度是5(4个字符加上一个字符串结束符’\0’)

将外部变量的声明与定义严格区分开来很重要。变量声明用于说明变量的属性(主要是变量的类型),而变量的定义除此之外还将引起存储器的分配。
如果将下列语句放在所有函数的外部
int sp;
double val[MAXVAL];
那么这两条语句将定义外部变量sp与val,并为之分配存储单元,同时这两条语句还可以作为该源文件中其余部分的声明。
下面的两行语句
extern int sp;
extern double val[];
为源文件的其余组成部分声明了一个int类型的外部变量sp以及一个double数组类型的外部变量val(长度在其他地方确定),但是这两个声明并没有建立变量或为他们分配存储单元。

Unicode通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以

什么是函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
int(p)(int, int);
这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“
”,即(p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int()(int,int)。

所以函数指针的定义方式为:
函数返回值类型 (* 指针变量名) (函数参数列表);
我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(指针变量名)”。但是这里需要注意的是:“(指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。
那么怎么判断一个指针变量是指向变量的指针变量还是指向函数的指针变量呢?首先看变量名前面有没有“
”,如果有“
”说明是指针变量;其次看变量名的后面有没有带有形参类型的圆括号,如果有就是指向函数的指针变量,即函数指针,如果没有就是指向变量的指针变量

最后需要注意的是,指向函数的指针变量没有 ++ 和 – 运算

例子
int Func(int x); /声明一个函数/
int (*p) (int x); /定义一个函数指针/
p = Func; /将Func函数的首地址赋给指针变量p/
//赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,//指针变量 p 就指向函数 Func() 代码的首地址了

include <stdio.h>

int Max(int, int); //函数声明
int main(void)
{
int(*p)(int, int); //定义一个函数指针
int a, b, c;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf(“please enter a and b:”);
scanf("%d%d", &a, &b);
c = (*p)(a, b); //通过函数指针调用Max函数
printf(“a = %d\nb = %d\nmax = %d\n”, a, b, c);
return 0;
}
int Max(int x, int y) //定义Max函数
{
int z;
if (x > y)
{
z = x;
}
else
{
z = y;
}
return z;
}

变量起名字尽量长一点,表达清楚这个变量是干嘛的 不会英语就去查字典,别int a int b intc str1 str2 str3,项目大了谁也看不懂。最后只能重构

if语句的赋值动作一定要用括号扩起来防止优先级混乱产生bug

C 库函数 int putchar(int char) 把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。

发命令下去,偶尔读不到板子返回的数据,可能是timeout不够,加一点可能避免。

学堂在线,网易云课堂,中国大学mooc,好大学在线,慕课网,网易公开课,51cto的学习资源甚至腾讯课堂的第三方机构在大学还会有多个数据库免费使用那么多,无力正版还可以百度云

需要多阅读别人的代码,需要多写自己的代码。在错误中成长,编程需要实践

“始终不安于现状,这好像是我生命的主轴……所以我一直在往前走。 假如所有人都有这么一颗恒心,都有一个追求,然后努力朝前走,就会有很大的收获。每个人都能这样,不枉过这一生,这个社会就会进步很快,国家也会进步很快。 钟南山

Sizeof运算符是静态的,编译时就已经确定了,参数里面不可以做运算
补码的意义就是拿补码和原码可以加出一个溢出的0(高位的1被丢掉) 翁恺 57集

整数的范围就是一个圆环最大的正值加一就变成最小的负值或0最小的值减1就翻回去变成最大值

unsigned:
1如果一个字面量常数想要表达自己是unsigned,可以在后面加u或U
例如255U

Int x = 21323;
short a;
a = (short)x;
强制类型转换不会改变x的值,只是拿x的值来进行计算
逻辑运算当中有短路求值,所以要把赋值等运算语句写入逻辑运算当中

函数的声明,参数的名字可以不写,只需要告诉编译器参数的类型就可以,写名字是为了方便读代码

一对大括号就是一个代码块,里面定义的变量外面不能用,涉及作用域问题。但是外面定义的变量里面能用

return 0 正确 return 非0 错误。翁恺P74 末尾讲的return 0 的意义

Int a[10]; 数组里面有十个元素,从a[0]到a[9] 作为一个变量时a[10]就数组越界
sizeof(a)/sizeof(a[0])计算有多少个元素。
当我使用数组作为函数的参数时,往往必须再用另一个参数来传入数组的大小,因为数组作为参数就转化为指针,所以不能使用sizeof运算符来计算数组元素个数,所以需要传入length。翁恺P84
Int *p = a; 数组整体不需要取地址&符号,但是单个元素就需要
Int *p = &a[0];
数组是常量指针,所以不能被赋值,也不能用两个数组直接赋值,需要在循环里一个一个赋值
int a[]; <===>int * const a;
int *const p ; p是常量指针,指针指向谁这种关系指向是const的,指针不可以再指向其他变量,也就是指针存储的地址不可改变,但是变量自己是可以改变的。(指针自己是个常量,指针存储的地址不能改变)
Int const *p;指针常量 指针指向的是一个变量,这个变量量可改变,但不可以通过指针改变这个变量,不能通过解引用的方式改变变量,不可以通过P去做修改。

给指针加1是让指针指向下一个单元的地址,地址加的是sizeof(类型)的数值
当两个指针相减,结果是两个指针指向地址的差除以 sizeof(类型)的结果,代表两个地址之间能放几个这种类型的变量。

p++;这个是表达式什么意识 先解引用取数据,p再把p递增
虽然++运算符的优先级比
高但是因为是后置++计算的是++之前的值,所以先解引用取数据,再递增. 翁恺p86 指针运算
Void *p;表示不知道指向什么类型的指针;

用引用取地址输出时,用%p来输出,不然变量转换会丢失精度,只能对变量取地址,&(a+b);会error,&右边必须是一个明确的变量

变量在内存中的分配是自顶向下,也就是说先定义的变量内存地址大,处于内存模型的顶端,后分配地址往小排列,内存模型中处于下方

void* malloc(size_t size) ;返回类型是 void*
1malloc申请的空间的大小是以字节为单位的
2返回的类型是void*,需要类型转换为自己需要的类型
例如 (int )malloc(nsizeof(int));

遗憾的是,很多程序员调用分配函数时(如malloc),使用算术表达式作为参数,并且不对这些表达式做溢出检查。产生漏洞(32位系统的上限是2^32,当参数结果超出这个范围就会产生溢出,所以需要对参数进行溢出检查)
详情见<<深入理解操作系统>>P69 P70页对XDR库中安全漏洞的分析。

free();
把申请来的空间还给系统。
申请的空间最终都要归还
Free归还的一定是要最初malloc的内存空间,比如我mallco一个指针p,然后指针p++ ++,指针移动了。我们再来free§,就会报错,因为这是指针p的内存地址不再是最初分配的地址,free归还一定要是当初malloc分配来的那一段内存空间

字符串
以0为结尾的一串字符
0和’\0’是一样的,就是整数0,但是和’0’不同 ,’0’是ASCII码,
0表示字符串的结束,但0不是字符串的一部分
计算字符串的长度时不包含这个0
字符串以数组的形式存在,以数组或指针的形式访问

唯一特殊的地方就是字符串字面量可以用来初始化字符数组

Char *s = “helloc world”;
编译器要找个地方放这个hello world字符串,但是这个字符串在编译时刻就是有值的东西,因此编译器把它放在一个只能读不能写的地方(内存中的代码段),让s这个指针指向它。 若通过s[0]=‘B’;来改变字符串,编译器会报错。
s是一个指针,初始化为指向一个字符串常量(指向字符串常量所在的地方)。由于常量所在的地方,实际上s是const char *s;但是由于历史原因,编译器接受不带const的写法。但是试图对s所指的字符串写入会导致error。
如果需要修改字符串应该用数组:(表示字符数组就存放在我这里,从代码段存放的只读的地方把字符串copy过来)
char s[] = “hello world”;

char s[] = “hello world”;
Char *s = “helloc world”;
那这两种方式怎么选择呢?
数组形式:这个字符串在这里,1作为本地变量空间被自动回收
指针形式:这个字符串不知道在哪里, 1处理参数 2动态分配空间

char *t = “title”;
char *s;
s = t;
并没有产生新的字符串,只是让指针s指向了t所指的字符串。对s的任何操作就是对t做的

scanf防止输入数组越界
char a[8];
scanf(“%7s”,a);这个7告诉scanf读入最多读七个字符。这个7应该比数组大小小1。

常见错误
char *str;
scanf("%s",str);
char *不是是字符串类型,定义str不可以直接使用,由于没有对str初始化为0,str中保存的地址可能是分配空间时指向的任何地址,写入内容,不一定会每次运行都通过,这就是为什么有时这个程序可以,换个电脑就不行。

char buf[]="";
这是一个空的字符串,buf[0]=’\0’,这个数组长度只有1。

char **a ; a是一个指针,指向另一个指针,那个指针指向一个字符串

枚举是一种用户定义的数据类型,但实际上只是int
enum 枚举类型名字{名字0,名字1,名字2};
枚举类型的名字通常不真的使用,要用的是大括号里面的名字,因为它们就是常量符号,类型是int,值依次从0到n;
enum color{red,yellow,blue};

1枚举量可以作为值
2枚举类型名字 可以跟上enum关键字作为数据类型:例如enum color t = red;

struct
1:声明结构类型(是虚没有实体)
struct point
{
int x;
int y;
int z;
};

struct 只在一个函数内使用就在函数内声明,函数外面也要使用就在函数外声明。

定义结构变量
struct point p1,p2;(是实的,定义了变量就有实体)
变量p1,p2都是point。

2:声明结构
struct
{
int x;
int y;
int z;
}p1,p2;
p1,p2都是一种无名结构,里面有x和y,z。

3:声明并定义结构
struct point
{
int x;
int y;
int z;
}p1,p2;
p1,p2都是point,里面有x,y,z的值

给结构变量赋值
struct point p1 = {1,2};
struct point p1 = {.x=1 , .z=2};

1:数组和结构有点像,数组里面有很多单元,但必须是同一种类型,结构有很多成员,可以是不同类型。
2:结构使用.运算符和成员名字访问其成员 例如p1.x , p1.y;

p1 = (struct point){5,10,15}; //强制类型转换,把{5,10,15}强制转化为结构变量p1
//p1.x 为5 ,p1.y为10
p1 = p2;//相当于p1.x=p2.x, p1.y = p2.y

结构指针
3和数组不同,可够变量的名字并不是结构变量的地址,必须使用&运算符, 数组的名字是地址
struct point *pDate = &p1;

结构作为函数参数
int numberOfDays(struct point p1)
1整个结构可以作为参数的值传入函数
2这时候是在函数内新建一个结构变量,并复制调用者的结构的值。
3也可以返回一个结构

结构数组
struct date dates[100];
struct date dates[]={{4,25,2005},{2,4,2005}}

自定义数据类型typedef
c语言提供了一个叫做typedef的功能来声明一个已有数据类型的新名字
比如
typedef int length;
length称为int类型的别名。这样length这个名字就可以代替int出现在变量定义和参数声明的地方了
length a,b,c;
length a[];
typedef 原来的类型名 新的类型名;
例如
typedef struct point{
int x;
int y;
} Date;
typedef 的核心是名称与别名, 最后名称前面如果有*号,可能不属于别名。

Date a = {1,2};
Date 就是结构类型的新名字

全局变量:
定义在函数外面的变量就是全局变量,全局变量具有全局的作用域和生存期
全局变量与任何函数都无关,在任何函数内部都能使用它们

没有做初始化的全局变量会得到0值
指针会得到NULL值
只能用编译时刻已知的值来初始化全局变量。//
它们的初始化发生在main函数之前。
如果函数内部存在与全局变量同名的变量,则全局变量被隐藏。

本地变量:
1本地变量是定义在块内的
(1)他可以是定义在函数的块内
(2)也可以定义在语句的块内
(3)甚至可以随便拉一对大括号来定义变量
2程序运行进入这个块之前,其中的变量不存在,离开这个块,其中的变量就消失了
3块外面定义的变量在里面仍然有效
4块里面定义了和外面同名的变量则掩盖了外面的
5不能在一个块内定义同名的变量
6本地变量不会被默认初始化
7参数金属函数的时候被初始化了

静态本地变量:
1在本地变量定义时加上static修饰符就称为静态本地变量。
2当函数离开时,静态本地变量会继续存在,并保存其值
3静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保存上次离开时的值。
4静态本地变量实际上是特殊的全局变量。
它们位于相同的内存区域。
静态本地变量具有全局的生存期,函数内的局部作用域。static的意思是局部作用域(本地可访问)。

static函数与普通函数的区别:
  1.用static修饰的函数,限定在本源码文件中使用,不能被本源码文件以外的代码文件调用。
  2.普通的函数,默认是extern的,也就是说,可以被其它代码文件调用该函数。
  
  若在函数的返回类型前加上关键字static,函数就被定义成为静态函数。普通 函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。因此定义静态函数有以下好处:
  <1> 其他文件中可以定义相同名字的函数,不会发生冲突。
  <2> 静态函数不能被其他文件所用

1返回本地变量的地址是危险的,因为出了作用域本地变量被回收了,不能保证本地变量的值不变
2返回全局变量或静态本地变量的地址是安全的。
3返回函数内的malloc的内存是安全的,但是容易造成问题
4最好的做法是返回传入的指针。

tips
1不要使用全局变量来在函数间传递参数和结果。
2尽量避免使用全局变量,使用全局变量和本地变量的函数是不可重入的,线程不安全的。

不对外公开:
1在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数
2全局变量前面加上static就使得它成为只能在所在编译单元中被使用的全局变量

编译预处理指令:(不是c语言的指令,所有语言都可以用,结尾不能有;号)
1#开头的是编译预处理指令。
2它不是c语言的成分,但是c语言程序离不开它们。
3#define用来定义一个宏

#define:
#define 名字 值
1注意没有结尾的分号,因为不是c的语句。
2名字必须是一个单词,值可以是各种东西。
3在c语言的编译器开始编译之前,预编译处理程序会把程序中的名字换成值(完成文本的替换)


1如果一个宏的值中有其他宏的名字,也是会被替换掉的
2如果一个宏的额值超过一行,行末需要加
3宏的后面出现的注释不会被当作宏的值的一部分。

没有值的宏:
例如#define _DEBUG
1这类宏是用于条件编译的,后面有其他的预处理指令来检查这个宏是否已经被定义过。#ifdefine

带参数宏的原则
1一切都要括号
2整个值都要括号
3参数出现的每个地方都要括号

#include:
1#include是一个预编译处理指令,和宏一样,在编译之前就处理了
2它把那个文件的全部文本内容原封不动地插入到它所在的地方
所以也不是一定要在.c文件的最前面#include
3#include不是用来引入库的

变量的声明:
1int i;变量的定义
2extern int i;变量的声明

如何避免头文件的重复#include
#ifndefine XXX
#define XXX

#endif

格式化输入输出
见翁恺老师C语言P112

FILE *fp = fopen(“12.in”,“r”);
其中的"r" :打开只读
“r+”:打开读写,从文件头开始
“w”:打开只写。如果不存在则新建,如果存在则清空。
“w+”:打开读写。如果不存在则新建,如果存在则清空。
“a”:打开追加。如果不存在则新建,如果存在则从文件尾开始。
“…x”:只新建,如果文件已存在则不能打开。

位运算:
按位与&
1如果(x)i == 1并且(y)i==1,那么(x&y)i = 1,否则(x&y)i = 0.

i<<j表示i左移j位
i>>j表示i右移j位
左移不看符号位,高位直接舍弃。
右移则分逻辑右移和算术右移
逻辑右移在做短部j个0
算术右移在做短补k个最高有效位的值
实际上几乎所有的编译器/机器组合对有符号数使用算术右移,且许多程序员假设及其会使用这种算术右移,
但对无符号数unsigned,右移必须是逻辑的(在做短补0)

空操作:
while( i!=1);
这条语句的意思是当i!=1时,程序停在这里,已知等待,直到i等于1,程序越过while循环继续执行

new_node->next = head;
new_node->prev = head->prev;
head->prev->next = new_node;
head->prev = new_node;
return new_node;

双向链表在表头插入一个新节点,当然是要先把新节点next指针指向头节点和prev指针指向头节点的前驱,然后头节点prev指针指向新节点,头节点前驱节点next指针指向新节点,顺序别弄错

删除一个节点
node->prev->next = node->next;
node->next->prev = node->prev;
节点prev的next指针指向节点的next,节点next的prev指向节点的prev。

C操作赋&(称为“取址操作符”)创建一个指针。保存变量的地址

int sprintf(char restrict buf,const char restrict format,…);
Int snprintf(char *restrict buf,size_t n,const char *restrict format,…);
注意,sprintf函数可能会造成由buf指向的缓冲区溢出。调用者有责任确保该缓冲区足够大。因为缓冲区会造成程序的不稳定甚至安全隐患,为了解决缓冲区溢出问题,引入了snprintf函数。在snprintf函数,缓冲区长度是一个显示参数,超过缓冲区尾端写的所有字符都被丢弃。

if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!= sizeof(buf)-1)
我们将buf长度减1作为输出字节数,这是为了避免将终止null字符写出。strlen计算不包含终止null字节的字符串长度,而sizeof则计算包括null字节的缓冲区长度。两者之间的另一个差别是,使用strlen需进行一次函数调用,而对于sizeof而言,因为缓冲区已用已知字符串进行初始化,其长度是固定的,所以sizeof是在编译时计算缓冲区长度。

宏命令发下去读不回来可能需要在末尾加上换行符\r\n

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
【4层】3100平米综合办公楼毕业设计(含计算书、建筑结构图) 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 、2项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资 5源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、 5资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值