C语言基础

Day1

  1. 基本的数据类型
  2. 转义字符
  3. 常量

32个关键字

关键字:系统预定义好的,有特定的含义,全部都是小写,不能重新定义。

数据类型:char, double, int, float, short, long, struct, union, enum, void

控制语句:if, else, while, do, for, switch, goto, default, break, continue, case

存储类型:auto, register, static, extern

return:返回函数

const:只读

signed:有符号数

unsigned:无符号数

sizeof:计算所占内存的大小

typedef:给一个已有的类型取别名

volatile:防止编译器优化

标识符:程序员自己定义,一般用来定义变量名,函数名,类型名

命名规范(见名知意

  1. 有数字,字母,下划线组成
  2. 第一个字母不能是数字
  3. 不能和关键字重名

  1. 基本数据类型

相对于32OS:

字符型:char(1byte)

整型:int(4byte),long(4byte),short(2byte)

浮点型:float(4byte),double(8byte)

相对于64OS:

字符型:char(1byte)

整型:int(4byte),long(8byte),short(2byte)

浮点型:float(4byte),double(8byte)

注意:每一种数据类型所占内存大小不一样,数据类型主要是让我们合理分配内存。

有符号数和无符号数:(计算机内默认是有符号数)

signed:数值有正负之分,以补码的形式存储

最高位是符号位,正数的符号位是0,负数的符号位是1

正数:原码,反码,补码都是一样的

比如:10-->0000 1010

负数:-10-->1000 1010

原码:1000 1010

反码:1111 0101

补码:1111 0110(补码的补码就是原码)

    1000 1001 1111 0101

      1000 1010 1000 1010

负数:原码---->补码:取反加1

     补码---->原码:减1取反(补码的补码就是原码)

unsigned:只有正数

2.1字符型家族

值域范围:(以下计算都是补码)

char(1byte) 1byte=8bit

unsigned:0000 0000  ~  1111 1111   0~255

signed:1000 0000  ~  0111 1111     -128~127(如果是1111 1111  那原码就是-1,很大

unsigned char c = 260;(超范围就会转圈去计算值

printf(“%d\n”,c);//4

signed char a = 130;

printf(“%d\n”,a);-126

2.2整型家族

int(4byte)

Unsigned:

0000 0000 0000 0000 0000 0000 0000 0000  ~  1111 1111 1111 1111 1111 1111 1111 1111

0~2^32-1

signed:

1000 0000 0000 0000 0000 0000 0000 0000  ~  0111 1111 1111 1111 1111 1111 1111 1111

-2^31 ~ 2^31-1

2.3浮点型家族

浮点型存储方式和正数的存储方式是不一样的

浮点型的存储方式决定了他不能够准确的表示一个数,只能是一个近似的值

float(4byte):单精度浮点数,有效数字的位数一般为6-7位(%f)

bouble(8byte):双精度浮点数,有效数字的位数一般位15-16位(%lf)

%f和%lf默认输出小数点后六位。

printf(“格式控制串”,输出表);

格式控制串:原样输出的内容+格式化符(%d,%f)

输出表:要输出的对象

练习:

求short的值域

2byte

Unsigned:

0000 0000 0000 0000  ~  1111 1111 1111 1111

0 ~ 2^16-1

signed:

1000 0000 0000 0000  ~  0111 1111 1111 1111

-2^15  ~  2^15-1

3.转义字符

“s  y  \453  a  b”(6个字节)(字符串/0结尾)

  1. 常量

在程序运行期间,其数值不会被改变的量

4.1字符常量

‘a’ , ‘b’ , ‘c’

4.2整型常量

二进制:0110

八进制:066

十进制:99 -2

十六进制:0x234

注意:默认情况下,整型常量都是有符号的

无符号的int型数:66U

长整型:66L

无符号的长整型:66UL

4.3浮点型常量

小数:1.23   0.00001   10000(浮点型常量包含整型常量)

指数形式:(1e-5) (1e+5)

4.4字符串常量

注意:字符串以’\0’作为结束符

4.5标识常量(宏)

#define 宏名 表达式

注意

  1. 宏名一般用大写,小写也可以,因为为了和变量区分,所以用大写
  2. 宏后面没有分号

gcc -E  .c  -o  .i

vim  .i

宏只是单纯的替换

宏函数:(既有函数的特点,又有宏的特点)

#define 函数名(形参) 函数体

注意:宏只是单纯的替换,不会考虑运算的优先级问题,所以需要给每个形参加括号,整个表达式也加括号。

  1. 变量

如何定义一个变量?

存储类型 数据类型 变量名;

存储类型:决定了开辟的空间在内存中的哪个分区(局部变量不写默认auto,全局变量不写就是没有)

数据类型:决定了要开辟的内存空间的大小

变量名:开辟的空间的名字

5.1局部变量

定义在函数体内部的变量(任何函数体)

5.2全局变量

定义在函数体外的变量

5.3存储类型

存储类型:auto,extern,static,register

auto:修饰的变量存储在栈区,只能修饰局部变量

extern:修饰的变量存储在静态区(.bss和.data统称为静态区),只能修饰全局变量

static:修饰的变量存储在静态区,局部变量和全局变量都可以修饰

register:修饰的变量存储在寄存器中,只能修饰局部变量

总结:

  1. 除了static和register修饰的局部变量外,其他的都存在栈区
  2. 全局变量存储在静态区
  3. 静态变量存储在静态区(static修饰的变量就是静态变量)

5.4初始化

初始化:定义变量时对变量进行赋值

  1. int a = 10;//初始化
  2. int a;

  a = 10;//赋值

总结

  1. 全局变量没有初始化其默认值为0
  2. 局部变量没有初始化其默认值为随机值 (64位操作系统优化为0)

auto修饰局部变量,存储在栈区

register:修饰局部变量,存储在寄存器中,建议把变量存储在寄存器,可以提高程序的运行速度,最终是否存储在寄存器中,取决于编译器,如果没有寄存器,存储在栈区。

extern:修饰全局变量,存储在静态区

程序可以由多个.c文件组成,但一个程序只能有且仅有一个main函数

作用:告诉编译器,这个全局变量已经在其他文件定义过了。

static:修饰的变量存储在静态区,既可以修饰局部变量也可以修饰全局变量

  1. static修饰局部变量时,延长了局部变量的生命周期,如果局部变量没有初始化,其值为0,如果初始化,只能初始化一次

  1. 修饰全局变量,只能在本文件内使用(限制了全局变量的作用域)

5.5生命周期和作用域

5.5.1生命周期

从什么时候开辟空间到什么时候释放空间

5.5.2作用域

使用的范围

局部变量:

生命周期:从定义开始,到模块(大括号)结束

作用域:大括号内

static修饰的局部变量:

生命周期:从定义开始,到程序结束

作用域:大括号内

全局变量:

生命周期:从定义开始,到程序结束

作用域:整个程序

static修饰的全局变量:

生命周期:从定义开始,到程序结束

作用域:本文件内

作业:

整理笔记

思维导图

Day2

数据类型转换

运算符

输入输出

  1. 数据类型转换

1.1强制类型转换(我们自己转的)

1.2隐式类型转换(编译器转的)

横向箭头:不管有没有进行混合运算,都势必进行转换,

注意:char,short使用的时候都按照int来使用

注意:float使用的时候按照double来使用

注意:竖向箭头只有进行混合运算时才会进行转换

案例:

1000 0000 0000 0000 0000 0000 0000 1000

1111 1111 1111 1111 1111 1111 1111 1000

  1. 运算符

单算移关与,异或逻条赋

单目运算符,算数运算符,左移右移,关系运算符,按位与,异或,按位或,逻辑运算符,条件运算符,赋值

2.1算数运算符

+, -, *, /, %, ++, --

注意:%不能用于浮点数

++在前:++a,先自加,再赋值

++在后:a++,先赋值,再自加

注意:如果a++或者++a自成立一条语句。都当作a=a+1

案例

2.2关系运算符

>, <, >=, <=, ==, !=

注意:0<a<5//error

等号的书写(****************)

常量写在等号左边

2.3逻辑运算符

&&  ||  !

表达式1 && 表达式2

&&截断法则:有一个为假结果就为假,前一个为假,后面就不进行运算了

表达式1 || 表达式2

||截断法则:有一个为真,结果就为真,前一个为真,后面就不需要进行计算

2.4sizeof运算符

2.5三目运算符

表达式1?表达式2:表达式3

判断表达式1的值是否成立,如果成立,将表达式2的值作为整个表达式的值,否则,将表达式3的值作为整个表达式的值

int a = 1,b = 2,c = 3;

a = b++;//a=2,b=3       c = ++a;//a=2,c=2

2.6逗号运算符

表达式1,表达式2,表达式3,………………表达式n

从左到右依次计算表达式的值,将表达式n的值作为整个表达式的值

注意:逗号运算符的优先级是最低的,所以使用的时候加括号

  1. 设int i = 2,j = 3,k = 4,a = 4,b = 5,c = 3;则执行表达式(a=i<j) &&(b =j>k)&&(c=i,j,k),c的值是多少?

2.7位运算符

&,|,~,^,<<,>>

2.7.1与运算(&)(有0为0)

1101 0011

&   0110 0101

0100 0001

案例:将1101 0011 的0-2位清零

1101 0011

&   1111 1000

1101 0000

2.7.2或运算(|)(有1为1)

1101 0101

|   0110 1101

1111 1101

案例:将1101 0101的3-5位变成101

1101 0101

&   1100 0111

1100 0101

|   0010 1000

1110 1101

2.7.3取反

~1101 0010--------->0010 1101

2.7.4异或

相同为0,不同为1

1101 0010

^   0100 1000

1001 1010

2.7.5左移

高位丢弃,低位补0

将1左移俩位

0000 0001--->0000 0100

2.7.6右移

无符号数:低位丢弃,高位补0

有符号数:低位丢弃,正数高位补0,负数高位补1

1000 0000 0000 0100

1111 1111 1111 1100

1111 1111 1111 1111

1000 0000 0000 0001------>  -1

3.输入输出

函数:有独立功能的模块

标准的输入输出函数:scanf,printf(对变量的类型没有限制)

输入:从键盘拷贝数据到内存中

输出:从内存拷贝数据到显示屏

3.1输出

printf(“格式控制串”,输出表)

格式控制串:原样输出的内容(可省)+格式化符

输出表:要输出的对象

整型:

%d:十进制整数

%o:八进制整数

%x,%X:十六进制整数

#:自动在八进制和十六进制前加前缀

%u:无符号整型

%hd:short类型

%ld:long类型

%lld:longlong类型

字符型:

%c字符型

浮点型:

%f:float

%lf:double

%e:指数

%g:选择小数和指数合适的一种

.n:保留n个小数

m:指定我们输出的域宽,默认是右对齐,m的值大于数据的实际长度,左边补空格,否则,原样输出

%m.nf

3.2输入

scanf(“格式控制串”,地址表)

地址表:&+变量名

注意:

  1. scanf格式控制串,不要加修饰语,如果要加,原样输入

  1. 如果输入“%d%d”时要给多个变量赋值,在格式控制符直接没有间隔,那在输入的时候,以空格,回车,tab作为一个变量的输入结束
  2. 全部输入结束,必须以回车作为结束符

  1. 如果是“%c%c”,在输入的时候,不能有空格,回车,tab,因为空格,回车,tab也是字符

解决办法:

  1. 在“%c%c”之间加个空格,逗号(输入时原样输入

  1. 加%*c,*代表是抑制符

3.3字符的输入输出

int getchar();

返回值:从键盘得到的ASCII码

char a;

a = getchar();

putchar(参数);

参数:你要输出的ASCII码

printf右结合,从右到左计算

首先:a++,第四位输出定格在2,a=3,

其次,a,第三位输出不能确定a=3

然后:++a,此时a=4,但第二位还不能确定

最后:第一个赋值确定为4,a=5,第二位第三位为5可以确定

总结:先赋值的第一次就可以确定,后赋值的要等运算完成,才能确定。

首先,++a等于7第一个

其次,第二个++a,影响到了前面的值,第二个等于8,所以第一个也为8

最后,后面的自加运算不受影响。

总结:只有第一个受到了第二个的影响。

  1. 自定义宏,用三目运算符实现比较俩个数的大小(使用输入输出)

  1. 设x为int变量,x = 10,计算x+=x-=x-x,x的值是多少?(x=20)

x+=2;

x=x+2

  1. 定义x和y为double型变量,x=1,y=x+3/2,y是多少?(2.0)
  2. 定义t为int型变量,则表达式t=1,t+5,t++的值是多少?(1,t=2)

Day3

控制语句

数组

三大结构:顺序结构,选择结构,循环结构

1.控制语句

1.1顺序结构

语句按照一定的先后顺序去执行

1.2选择结构

1.2.1单分支选择语句

if(表达式)

{

语句;

}

先判断表达式的值,如果表达式的值为真,则执行语句

1.2.2双分支if语句

if(表达式)

{

语句1;

}

else

{

语句2;

}

先判断表达式的值,如果表达式的值为真,执行语句1,否则执行语句2.

案例:输入一个年份,判断该年是平年还是闰年

1.2.3多分支if语句

if(表达式1)

{

语句1;

}

else if(表达式2)

{

语句2;

}

else if(表达式3)

{

语句3;

}

………………

else if(表达式n)

{

语句n;

}

else

{

语句n+1;

}

从上到下,依次判断表达式的值,如果表达式的值成立,就执行对应的语句

案例:输入一个成绩,判断成绩的等级

1.2.4switch语句

Switch(表达式

{

case 标号1

语句1;

case 标号2:

语句2;

…………

case 标号n:

语句n;

default:

语句n+1;

}

  1. 表达式不能是float类型
  2. 标号必须为常量
  3. 表达式=标号时,执行冒号后面的语句,直到switch,case语句结束,或者碰到break语句结束,所有的标号都不等于表达式时,执行default

案例:

写出下面程序的结果:

int a = 5;

switch(a)

{

case 2:printf(“2\n”);

default:printf(“不存在该选项\n”);

case 4:

case 1:printf(“1\n”);

case 3:printf(“3\n”);break;

case 0:printf(“0\n”);

}

案例:

输入年份,月份,输出该年该月有多少天?

作业:输入年份,月份,天数,输出是该年的第几天?

1.3循环结构

重复的去做某一件事

循环的三要素:循环的起始条件,循环的终止条件,循环变量的变化

1.3.1for循环

for(表达式1;表达式2;表达式3)

{

循环体;

}

表达式1:循环的起始条件

表达式2:循环的终止条件

表达式3:循环变量的变化

先执行表达式1的值,再执行表达式2的值,如果表达式2的值为真,执行循环体,然后执行表达式3的值,如此反复,直到表达式2的值为假,跳出循环

思考:表达式1,表达式2,表达式3能不能省略?

省略表达式1:

省略表达式2:(死循环)

省略表达式3:

注意:表达式1,2,3都是可以省略的,但是分号不能省略

案例:

for(i = 0;i < 2;i++)

for(j = 0;j <3;j++)

每一次循环i,j的值是多少?

案例:

*

***

*****

*******

自己定义行数进行打印。

1.3.2while语句

while(表达式)

{

循环体;

}

判断表达式的值是否成立,如果成立,执行循环体,否则,跳出循环

案例:求1-100之和

1.3.3do while语句

do

{

循环体;

}while(表达式);

总结:while和do while区别

while先判断,再执行,语句至少执行0次

do while先执行,后判断,语句至少执行1次

break,continue

break:1,跳出switch语句 2,跳出循环

Continue:结束本次循环,开始下一次循环

死循环

没有第一个i++就是死循环

1.3.4死循环

for(;1;)

{

}

while(1)

{

}

1.3.4goto语句

无条件跳转语句,一般格式为goto语句标号

语句标号:按照标识符命名规范

数组

思考?定义1000个int型变量,挨个定义,变量名;

  1. 概念

一组数据类型相同的元素的集合

特点:(1)数据类型相同(2)地址连续

打印地址%p

  1. 定义

存储类型 数据类型 变量名;

int a;//定义了一个整型变量

存储类型 数据类型 数组名[元素的个数];

int a[5];//定义了一个整型数组

存储类型:auto,static,extern,register

数据类型:数组中每一个元素的数据类型

数组的数据类型:数据类型 [元素个数]

数据类型:去掉变量名就是数据类型

数组所占内存空间=sizeof(数据类型)*元素个数

数组元素个数不同,数据类型也不同

注意:

  1. 数组名代表整个数组
  2. 数组名也代表数组首元素的地址

注意:元素个数必须是一个确定的数

  1. 初始化

3.1部分初始化

int a[5] = {1,2,3};

a[0] = 1, a[1] = 2, a[2] = 3, a[3] = ? a[4] = ?

在进行部分初始化的时候,未初始化部分的值为0,因此,利用这一特点可以给数组中元素清零。

int arr[100]= {0};

3.2全部初始化

int a[5] = {1,2,3,4,5};

int a[ ] = {1,2,3};//在进行全部初始化的时候,数组元素的个数是可以省略的,由后面赋值的具体个数来决定

总结:

  1. 数组定义在函数体内,没有初始化,其值为随机值
  2. 数组定义在函数体外,没有初始化,其值为0
  3. 如果数组被static修饰,没有初始化,其值为0
  1. 数组的访问

数组名[下标];

注意:下标是从0开始

案例:

  1. int a[5];

a[5] = {1,2,3,4,5};//error

  1. int a[5];

a[] = {1,2,3,4,5};//error,数组名代表数组首元素地址

  1. int a[ ] = {0};//表示你这个数组中只有一个元素,没有意义,但是正确的
  2. int a[ ] ;//数组的元素个数必须是一个确定的数

作业:

  1. 打印等腰三角形

  1. 9x9乘法表

  1. 选做(打印菱形)

Day4

冒泡排序

字符数组

字符串处理函数

二维数组

  1. 冒泡排序

思想:从左到右,俩俩依次比较,如果前一个数比后一个数大的话,交换位置,否则不变

int temp = 0;

temp = a[i];

a[i] = a[i+1];

a[i+1] = temp;//交换

  1. 字符数组

字符数组的本质:其实就是字符串,以’\0’作为结束符

存储类型 数据类型 数组名[元素个数];

char str[10];//定义了一个字符数组,名字叫str,有十个元素,每一个元素都是char型

char str[6] = {‘h’,’e’,’l’,’l’,’o’,’q’};//error 最多存放五个元素,留一个位置给‘\0’

char str[6] = “hello”;

char str[6] = {‘\0’};//字符数组清零

2.1字符数组的输出函数

%s:字符串

puts(数组名);

功能:将数组中的内容输出打印到终端,并且自动加换行

注意:遇到’\0’结束

2.2字符串的输入函数

gets(数组名);

功能:将键盘接收到的字符串存放在数组中,并在末尾自动加’\0’

注意:不会越界检查,所以输入时不要越界

回车被直接使用

2.3总结

2.3.1scanf和gets区别

gets是以回车作为结束符,但是scanf以回车,table,空格作为结束符

缓冲区

gets:当完成字符串的输入后,会自动清空缓冲区内容

scanf:当完成字符串的输入后,缓冲区会遗留空格,回车,tab

注意

gets首先会检查缓冲区有没有内容,如果有,直接拿来使用,否则输入

scanf是标准的输入函数,只能通过键入方式

2.3.2printf和puts的区别

puts会自动添加换行,而printf不会

  1. 字符串的处理函数

strlen, strcpy, strcat, strcmp

头文件:#include<string.h>

3.1求字符串的长度

strlen(数组名);

功能:求字符串的长度

返回值:求得的字符串的实际长度,不包含’\0’

strlen和sizeof的区别:

  1. strlen是求得的字符串的实际长度,不包含’\0’,而sizeof求得的是整个空间的大小
  2. sizeof是运算符,strlen是库函数

案例:求字符串的长度,不使用库函数

3.2字符串的拷贝函数

strcpy(数组1,数组2/字符串);

功能:将数组2的内容拷贝到数组1,包含’\0’,相当于完全拷贝

注意:数组1的容量大于数组2

strncpy(数组1,数组2/字符串2,n);

功能:将数组2的前n个字符拷贝到数组1中

注意:拷贝的字符不包含’\0’

3.3字符串的连接函数

strcat(数组1,数组2/字符串2);

功能:将数组2或者字符串2的内容连接到数组1中,数组1的’\0’会被覆盖

注意:数组1的容量大于数组2

strncat(数组1,数组2/字符串2,n);

功能:将数组2的前n个字符,连接到数组1中

3.4字符串的比较函数

strcmp(数组1/字符串1,数组2/字符串2);

功能:比较字符串1和字符串2的大小

返回值:

大于0:字符串1 > 字符串2

等于0:字符串1 == 字符串2

小于0:字符串1 < 字符串2

比较规则:

从左到右依次对字符串的ASCII码进行比较,直到遇到不同的ASCII码或者遇到’\0’结束

案例:

实现字符串的拷贝,不使用库函数

4.二维数组

数组:一组数据类型相同的元素的集合

整型数组:一组int型的数集合在一起

字符数组:一组char型的字符集合在一起

二维数组:一组(数组类型的)元素集合在一起

4.1概念

本质:表示元素为一维数组的数组(数组的数组)

数组特点:(1)数据类型相同(2)地址连续

4.2定义

存储类型 数据类型 数组名[元素个数];

存储类型 数据类型 数组名[行数][列数];

行数:有几个一维数组

列数:一维数组中有几个元素个数

int a[2][3];//定义了一个二维数组,数组的长度为2,每一个元素又是长度为3的int型数组

4.3数组的初始化

4.3.1部分初始化

int a[2][3] = {1,2};

4.3.2全部初始化

int a[2][3] = {1,2,3,4,5,6};

int a[2][3] = {{1,2,3},{4,5,6}};

注意:二维数组的行数可以省略,列数不能省

int a[ ][3] = {1,2,3,4,5,6,7,8};//表示有三个一维数组,每一个一维数组有三个元素

int a[2][ ] = {1,2,3,4,5,6};//error有俩个一维数组,但每一个一维数组中有几个元素,不能确定

4.4数组的访问

案例:打印杨辉三角 8x8

1

1  1

1  2  1

1  3  3  1

作业:

  1. 求一组数据中的最大值和次大值(不使用冒泡排序)

  1. 打印字符数组中每一个元素

  1. 实现字符串的连接(不使用库函数)

Day5

二维字符数组

函数

指针

  1. 二维字符数组

char dtr[30] = “hello”;

scanf(“%s”,dtr);

printf(“%d\n”,dtr);

存储类型 数据类型 数组名[行数][列数];

行数:(一维字符数组的个数)字符串的个数

列数:(一维字符数组中字符的个数)每一个字符串最多存放几个字符

char str[3][20];//定义了一个长度为3的数组,每一个元素都是长度为20的字符数组

案例:实现字符串的输入输出

  1. 函数

一个独立的功能模块

2.1为什么要使用函数

2.1.1是程序变得模块化

2.1.2.提高代码的复用率

2.2函数的分类

2.2.1库函数

printf,scanf,strlen

2.2.1.1引入头文件

#include<stdio.h>

#include<string.h>

2.2.1.2调用函数

strlen(str);

函数名(实际参数列表);

注意:参数有多少个,数据类型是什么,返回值

2.2.2自定义函数

2.2.2.1函数定义

存储类型 数据类型 函数名(形式参数列表)

{

函数体;

返回值

}

存储类型:auto,static,extern,register

数据类型:函数返回值的数据类型

函数名:见名知意

形式参数列表:要实现功能所需要的参数,需要调用者传入(1,需要几个参数2,每个参数需要什么类型)

函数体:具体实现的功能

返回值:如果没有返回值,可以省略,不需要写return,数据类型void,如果有,有且仅有一个

2.2.2.2调用函数

函数名(实际参数列表)

注意

  1. 需要将实参的值传递给形参,实参的个数和数据类型必须和形参一致
  2. 实参可以是变量,常量,表达式,必须是一个确定的值
  3. 实参和形参是俩块独立的内存空间
  4. 传参实际上是将实参的值拷贝给形参
  5. 形参是局部变量,在函数调用的时候被定义,函数调用结束后,释放空间

案例:

2.2.2.2.1调用时

2.2.2.2.2调用结束

2.2.3函数声明

如果函数没有在main函数之前,就需要在main函数之前进行声明

声明:将函数头直接拷贝至main函数之前,然后加分号

未加声明之前:

加上声明之后:

声明的作用:帮助编译器做语法检查

案例:封装函数实现+ - * /

  1. 输入
  2. 选择
  3. 调用模块
  4. 打印

  1. 指针

3.1什么是指针

指针是一种数据类型,是一种保存地址的数据类型

int a;//int:用来保存整型数的数据类型

char c;//char:用来保存字符的数据类型

float b;//float:用来保存小数的数据类型

指针 d;//指针:用来保存地址的数据类型

3.2什么是地址

内存分配的最小单位是字节,每一个字节都有一个编号,我们把这个编号叫做地址

地址的本质:内存单元的编号

指针:指针就是地址

指针的本质:内存单元的编号

3.3指针变量

int a;//整型变量

float b;//浮点型变量

char c://字符型变量

指针变量:专门用来保存地址(内存单元的编号)的变量

3.4指针的定义

存储类型 数据类型 *指针变量名;

int *p;

存储类型:auto,extern,static,register

数据类型:指针所指向的数据类型(去掉*和变量名,剩下的就是指针所指向的数据类型)

指针的数据类型:数据类型 *//int *

注意:

在所有32os,所有的指针占4个字节

在所有64os,所有的指针占8个字节

3.5赋值

char *p = &a;

char *p = NULL;

p = &a;

注意:对指针赋值时,一定要注意数据类型的匹配

思考?

  1. 什么是指针

是一种数据类型,保存地址的数据类型

  1. 地址是什么

字节(内存单元)的编号

  1. 什么是指针变量

专门用来保存地址(内存单元的编号)的变量

  1. 指针变量如何定义

存储类型 数据类型 *指针变量名

int *p;

  1. 指针变量赋值后能干什么

指针指向谁,就是保存谁的地址,赋值之后可以操作地址里面的元素。

3.6空指针

没有指向的指针(值为0的指针,就认为该指针没有指向)

注意:0号地址,禁止操作

要操作的话就改变指针指向

3.7野指针

不知道指向哪里的指针

局部变量没有初始化,其值是随机值

局部指针变量没有初始化,就是野指针

如何避免野指针的出现?初始化为NULL

int *p = NULL;

很危险!!!!!

Day6

  1. 值传递

案例:用子函数的形式,实现俩个整数的交换

  1. 地址传递

  1. 二级指针

3.1概念

指针的指针

二级指针的内存空间存放的是一级指针的地址

3.2定义

定义一级指针:存储类型 数据类型 *指针变量名;

数据类型:指针指向的数据类型

存储类型 数据类型 **指针变量名;

总结:

  1. 指针的数据类型,去掉变量名剩下的就是

int *p;//int *

int **pp;//int **

int ***ppp;//int ***

  1. 指针指向的数据类型,去掉一个*和变量名就是所指向的数据类型

int *p;//int

int **pp;//int *

int ***ppp;//int **

  1. 指针所能访问的空间大小,由指针所指向的数据类型决定
  1. int a;

int *p = &a;//*p所能访问的空间大小是4个字节

  1. char b;

char *p = &b;//*p所能访问的空间大小是1个字节

  1. int*p;

int **pp = &p;//**pp所能访问的空间大小是4个字节

  1. 指针和一维数组

4.1指针的算数运算

总结:

p+n:p+n相对于p向地址增大的方向移动了n个数据

 实际的变化:p + sizeof(指向的数据类型)*n

p-n:p-n相对于p向地址减小的方向移动了n个数据

 实际的变化:p - sizeof(指向的数据类型)*n

p++:p向地址增大的方向移动了一个数据

p--:p向地址减小的方向移动了一个数据

p-q:(p和q的数据类型必须一致)这俩个指针直接相隔的个数

 实际的变化:(p-q)/sizeof(指向的数据类型)

注意:

  1. 指针的算数运算只有在操作连续的内存空间时才有意义
  2. p是指针变量,以上的方法也适用于常量,但是++,--除外

(数组名:1.数组首元素地址(指针常量))

4.2通过指针常量来访问

数组名:指针常量,不能++,--

4.3通过指针变量来访问

访问数组:

总结:数组名和指针变量的本质区别:数组名是指针常量

案例1:

printf:右结合

案例2:

void input(int *p,int count)

  1. 冒泡排序

5.1指针的指向没有发生改变

5.2指针指向发生改变

作业:

  1. 用子函数的形式实现字符串的拷贝

  1. 用子函数的形式实现字符串的连接

(都使用指针移动方式)(不使用库函数)

Day7

  1. 指针和二维数组

int a[2][3] ={0};

&a  a  &a[0]  a[0]  &a[0][0]

&a:a当作整个数组,整个数组的地址就是首地址

a:代表首元素地址,a[0]地址

&a[0]:二维数组首元素的地址

a[0]:代表一维数组中首元素的地址,a[0][0]地址

&a[0][0]:第一个一维数组的第一个元素的地址

  1. a,&a[0],&a[0][0]的值是一样的,但是意义不一样

a:int (*)[3]:指向一维数组的指针  a[0]:int *:指向一个整型变量  a[0][0]:int类型

  1. 为什么a不是int **?

a+1移动了一个数组(12byte)如果是int **,加1,移动4byte

  1. a指向a[0],a[0]又是一个一维数组,所以说a指向了一个一维数组

案例:

数组的输入,输出,排序,倒置,求最大值。(封装函数)一维数组

  1. 数组指针与指针数组

2.1数组指针

2.1.1概念

指向数组的指针

2.1.2定义

存储类型 数据类型 (*指针变量名)[元素个数];

存储类型:auto,register,static,extern

数据类型:数组指针指向的数组中元素的数据类型

指针的数据类型:数据类型 (*)[元素个数]

元素个数:指针所指向的数组中元素的个数

int a;//数据类型 int

int *p = NULL;//数据类型 int *

p = &a;//一个指向整型变量的指针

int a[5] = {0};//数据类型 int [5]

int (*p)[5] = NULL;//int (*)[5] 数组指针指向整个数组

p = &a;//a相当于整个数组

2.1.3数组指针与一维数组

注意:数组指针几乎不操作一维数组,更多的操作二维数组,因为指针访问连续的内存空间才有意义,如果是一维数组,p+1就会越界

2.1.4数组指针与二维数组

int a[2][3] = {0};

int (*p)[3] = NULL;(p=&a[0],&a[0]就是二维数组的数组名)

p = a;(&a[0](a就是二维数组首元素地址)

//之前 int a[5];int *p = a;   a,指向首元素的地址,定义了一个指针也指向首元素地址

//现在,首元素为一维数组,a指向首元素地址,首元素一维数组,a就是数组指针,

定义一个数组指针,也指向二维数组的首元素,首元素是一维数组

2.2指针数组

2.2.1概念

元素为指针的数组

2.2.2定义

存储类型 数据类型 *数组名[元素个数];

数据类型 *:数组中元素的数据类型

int  *arr[3];

定义了一个数组,数组名叫arr,有三个元素,每一个都是int *

2.2.3指针数组与二维数组

作业:

查找指定字符在字符串中第一次出现的位置

最后一次出现的位置

封装子函数实现

去掉break,就是最后出现的位置

Day8

  1. const修饰的指针

const:只读

const用来修饰变量,修饰的变量只能读,不能写

案例:const是否在常量区

const修饰的指针:

总结:

  1. const int *p = &a;//const修饰的是值,*p不能被改变
  2. int *const p = &a;//const修饰的是地址,p不能被改变
  3. const int *const p =&a;//const修饰值和地址,*p和p都不能被改

int const *p;

左值右址

const在*左边:*p不能被改变

const在*右边:p不能被改变

  1. main函数传参

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值