C语言基础学习

一丶基本数据类型

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

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

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

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

unsigned:只有正数;

2.字符型家族

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

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

3.整型家族

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

3.浮点型家族

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

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

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

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

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

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

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

输出表:要输出的对象

4.转义字符

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

5.常量

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

5.1 字符常量

‘a’ , ‘b’ , ‘c’

5.2 整型常量

二进制:0110

八进制:066

十进制:99 -2

十六进制:0x234

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

无符号的int型数:66U

长整型:66L

无符号的长整型:66UL

5.3 浮点型常量

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

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

5.4 字符串常量

"hello","word"

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

5.5 标识常量(宏)

#define 宏名 表达式

注意:

        1.宏名一般用大写,小写也可以,因为为了和变量区分,所以用大写;

        2.宏后面没有分号;

宏只是单纯的替换

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

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

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

6.变量

如何定义一个变量?

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

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

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

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

 6.1 局部变量

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

6.2 全局变量

定义在函数体外的变量;

6.3 存储类型

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

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

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

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

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

总结:

        1. 除了static和register修饰的局部变量外,其他的都存在栈区;

        2. 全局变量存储在静态区;

        3. 静态区变量存储在静态区(static修饰的变量就是静态变量)

6.4 初始化

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

1)int a = 10; //初始化

2)  int a;

        a = 10; //赋值

总结:

1)全局变量没有初始化其默认值为0;

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

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

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

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

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

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

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

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

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

6.5 生命周期和作用域

        生命周期:从什么时候开辟空间到什么时候释放空间;

        作用域:

局部变量:

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

作用域:大括号内

static修饰的局部变量:

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

作用域:大括号内

全局变量:

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

作用域:整个程序

static修饰的全局变量:

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

作用域:本文件内

二丶数据类型转换

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

 

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

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

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

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

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

2. 运算符

单算移关与,异或逻条赋

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

2.1 算数运算符

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

注意:%不能用于浮点数

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

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

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

 2.2 关系运算符

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

2.3 逻辑运算符

&&  ||  !

表达式1 && 表达式2

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

表达式1 || 表达式2

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

2.4 sizeof 运算符

 2.5 三目运算符

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

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

2.6 逗号运算符

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

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

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

2.7 位运算符

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

与运算(&)(有0为0);或运算(|)(有1为1);取反;异或

左移:

高位丢弃,低位补0

将1左移俩位

0000 0001--->0000 0100

右移:

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

有符号数:低位丢弃,正数高位补0,负数高位补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 格式控制串,不要加修饰语,如果要加,原样输出;

        2.如果输入"%d%d" 时要给多个变量赋值,在格式控制符之间没有间隔,那在输入的时候,以空格,回车,tab作为一个变量的输入结束;

        3.全部输入结束,必须以回车作为结束符;

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

        解决办法:

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

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

3.3 字符的输入输出

int getchar();

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

char a;

a = getchar();

putchar(参数);

参数:你要输出的ASCLL码

printf右结合,从右到左计算

三丶控制语句

1. 顺序结构

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

2. 选择结构

2.1 单分支选择语句

if(表达式)

{

语句;

}

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

2.2 双分支 if 语句

if(表达式)

{

语句1;

}

else

{

语句2;

}

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

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

 2.3 多分支语句

if(表达式1)

{

语句1;

}

else if(表达式2)

{

语句2;

}

else if(表达式3)

{

语句3;

}

………………

else if(表达式n)

{

语句n;

}

else

{

语句n+1;

}

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

2.4 switch 语句

Switch(表达式

{

case 标号1

语句1;

case 标号2:

语句2;

…………

case 标号n:

语句n;

default:

语句n+1;

}

注意:

        1.表达式不能是float类型;

        2.标号必须为常量;

        3.表达式 = 标号时,执行冒号后面的语句,直到switch,case语句结束,或者碰到break语句结束,所有的标号都不等于表达式是,执行default;

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

 3. 循环结构

重复的去做某一件事

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

3.1 for 循环

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

{

循环体;

}

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

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

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

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

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

案例:

*

***

*****

*******

自己定义行数进行打印;

 3.2 while 语句

while(表达式)

{

循环体;

}

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

3.3 do while 语句

do

{

循环体;

}while(表达式);

总结:while和do while区别

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

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

break,continue

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

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

3.4 死循环

for(;1;)

{

}

while(1)

{

}

3.5 goto 语句

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

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

四丶数组

1. 概念

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

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

打印地址%p

2. 定义

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

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

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

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

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

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

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

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

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

 注意:

        1. 数组名代表整个数组;

        2. 数组名也代表数组首元素的地址;

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

3. 初始化

3.1 部分初始化

在进行部分初始化的时候,未初始化部分的值为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

4. 数组的访问

数组名[下标];

注意:下标是从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[ ] ;//数组的元素个数必须是一个确定的数

打印等腰三角形

 打印菱形

 5. 冒泡排序

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

 

 6. 字符数组

字符数组的本质:其实就是字符串,以’\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’};//字符数组清零

6.1 字符数组的输出函数

%s:字符串

puts(数组名);

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

注意:遇到’\0’结束

6.2 字符串的输入函数

gets(数组名);

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

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

总结:

scanf和gets区别:

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

缓冲区

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

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

注意

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

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

printf和puts的区别:

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

7. 字符串的处理函数

strlen(数组名);

功能:求字符串的长度

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

strlen和sizeof的区别:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

返回值:

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

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

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

比较规则:

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

7. 二维数组

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

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

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

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

7.1 概念

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

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

7.2 定义

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

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

行数:有几个一维数组

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

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

 7.3 数组的初始化

部分初始化:

int a[2][3] = {1,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有俩个一维数组,但每一个一维数组中有几个元素,不能确定

7.4 数组的访问

 

 7.5 二维字符数组

char dtr[30] = “hello”;

scanf(“%s”,dtr);

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

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

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

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

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

 8. 函数

一个独立的功能模块

8.1 为什么要使用函数

使程序变得模块化;提高代码的复用率;

8.2 函数的分类

库函数:printf,scanf,strlen;

引入头文件:#include<stdio.h>;#include<string.h>

调用函数:

strlen(str);

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

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

8.3 自定义函数

函数定义

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

{

函数体;

返回值

}

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

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

函数名:见名知意

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

函数体:具体实现的功能

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

调用函数

函数名(实际参数列表)

注意

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

 函数声明

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

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

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

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

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

9. 指针

9.1 什么是指针

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

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

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

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

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

9.2 什么是地址

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

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

指针:指针就是地址

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

9.3 指针变量

int a;//整型变量

float b;//浮点型变量

char c://字符型变量

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

9.4 指针的定义

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

int *p;

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

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

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

注意:

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

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

9.5 赋值

har *p = &a;

char *p = NULL;

p = &a;

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

思考?

什么是指针

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

地址是什么

字节(内存单元)的编号

什么是指针变量

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

指针变量如何定义

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

int *p;

指针变量赋值后能干什么

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

9.6 空指针

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

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

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

 9.7 野指针

不知道指向哪里的指针

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

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

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

int *p = NULL;

 很危险!!!!!

10. 二级指针

10.1 概念

指针的指针;

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

10.2 定义

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

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

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

总结:

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

int *p;//int *

int **pp;//int **

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

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

int *p;//int

int **pp;//int *

int ***ppp;//int **

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

int a;

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

char b;

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

int*p;

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

四丶指针和数组

1. 指针和一维数组

 1.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.数组首元素地址(指针常量))

1.2 通过指针常量来访问

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

1.3 通过指针变量来访问

 访问数组:

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

 

 2. 冒泡排序

指针的指向没有改变

 指针指向发生改变

3.指针和二维数组

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类型;

2. 为·什么a不是 int**?

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

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

4. 数组指针与指针数组

4.1 数组指针

概念:

指向数组的指针;

定义:

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

存储类型: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相当于整个数组

4.2 数组指针与一维数组

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

4.3 数组指针与二维数组

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就是数组指针,

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

4.4 指针数组

概念:元素为指针的数组;

定义:

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

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

int  *arr[3];

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

 

 4.5 指针数组与二维数组

 

5. 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都不能被改

6. main 函数传参

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值