#include
这个整条语句叫做预处理指令 stdio.h才叫头文件
在C语言中数组参数是以引用(reference)形式进行传递的,也就是传地址
1、puts()函数和printf()函数输出字符串的区别:
puts()函数,输出一串字符串,并且会在末尾进行换行操作
使用printf()输出字符串就不会进行换行
2、特殊字符表示:
三字母词:几个字符的序列,表示另外一个字符
例如:??( 表示一个[字符 ??)表示 ]
??< 表示一个{ ??>表示}
有的编译环境也许会不处理三字母词,vs2017就不处理
转义字符:
如果在某个地方想要使用某个特定字符,但是这个字符在这里有其他的意义,导致不可以使用该字符,这是就应该使用转义字符,将特定字符作为单个字符来处理,
\” 表示”
\\ 表示\
\r 表示回车
\t 表示制表符,一个制表符代表8个空格
\’ 表示’
\b 表示退格键(backspace)
3、#if 0
.........
#endif 也可以进行注释代码,功能要比/**/强大的多
4、注释/**/里面不可以有单独的 */必须是成对出现的
5、长整形和整形以及短整形:
长整形并不一定比整形大,短整形也不一定比整形小
规定:长整形至少应该和整形一样长,短整形最大和整形一样大
Char 0------127
Sign char -127----127
Unsigned char 0------255
Short int -32767------32767
int -32767-------32767
Unsigned short int 0-------65535
Long int
6、枚举类型:
enum{ cup,yellow ,blue,black
}name;
大括号中的单词分别代表的是0 1 2 3
声明为枚举类型的变量实际上是数类型, enum name; 你实际上可以给name赋值为数字都可以
另外枚举类型的变量的大小都是4字节
7、浮点类型:
Double 类型至少和float类型一样长
所有的浮点类型至少能够容纳从10^-37到10^37之间的任何值
8、指针:
int *a;
变量名是a 类型是int*
int* a;与int *a;
int* a,b,c; 写成这样很容易误认为b,c也是指针变量,实际上不是的
定义指针变量最好定义成 int *a;
Char *pArr=”张三”;将字符串常量赋值给char*类型的指针变量pArr
9、typedef:
Typedef char* ptr_to_char;
ptr_to_char a; a是一个指向char类型的指针变量
使用typedef 和 #define 的区别:
使用#define 重命名指针类型是无效的,typedef是可以的
例如:
#define d_ptr_to_char char*
Typedef char *ptr_to_char
声明变量:
d_ptr_to_char a,b; 这样执行之后a被成功声明成了指针类型的变量,但是b仍然是字符变量
ptr_to_char a,b;这样执行之后a,b两个 变量全是指针变量
10、常量:
Const 声明的常量样子和变量一样,只是他们的值是不允许修改的
常量的声明:
int const a;
const int a; 两种方式是一样的
那么既然常量的值是不可以修改的,那么就需要在声明是直接初始化
或者作为函数中形参的值,由实参进行赋值
指针和const 混合使用:
只需要记住const修饰的是其后面的变量,就像下面的例子:
int const *a; 也可以写成 const int *a; //因为*a是被const修饰的,所以*a是一个常量,也就是说指针所指向的值是个常量
Int *const a; 不可以写成const *int a; //因为a是被const修饰的,所以a是个常量,又因为a是一个指针,所以指针是个常量
Int const *const a; //这种情况,因为后面的const修饰的a,但是因为a是一个指针,所以指针是个常量,又因为前面的const修饰的是*a,所以*a是个常量,也就是指针所指向的值十个常量,所以这种用法是:指针和指针所指向的值都是常量
11、作用域:
四种不同类型的作用域:
1文件作用域
2函数作用域
3代码块作用域
4原型作用域
12、c语言内存四区:
内存四区模型:
操作系统给C/C++编写的程序分配内存,通常将分配的内存划分为以下四个区域:
1.栈区:存放局部变量,用完由操作系统自动释放
2.堆区:动态分配给程序的内存区域,由程序员手动释放
3.数据区:
分为两种:
(1)常量区:存放常量,一般是字符串常量
(2)全局区/静态区:存放全局变量和静态变量
4.代码区:
存放可执行代码的区域
13:、goto语句:
14、getchar()返回的是int类型的值
15、逗号操作符:
16、指针:
每个计算机的内存有数以亿计的位组成,每个位可以容纳0或1,但是由于每个位所能表示的值的范围太有限,所以由几个位组成一个单位,来进行容纳范围更大的值
间接访问操作符*
具有从右往左结合的结合性
指针的指针:
int a = 12;
int *b = &a;
int **c = &b;
只要从右往左结合性一步步看就很好理解
A 相当于 12
b &a
*b a,12
C &b
*c *b, b,&a
**c *b , a,12
指针的类型:去掉变量名剩下的就是指针的类型 int*
指针指向的类型: 去掉变量名和*剩下的就是 int
*的运算级别高于+的运算级别,但是小于++的运算级别
char str[10] = "ABCDE";
char *p = str;
单独执行下面的一个语句:
printf("*p=%c\n",*p); 结果是A
printf("*p++=%c\n",*p++); 结果也是A
printf("*++p=%c\n", *++p); B
printf("++*p=%c\n", ++*p); B
需要注意的是++p得到的是p后面的那一个数的地址,不是仅仅只用p的地址加1,而是p的地址加上 类型所占的字节数*1
也就是说++p 《===》 p+(sizeof(int)*1)
如果p的地址是 10011
那么++p的地址就是 10015
17、 如何在函数中使用可变参数?
头文件stdarg.h va_list类型的变量 访问可变参数
Va_startva_arg va_end
18、 数组
int b[10] ,b[0]是int类型的 b是什么类型呢?因为数组名表示数组的地址,所以在这里b就是指向int类型的指针常量,注意不是指针变量,所以你无法修改b的值,因为数组的地址是一定的,因此数组名的值是一个指针常量
所以不可以使用a++。必须使用a+1
int a[10];
Int *b=a;和int *b=&a[0],有区别吗?
回答:因为数组名表示的就是数组的首个元素的地址,所以上面的两条赋值语句是完全一样的
除了优先级之外,下标引用和间接访问是完全一样的
数组中看着很奇怪但是是正确的语句:
5[a] 是和 a[5] 完全一样的
因为a[5] 如果使用间接访问访问的写法就是 *(a+5)那么和 *(5+a)不是一样的嘛
所以也是可以写成 5[a] 是完全没有问题的
指针与下标的运行效率比较:
多维数组数组名表示含义:
Int a[5][10];
数组名a可以看做是一个一维数组,它包含五个元素,只是每个元素又包含十个整形元素
因为a是指向数组的第一个元素,也就是数组首元素的地址,所以a是一个指向一个包含十个整形元素的数组的指针,简单说a就是数组指针
例如int a[3][5]
数组名a指向第一行 是数组指针
a+1指向第二行
a+2 指向第三行
*a表示 a[0]这个指向5个元素的一维数组 是数组
*(a+1) 表示 a[1] 是个数组
*(a+2) 表示 a[2] 是个数组
使用间接访问表示a[2][4]这个元素 *(*(a+2)+4)
其他语言允许写成a[3,5]
但是在C语言中标a[3,5]仅仅是表示a[5] ,如果没有越界的话还好
指向数组的指针:
例如
int a[5], *p=a;
int a[3][5], *p=a;
第一行语句是合法的,p是一个指向一维数组的指针
但是第二句就是非法的,因为 a本身就是一个指向数组的指针,将一个数组指针赋给一个指针,是不可以的 除非p也是一个数组指针 可以这样写 int (*p)[5] =a; 下标的优先级高于间接访问所以要加括号
作为函数参数的多维数组;
Int a[5];
Fun(a);
这样的一维数组 函数原型可以是一下这样的
Void fun(int a[])
或者 void fun(int * a) 因为一维数组名只是首元素的地址,所以形参使用一个指针变量即可
那么对于这样的二维数组呢?
Int a[3][5];
Fun(a);
函数原型可以是一下两种:
Void fun(int a[][5])
或者 void fun(int (*p)[5])
这是因为二维数组名,表示的是一个数组指针,所以形参必须也是数组指针
那么为什么需要第二个数字5,而不是第一个数字3呢?因为编译器必须知道第二个及以后各维的长度,才能对各下标进行求值
对于多维数组如何初始化:
二维数组:
int b[3][5] =
{
{1,2,3,4,5},
{1,1,1,1,1},
{1,1,1,1,1},
};
三维数组:
int a[2][3][4] =
{
{
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
},
{
{2,2,2,2},
{3,3,3,3},
{4,4,4,4},
},
};
四维数组:
对于多维数组初始化时从前面的中括号往后面看的
数组指针:
表示是一个指针,指向的是一个数组的地址
int (*p)[5]
指针数组:
表示是一个数组,只是数组的元素存放的是地址
除了类型之外,指针变量和普通变量很相似,只是普通变量是存放的数字,指针变量是存放的变量的地址罢了,
那么有数组,当然也可以有指针数组,数组元素中是存放的地址罢了
int * p[10]; p是一个int* 类型的指针数组,可以存放十个整形变量的地址
一维数组名取地址表示什么?
int a[5];
&a和a 和&a[0] 的值都是一样的,但是&a的类型是 int (*)[5] 是一个数组指针
a+1表示 数组的首地址加上 1*sizeof(int)
然而 &a+1表示 数组的首地址加上 1*sizeof(a) ,也就是加上的一个数组的占的所有的字节长度
int a[4][5]; 假设数组的首地址为1000的话
那么 a=1000
A+1=1020
A[1]=1020
*(a+1) =1020
A[1]-1=1016
指针函数与函数指针:
返回值是某一种指针的函数叫做指针函数
指针指向函数的地址叫做函数指针、
函数指针除了将函数名用函数指针代替,其他和函数一样
函数指针的定义和初始化:和函数原型一样
Int min(int x,iny y); 函数原型
Int (*p) (int x,int y);
函数指针:
字符串:
要注意strlen()函数返回的是无符号整形类型的值
第十章:结构和联合:
数组是相同元素的集合
结构也是一些值的集合,这些值称为他的成员
结构的声明:
Struct tag
{
member-list
} variable-list;
下标引用和点操作符的优先级是一样的,他们的结合性都是从左往右
->优先级高于*也高于 &
++高于* 但是+小于*
动态申请内存:
Malloc() 成功返回的是void*类型的指针,失败返回NULL(相当于0)
申请的是一块连续的内存
Int *p=malloc(25*sizeof(int)); //申请100字节的内存(假设int类型占4个字节)
初始化:
for(int i=0;i<25;i++)
*p++=0;
或者
for(int i=0;i<25;i++)
P[i]=0;
Free() 释放内存函数,必须是释放一整块,不能是一部分