C语言指针、函数、数组部分

 注意:

1.定义的局部变量都在栈区

一、指针

2.二级指针:

定义方式:  使用两个 ** 进行定义

概念:指针变量的地址-->指针的指针

保存一级指针的地址的指针  被叫做二级指针

常用二级指针类型的函数形参,接收一级指针地址形式的实参,以修改调用者指针的目标,或为其分配资源

注意:对一维数组的数组名取地址,得到的不是二级指针而是数组指针

int* pn =&p -->不是二级指针         

 

 

(2) 常用二级指针类型的函数形参,接收一级指针地址形式的实参,以修改调用者指针的目标,或为其分配资源

调换两个字符串 

 

1.指针基本概念

(1)C语言将地址形象地称为指针。地址(指针)指向变量单元

在编译时,系统会给变量分配内存,在执行语句时,会通过变量名找到对应地地址。

内存以字节为单位,不同类型数据的字节数不同,每个字节编号-->地址,每个字节都有唯一的地址

注意:::多字节数据,将其首字节地址作为该数据的地址

根据地址可以找到相应的数据,地址又称指针   将指针存在一个变量中,这个变量成为指针变量

(变量中存储一个地址-->指针变量)

2.取地址运算符:&   

根据变量  得到变量的内存首地址

3.解引用运算(*) 

根据变量内存首地址取得变量值

*(&a)   通过a的首地址  获取变量值  

注意: 前面有&说明是地址

4.指针变量特点:

1.存储地址 --->   4(32位)/8(64位)字节   跟数据类型无关  X000000...1

2.变量 ---  存储其他地址   自己也有地址 int *p =  &a   *p--->解引用  a的值       p--->指针的值     &p  -->指针变量的地址

5.野指针与空指针:

(1) 野指针:指向不可用内存区域的指针

产生野指针原因:

1. 指针变量没有初始化

2.指针变量所指向的内存已经被释放---malloc

(2)空指针:值为0的指针,可以用宏NULL表示

1.任何情况下,操作空指针的结果都是确定的---》崩溃   

2.空指针比野指针更适合作为指针有效性的判断依据

 

6. 指针计算

(1) 指针支持加减整数、关系比较和相减运算

指针计算的结果由指针的类型决定

指针变量 + n  = 指针变量+n * sizeof(数据类型)

        

二、函数

三、数组

注意:数组名存储的是第一个元素的首地址 但是不能像指针一样 指向新的地方 相当于const修饰

不能进行指针运算 arr++ ; -->error 

数组与指针具有通用性   注意 :不能一个元素都不进行赋值

1.基本概念:

有序的数据集合

每个元素都是同一个数据类型

下标从0开始

C语言不允许对数组的大小进行动态定义

2.一维数组的初始化

(1) 在定义时,对全部数组元素初始化

(2) 在定义时,对部分元素进行初始化  后面没有初始化的元素 会自动赋值 0 如果是字符型 会赋值 '\0'   如果是指针  会初始化为NULL(即空指针)

(3) 如果想全部赋值为0,可以写成

   或者全部元素赋值为 0   但是不能只写长度  一个元素都没有

(4) 确定数组所有元素,但是不写数组长度(系统会根据数组元素个数 给数组定义长度)

 如果数组的长度  与元素个数不同,则必须写上数组长度

注意:不能一个元素都不赋值

3.二维数组:

(1) 基本概念

二维数组常被称为矩阵,二维数组--->行和列的排列形式

(2) 定义二维数组

 在内存中 二维数组是线性存储的:

 

 

4.多维数组

多维数组的特点:第一维的下标变化最慢,最右边的下标变化最快

(1) 多维数组的初始化

1.分行给二维数组赋初始值

 2.所有元素按内存中的排列顺序进行赋值 --->可以不指定第一维的长度(计算机会自动计算),但是第二维的长度必须设置

 3.对部分元素赋值

 

 

 

5.字符数组

C语言中没有字符串类型,也没有字符串变量,字符串是存储在字符型数组中的

注意:字符型数组是以整数形式(ASCII代码)存放的 a--> 65

 1.在字符数组长度之内,未赋值的元素会被初始化为'\0'

2.字符串的结束标志---> '\0'

字符数组在存储字符串常量时,会自动在末尾加'\0';   以下二者等价

 

 注意:以下代码的数组长度是11 而不是10 (末尾有个'\0')

 

如果不以'\0'结尾会出现在内存中乱找

 1.数组指针

概念:指向整个数组的指针  进行指针运算 会跳跃数组长度的字节数

重点:N维数组的数组名是指向N-1维数组的数组指针  相当于数组指针

 

一维数组转二维数组://数组中每个元素都是4个int类型的数组

二维数组转一维数组: //数组中每个元素都是int类型

 

 

 

2.指针数组

概念:每个元素都是指针的数组

int* arr[] = {&a,&b,&c};

 

 3.多维数组与指针

重点:N维数组的数组名是指向N-1维数组的数组指针

 八 、 数组:

1.概念:

数组用来存储多个相同类型数据的内存分配方法

语法:元素数据类型  数组名[元素个数]     =  {初始值};

int a[5] = {1};

特点:多个、相同类型、连续的内存区域

数组名是数组首元素的符号地址,即数组的首地址

数组元素是数组中存储的数据,一般是多个,没有时,有默认值

2.数组使用

printf("%d\n",a[0]);   a[0]  数组的下标从0开始

*&a[0] = 20   解引用  

如果不初始化,必须要指定数组的长度

 

 sizeof(数组名)  计算数组的占用内存大小

sizeof(a[0])  计算数组单个元素的内存大小

数组名是数组首地址====第一个元素的首地址

sizeof(a)/sizeof(a[0])  ====计算数组的长度

 3.动态数组    C99才支持

在定义数组时,通过变量指定数组的长度   非C99会报错

4. 多维数组:

二维数组:int arr[5][10] = {{},{},{}}

二维数组最右边的[]必须有长度

一.二维数组 
    a[i][j] - 表示二维数组某一个存储区的数据 
        i - 分组编号 - 一维数组下标 
            i - 0 ~ 一维数组个数减一 
        j - 组内下标 - 一维数组中的存储区下标 
            j - 0 ~ 存储区个数建议 

 

 

 

 7.指针与函数:

(1) 将函数的形参定义为指针,并且传递实参的地址

(2) 可以从函数中返回指针,但是不要返回指向局部变量的指针,因为该变量的内存在函数返回后会被释放,此类函数又被称为指针函数

可以返回static修饰的静态变量/返回全局变量的指针,因为在函数结束之后,内存不会销毁

 8.指针与数组:

(1) 数组名本身是一个指针,代表数组的首元素地址

(2)数组元素下标访问的本质就是首元素地址做指针计算 然后解引用

(3)数组名是个指针常量,不能通过再次赋值令其指向其他的数据

9.泛型指针 ---void*(无类型指针)

(1)仅存储内存地址,不指定目标类型

(2) 目标类型不确定,不能直接解引用

(3)使用前,必须先进行数据类型转换

(4)泛型指针做指针计算,以1字节位单位

 在ANSI C标准中,不允许对void指针进行算术运算如pvoid++或pvoid+=1等,而在GNU中则允许,因为在缺省情况下,GNU认为void *与char *一样。sizeof( *pvoid )== sizeof( char ).

10.常量指针与指针常量

(1) const型常量:

被const修饰的变量具有只读属性,必须在定义时初始化

(2)常量指针:

当const修饰指针时:

   11.常量指针:指针变量保存的地址可以改变,指向的内存值不能修改

const int*   或    int const*

常量指针常作为函数的输入参数,在避免值赋值传递参数开销的同时,有效防止在函数中以外地修改实参数

     22. 指针常量:

指针变量保存地址不能修改,内存值可以修改

int* const 

数组名就是指针常量

arr++  不可以进行指针计算   *(arr+i) = 5  可以使用解引用进行修改值

        33.常量指针常量:

指针地目标和指针本身都只读:

const int* const   或  int const* const 

11.指针  指向单个字节

(1)进行强转  然后解引用

12.高级指针(重点)

 

四、指针函数与函数指针、指针函数指针(重点)

注意:()的优先级大于 * 

函数的参数最好不要超过四个

1.指针函数(函数名就是函数的首地址)

指针函数 -->  主体是 函数     -->   返回类型是指针

 

2.函数指针

函数指针---> 主体是 指针      --->  指针指向一个函数    相当于调用对应的函数

表达式:int (*f)(int a , int b) ;

 

 用法:可以提高代码复用性:

 3.指针函数指针

--->返回一个指针,但是用的是函数指针调用对应的函数

 

4.回调函数 (函数指针部分内容)--->  函数作为参数 就是回调函数

五、动态分配内存

注意:动态分配了内存  一定要记得free释放内存

(1)分配内存的方式:

1.变量(静态)

2.数组(静态)

3.结构体(静态分配内存)

4.malloc 、call

静态分配内存的特点(缺点):占用的内存空间大小在编辑代码的时候已经定死了

(2)如何实现动态内存空间分配

首先需要包含头文件:#include<stdlib.h>

1.malloc   --- memory  allocation --内存分配

void* malloc (size_t size);    --- 分配size个字节的内存空间 --堆中

堆中的内存特点:

a.直到free函数进行释放  ---注意:一定要记得释放内存空间  free

b.直到程序结束  

返回值void*  --》返回分配内存的首地址

如果分配失败 会返回NULL 

2.free ---的参数就是malloc的返回值

void free(void* ptr);

释放ptr所指向的动态内存        ptr必须是之前malloc/calloc/realloc函数的返回值

释放一块已被释放过的内存,会导致未定义的后果

若ptr取NULL,则不会执行任何操作

所有动态分配的内存都需要释放,否则会导致内存泄漏

 (1) malloc 分配内存

void* malloc (size_t size);    --- 分配size个字节的内存空间 --堆中

 (2)calloc分配内存 ---》 clear allocation   主要对数组进行分配空间

void* calloc(size_t nmemb,size_t  size);    --- 分配nmemb个元素的数组,其中每个元素占size字节

成功返回数组起始值  失败返回NULL  对分配数组的每个元素,用相应类型的0初始化

  (3)realloc分配内存 ---》 reset allocation   调整内存  配合 malloc/calloc使用

void* realloc (void* ptr , size_t size );

将ptr所指向的动态内存大小调整为size字节,原内容不变,对新增部分不做初始化

成功返回数组起始值  失败返回NULL  

ptr 必须是之前malloc/calloc/realloc函数的返回值

realloc 内存分配不够时: 首地址会发生变化

 会从堆中继续寻找,直到找到一块连续16个字节的内存空间,以存储动态分配的内存

这个时候 ---> 首地址  p  就会发生变化

连着前面的 8 字节 + 新分配的 8 字节

realloc 缩减内存  和 free()函数相同  会把不用的内存释放掉

 若ptr取NULL,则等价于 malloc函数 realloc(NULL,1024)  分配内存

若size取 0  realloc(ptr,0)  ---> 等价于 free()释放内存

                        

六、文件操作IO流:

1.fopen:打开一个文件

向文件中写入数据:

从文件中读取数据:

 

2.fclose:关闭一个文件

 

 

七、关键字

1.const

2.enum

3.extern

4.goto

5.register

6.signed、unsigned

7.sizeof

8.static

9.struct

10.typedef

11.union

12.volatile

八、结构体、联合体

1.结构体的基本概念与定义形式

自己设计的类型,用结构体封装一些属性

struct 结构名
{
    成员列表(基本数据类型/指针/其他结构体)    
}
struct Student
{
  char s_id[8];
  char s_name[8];
  char s_sex[4];
  int s_age;
};

2.结构体类型不占用空间,结构体中的变量需要占用空间

3.结构体初始化的几种方式

4.结构体访问成员变量的两种方式

5.结构体大小

6.结构体取别名

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值