C语言督学营 学习笔记 (Day11~12)

文章目录

  • 第11次直播 指针数组与malloc
    • 易错三大例子
    • 指针与一维数组
    • 指针与动态内存申请
    • 栈空间与堆空间的差异
  • 第12次直播 函数与指针
    • 字符指针与字符数组的初始化(了解)
  • 第12次直播 二级指针 结构体
    • 关于全局变量与局部变量
    • 结构体
      • 结构体指针(重要)

第11次直播 指针数组与malloc

易错三大例子

例子一:
C语言督学营 学习笔记 (Day11~12)_第1张图片
上述正确的输出为: 2 2 7

例子二:
C语言督学营 学习笔记 (Day11~12)_第2张图片
上述正确的输出为: 3 2 3

例子三:

C语言督学营 学习笔记 (Day11~12)_第3张图片
上述正确的输出为:2 7 8

指针与一维数组

例子一:
C语言督学营 学习笔记 (Day11~12)_第4张图片
输出结果为: Hello

  • 数组名作为实参传递给子函数时,是弱化为指针的

例子二:
C语言督学营 学习笔记 (Day11~12)_第5张图片

指针与动态内存申请

  • 很多读者在学习C语言的数组后都会觉得数组长度固定很不方便,其实C语言的数组长度固定是因为其定义的整型、浮点型、字符型变量、数组变量都在栈空间中,而栈空间的大小在编译时是确定的。如果使用的空间大小不确定,那么就要使用堆空间

  • 既然都是内存空间,为什么还要分栈空间和堆空间呢?栈是计算机系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈操作、出栈操作都有专门的旨令执行,这就决定了栈的效率比较高;堆则是CC艹函数库提供的数据结构,它的机制很复杂,例如为了分配一块内存,库函数会按照一定的算法(具体的算法请参考关于数据结构、操作系统的书籍)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能由于内存碎片太多),那么就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后返回。显然,堆的效率要比栈低得多栈空间由系统自动管理,而堆空间的申请和释放需要自行管理,所以在具体例子中需要通过free函数释放堆空间。free函数的头文件及格式为

进程地址空间如下

C语言督学营 学习笔记 (Day11~12)_第6张图片

  • 首先进行解析 malloc# include< stdlib. h> 头文件中, 函数的定义为void* malloc(size_ t size) void * 表示定义的为无类型指针,因为是无类型所以才使用强制类型转换,在前面加上 (char *) , malloc 申请空间的单位是字节

易错点: 指针在释放的时候发生偏移

  • 释放空间,p的值必须和最初 malloc 返回的值一致,如果发生偏移则会有下下图的报错
    C语言督学营 学习笔记 (Day11~12)_第7张图片

报错如下:
C语言督学营 学习笔记 (Day11~12)_第8张图片
free(p) ; p=NULL ; 释放操作

栈空间与堆空间的差异

问题引入:

#include  

char* print_stack() {
     
	char c[17] = "i am ok";
	puts(c);
	return c;
}

int main() {
     

	char* p;
	p = print_stack();
	puts(p);
	return 0;
}

C语言督学营 学习笔记 (Day11~12)_第9张图片

  • 原因在在于函数是栈空间,栈空间会随着函数结束而释放。
  • 不能使指针变量指向栈空间,进行操作,因为栈空间会在之后进行释放

解决方法
C语言督学营 学习笔记 (Day11~12)_第10张图片

  • 堆空间不会随子函数的结束而释放,必须自己free

第12次直播 函数与指针

字符指针与字符数组的初始化(了解)

  • 字符指针可以初始化赋值一个字符串,字符数组初始化也可以赋值一个字符串。 char *p="hello"char c[10]="hello"有什么区别呢?

易错分析一:
C语言督学营 学习笔记 (Day11~12)_第11张图片错误分析:

  • p[0] 进行修改,会报如下错误,然而 c[0] 对数组进行修改可以,因为char c [10] = "hello"实际等价于 strcpy(c,"hello") ; 操作的是堆区(可读可写),p[0] 实际操作的是字符串常量区(数据区),该区域只读不能写
    C语言督学营 学习笔记 (Day11~12)_第12张图片
    原因在于:不能对常量区数据进行修改

易错分析二:

C语言督学营 学习笔记 (Day11~12)_第13张图片

第12次直播 二级指针 结构体

  • 二级指针只服务于一级指针的传递与偏移

  • 要想在子函数中改变一个变量的值,必须把该变量的地址传进去

  • 要想在子函数中改变一个指针变量的值,必须把该指针变量的地址传进去

#include  
#include 

void change(int** p, int* pj) {
     
	int i = 5;
	*p = pj;
}

int main() {
     

	int i = 10;
	int j = 5;
	int* pi;
	int* pj;
	pi = &i;
	pj = &j;

	printf("i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);
	change(&pi, pj);
	printf("after change i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);
	system("pause");
	return 0;
}

C语言督学营 学习笔记 (Day11~12)_第14张图片

C语言督学营 学习笔记 (Day11~12)_第15张图片
微软的C动态库 后缀为 dll

注意区分函数的声明与函数的定义:

链接错误 main.obj 在这里插入图片描述

关于全局变量与局部变量

C语言督学营 学习笔记 (Day11~12)_第16张图片
输出结果为: 10 5

#include  
// 定义全局变量
int i = 10;
void print(int a) {
     
	printf("print i =%d\n", i);
}

int main() {
     
	printf("main i =%d\n", i);
	i = 5;    //局部变量
	print(i);
	return 0;
}

输出结果为 10 10

  • 这是因为全局变量存储于数据段中(全局变量定义存储于数据段)

C语言督学营 学习笔记 (Day11~12)_第17张图片

结构体

  • 结构体所占的空间,并不是简单的里面所包含的数据类型容量简单相加,因为存在对齐策略,会比预期要大

结构体指针(重要)

易错分析一:
C语言督学营 学习笔记 (Day11~12)_第18张图片

  • 正确写法为: (*p).num ,(*p).name,(*p).sex

  • . 的优先级比 *

  • 优化写法: p->num p->name p->sex

关于结构体的偏移:

C语言督学营 学习笔记 (Day11~12)_第19张图片

你可能感兴趣的:(学习随笔,c语言,开发语言,后端)