C 提高1 内存四区 变量本质 栈开口方向 指针铁律1

C 提高第一天复习

内存四区,变量常量的本质,函数调用模型,栈开口方向,指针铁律1,指针是一种数据类型

C 提高学员标准:写一个标准的冒泡排序

选择法或者冒泡法排序

在一个函数内排序

通过函数调用的方式排序

数组做函数参数的技术盲点和推演

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	int i = 0;
	int j = 0;
	int tmp = 0;
	int a[] = {3,66,54,32,11,22,99,2334,32};

	for (i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d ",a[i]);
	}
	printf("\n", a[i]);

	for (i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		for (j = i+1; j < sizeof(a) / sizeof(int); j++)
		{
			if (a[i] > a[j])
			{
				tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
	}

	for (i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n", a[i]);

	system("pause");
}

编译运行:
3 66 54 32 11 22 99 2334 32
3 11 22 32 32 54 66 99 2334
请按任意键继续. . .

冒泡程序,优化输出与排序 与 函数的数组参数问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void printfArray(int array[], int len)
{
	int i;
	for (i = 0; i < len; i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n", array[i]);
}

//数组做函数的参数的退回问题,退回为一个指针
//结论:把数组内存的首地址和有效长度传给被调用的函数
//本质:函数中的数组形参,编译器会把它当成指针处理
void sortArray(int array[], int len)
{
	int i, j, tmp;
	for (i = 0; i <len; i++)
	{
		for (j = i + 1; j < len; j++)
		{
			if (array[i] > array[j])
			{
				tmp = array[i];
				array[i] = array[j];
				array[j] = tmp;
			}
		}
	}
}

int main()
{

	int a[] = {3,66,54,32,11,22,99,2334,32};
	int len = sizeof(a) / sizeof(int);

	printfArray(a, len);
	sortArray(a,len);
	printfArray(a, len);

	system("pause");
}

编译运行:
3 66 54 32 11 22 99 2334 32
3 11 22 32 32 54 66 99 2334
请按任意键继续. . .

数据类型概念:

“类型”是对数据的抽象

类型相同的数据有相同的表示形式、存储格式以及相关的操作

程序中使用的所有数据都必定属于某一种数据类型

基本数据类型:typedef 数组与地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct teacher1{
	char name[64];
	int age;
}Teacher1;

//使用typedef,以后定义就是这样了 Teacher2 t2;
typedef struct teacher2{
	char name[64];
	int age;
}Teacher2;

int main()
{

	int b[10];
	printf("b:%d , b+1:%d \n", b, b + 1);
	printf("&b:%d, &b+1:%d \n", &b, &b + 1);
	// b 代表数组首元素的地址
	// &b代表整个数组的地址
	// &b+1代表跨过整个数组地址

	struct teacher1 t1;
	Teacher1.age = 0;
	Teacher2 t2;

	typedef int u32;
	printf("u32 =%d \n",sizeof(u32));

	system("pause");
}
编译运行:
b:3603504 , b+1:3603508
&b:3603504, &b+1:3603544
u32 =4
请按任意键继续. . .

数据类型的本质思考

思考数据类型和内存有关系吗?

C/C++为什么会引入数据类型?

数据类型的本质 

数据类型可理解为创建变量的模具(模子);是固定内存大小的别名。

数据类型的作用:编译器预算对象(变量)分配的内存空间大小

程序举例,如何求数据类型的大小  sizeof(int *)

请问:数据类型可以有别名吗?数据类型可以自定义吗?(typedef)

数据类型大小C程序:

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int a = 10;
	int b[10] ;
	printf("int a:%d \n", sizeof(a));
	printf("int a:%d \n", sizeof(int *));
	printf("int b:%d \n", sizeof(b));
	printf("int b:%d \n", sizeof(b[0]));
	printf("int b:%d \n", sizeof(*b));
	printf("hello.....\n");
	return 0;
} 
编译运行:
C:\Users\chunli>gcc main.c & a
int a:4
int a:4
int b:40
int b:4
int b:4
hello.....

常量的探讨:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * getstr1()
{
	char *p = "1234";
	return p;
}

char * getstr2()
{
	char *p = "5678";
	return p;
}

int main()
{
	char *p1 = NULL;
	char *p2 = NULL;
	p1 = getstr1();
	p2 = getstr2();
	printf("%s,%s \n", p1, p2);
	printf("%d,%d \n", p1, p2);
	system("pause");
}

编译运行:
1234,5678
14309464,14309644
请按任意键继续. . .

改一改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * getstr1()
{
	char *p = "1234";
	return p;
}

char * getstr2()
{
	char *p = "1234";
	return p;
}

int main()
{
	char *p1 = NULL;
	char *p2 = NULL;
	p1 = getstr1();
	p2 = getstr2();
	printf("%s,%s \n", p1, p2);
	printf("%d,%d \n", p1, p2);
	system("pause");
}

编译运行:
1234,1234
2054232,2054232
请按任意键继续. .

堆栈变量,函数返回一个被析构的内存空间块

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//堆
char * getmem(int size)
{
	char *p = NULL;
	p = (char *)malloc(size);
	return p;
}

//栈
//return 不是把内存块返回出来,而是把首地址返回了
char * getmem2()
{
	char p[20];
	strcpy(p, "haha2 \n");
	return p;	//【危险!】p即将释放,但是地址返回去来了。
}

int main()
{
	char  *p = NULL;
	p = getmem(20);
	strcpy(p, "haha1 \n");
	printf("%s",p);
	free(p);
	p = NULL;

	p = getmem2();//返回了一个被析构的数据块
	printf("%s", p);//不应该这么做!

	system("pause");
}

编译运行:
haha1
haha2
请按任意键继续. . .

栈的开口方向:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

	int a;
	int b;
	printf("&a = %d \n", &a);
	printf("&b = %d \n", &b);
	system("pause");
}
编译运行:
C:\Users\chunli>gcc -o main.exe main.c & main
&a = 2686652
&b = 2686648
请按任意键继续. . .

数组基地址永远都是在下面:



指针铁律1:指针是一种数据类型

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//*p 在等号的左边 修改内存
//*p 在等号的右边 读取内存

char * getstr()
{
	int *tmp = "hello \n";//	常量区
	return tmp;
}

int main()
{

	int a;
	char *p1 = 100;//分配4个字节
	p1 = &a;
	*p1 = 20;	//*就像一把钥匙,找到这个地址,并修改它
	printf("%d  \n", sizeof(p1));
	printf("%d  \n", *p1);

	int b = 0;
	b = *p1;
	printf("%d  \n", b);

	char p2 = (char *)malloc(100);
	char p3 = (char *)malloc(100);

	char *p4 = getstr();
//	*(p4 + 2) = ‘K‘;  因为返回的是常量	,不能修改
	printf("%s",p4);
	system("pause");
}

指针经典话语:

1,指针指向谁,就把谁的地址赋给指针;

2,指针变量 和 它指向的内存空间变量是两个不同的概念

3,理解指针的关键是内存,没有内存哪里来的指针

变量的本质是一个固定大小的数据块,变量名就是数据块的编号

内存的使用范围:

main函数可以在栈分配内存/堆分配内存/全局分配内存,可以给子函数使用

子函数在栈分配的内存不能给主函数使用,但是堆内存与全局变量是可以给main使用

编译器会为每个程序分配一个内存4区,主函数与子函数公用这个内存4区

建立正确程序运行内存布局图是学好C的关键!

指针铁律1:指针是一种数据类型

1)指针也是一种变量,占有内存空间,用来保存内存地址

2)*p 操作内存;

3)*就像一把钥匙,通过一个地址(&a),去修改a变量的标示的内存空间

4)不断的给指针赋值,相当于不停的改变指针的指向。

5) 指针是一种数据类型,是指它指向内存空间的数据类型


时间: 2024-12-30 03:05:26

C 提高1 内存四区 变量本质 栈开口方向 指针铁律1的相关文章

C语言的内存四区模型和函数调用模型

首先是操作系统将代码程序加载到内存中 然后将内存分为4个区 栈区,程序的局部变量区,函数传递的参数,由编译器自动进行内存资源的释放. 堆区,动态内存申请,如果不手动释放内存,则这块内存不会进行析构. 全局区,静态区,常量区(字符串存放的位置),程序结束后,有操作系统释放 代码区,存放函数体的二进制代码. 最后,操作系统找到main函数的入口,就开始代码的执行. 一般内存四区中的栈的开口方向是向下的.为什么要这样设计呢,因为设计栈的方向向下,可以给应用程序设定栈的大小,这样就可以避免栈溢出. 不管

C++ 数据类型提高+内存四区

# 这一章节全部是C语言的内容# 数据类型提高**注意**1.数组作为形参会退化为指针(验证,传参后用sizeof进行打印,可以看出打印出数组的字节为一字节)2.形参在函数上和函数内是一样的,只不过对外开放 # 内存四区 ##### 数组和数组元素指针```void main(){ int a;//告诉编译器分配4个字节内存 int b[10];//告诉编译器自己分配40个内存 printf("b:%d,b+1:%d,&b:%d,&b+1:%d",b,b+1,&

深入理解数据类型、变量类型属性、内存四区和指针

数据类型可理解为创建变量的模具(模子):是固定内存大小的别名. 数据类型的作用:编译器预算对象(变量)分配的内存空间大小. 既能读又能写的内存对象,称为变量:若一旦初始化后不能修改的对象则称为常量. 变量本质:(一段连续)内存空间的别名. 内存四区 栈区(stack):也叫临时区,由编译器自动分配释放,存放函数的参数值,局部变量的值等. 堆区(heap):一般由程序员分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收. 全局区(静态区)(static):全局变量和静态变

面向过程—面向对象(C++的封装,this)_内存四区_变量生命周期

1.面向对象主要涉及  构造函数.析构函数.虚函数.继承.多态等. 2.对各种支持 的底层实现机制 c语言中,数据 和 处理数据的操作(函数) 是分开来声明,即语言本身并没有支持 “数据和函数”的关联性. 在C++中,通过抽象数据类型(abstract data type, ADT),在类中定义数据和函数,来实现数据和函数直接的绑定. C++成员数据:static.nonstatic C++成员函数:static.nonstatic.virtual C++中的类class从面向对象理论出发,将变

C语言提高之技术模型层次、学习标准、特点、内存四区、函数调用模型

1.C语言技术模型分层: 其中,接口的封装和设计尤为重要! 2.着重需要培养的能力 (1)接口的封装和设计(业务模型的抽象.功能抽象和封装) ---重中之重! a.接口api的使用能力: b.接口api的查找能力(快速上手): c.接口api的实现能力: // SOCKETCLIENT_H,一个简单信息系统的封装接口 #ifndef _SOCKETCLIENT_H #endif _SOCKETCLIENT_H #ifdef __cplusplus extern "C" { #endif

C语言 内存四区与函数调用模型

C语言提高笔记 标签(空格分隔): C++ C语言 day1 数组做函数参数的退回问题 数组做函数参数会退回为一个指针, 正确做法:把数组的内存首地址和数组的有效长度传给被调用函数. 实参的a 和 形参的a 的数据类型本质不一样, 形参中的数组,编译器会把它当成指针处理 只会分配四个字节. 形参写在函数上,和写在函数内是一样的,只不过是具有对外的属性而已. 数据类型本质分析 数据类型可理解为创建变量的模具(模子):是固定内存大小的别名: 数据类型的作用:编译器预算对象(变量)分配的内存空间大小

内存四区模型与指针

数据类型的封装 1.void的字面意思是"无类型",void 则为"无类型指针",void 可以指向任何类型的数据. 2.用法1:数据类型的封装 int InitHardEnv(void **handle); 典型的如内存操作函数memcpy和memset的函数原型分别为 void * memcpy(void *dest, const void *src, size_t len); void * memset ( void * buffer, int c, size

c语言内存四区模型

c语言内存四区模型:代码区,全局区(常量区),栈区,堆区 在全局区(常量区),两个字符串完全一样c++编译器只会定义一份 char * getBuf() { char buf[20]; strcpy(buf, "abcde"); return buf; } abcdX?  有乱码! 确实把内存地址返回了,但不能用 被调函数调用完毕,在临时区分配的内存统统消失 char *buf= (char *)malloc(sizeof(char)*20); 手动malloc申请一份内存,由程序员手

内存四区中全局区见解

今天我把自己对于内存四区中全局区见解写出来,希望可以帮到大家,同时也希望指出我的不正! 可能有些人不解,我不是想通过,内存四区引入指针么?怎么上来就用指针? 这一点我要说明一下,我用指针是为了更清楚的表明我对于内存四区的见解,是想让大家明白,内存四区是什么?栈区,堆区和全局区之间的关系! 正如同在栈区和在堆区分配的内存空间是不同的!指针里存的是地址,地址是哪里的地址?是内存上的地址!而如果我们分不清我们的指针到底指向的是哪一个区域的地址,调用起来岂不是很麻烦.比如我们在子函数上分配了一个变量(栈