2.第一个C程序之数组排序
#include<stdlib.h>
#include<string.h>
//排序
void main()
{
int i = 0,j = 0;
int tmp = 0;
int a[] = { 33, 55, 22, 66, 44, 99, 11 };
printf("排序前\n");
for (i = 0; i < 7; i++){
printf("%d", a[i]);
}
//排序
//外层循环 当i=0的时候,让j从1到n进行变化
//外层循环 当i=1的时候,让j从2到n进行变化
//外层循环 当i=2的时候,让j从3到n进行变化
//外层循环 当i=3的时候,让j从4到n进行变化...
//结论:按照一个i变量不变,让另外一个变量j进行变化;下一轮,依次进行
for (i = 0; i< 7; i++){
for (j = i+1; j < 7; j++){
if (a[i]>a[j]){//如果a[i]>a[j],则交换
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
printf("排序后\n");
for (i = 0; i < 7; i++){
printf("%d", a[i]);
}
printf("hello...\n");
system("pause");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
代码优化
#include<stdlib.h>
#include<string.h>
//void printArray(int a[],int num)
void printArray(int *a,int num)
{
int i = 0;
for (i = 0; i < num; i++){
printf("%d", a[i]);
}
}
//void sortArray(int a[],int num)
void sortArray(int *a,int num)
{
//排序
int i, j, tmp;
for (i = 0; i< num; i++){
for (j = i + 1; j < num; j++){
if (a[i]>a[j]){//如果a[i]>a[j],则交换
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
}
//数组做函数参数的退回问题 退回为一个指针
//结论:把数组的内存地址和数组的有效长度传给被调用函数
//排序
void main()
{
int i = 0, j = 0;
int tmp = 0;
int num = 0;
int a[] = { 33, 55, 22, 66, 44, 99, 11 };
num = sizeof(a) / sizeof(a[0]);
printf("num:%d", num);
printf("排序前\n");
printArray(a,num);
//排序
sortArray(a, num);
printf("排序后\n");
printArray(a, num);
printf("hello...\n");
system("pause");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
结论
- 数组做函数参数的退回问题 退回为一个指针
- 1.把数组的内存地址和数组的有效长度传给被调用函数
- 2.实参的a和形参的a的数据类型本质不一样
- 3.形参中的数组,编译器会把它当成指针处理 这是c语言特色
- 4.形参写在函数上,和写在函数内是一样的,只不过是具有对外的属性而已。
运行结果
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/452c0e91b363b2c552eed04c9a81c7b5.png)
3.数据类型本质分析
(1)数据类型概念
- “类型”是对数据的抽象
- 类型相同的数据有相同的表示形式、存储格式以及相关的操作
- 程序中使用的所有数据都必定属于某一种数据类型
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/637afdd53d5dc4e90f228b55bb69160d.png)
(2)求数据类型大小
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
void main()
{
int a; //告诉c编译器分配4个字节的内存
int b[10] ; //告诉c编译器分配40个自己内存
printf("b:%d, b+1:%d, &b:%d, &b+1:%d \n", b, b+1, &b, &b+1);
printf("sizeof(b):%d \n", sizeof(b)); //40
printf("sizeof(a):%d \n ", sizeof(a)); //4
//sizeof是操作符,不是函数;sizeof测量的实体大小为编译期间就已确定
// b+1 &b+1 结果不一样 //b &b所代表的数据类型不一样
//b 代表的数组首元素的地址
//&b代表的是整个数组的地址
printf("hello....\n");
system("pause");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/ee4feae7e1b14e125623a7c6b937a3b0.png)
(2)数据类型别名
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
//复杂类型别名
struct Teacher
{
char name[64];
int age;
}Teacher;
typedef struct Teacher2
{
char name[64];
int age;
}Teacher2;
//简单类型别名 typedef
typedef int u32;
void main()
{
int a; //告诉c编译器分配4个字节的内存
int b[10] ; //告诉c编译器分配40个自己内存
struct Teacher t1;//前要加struct
Teacher2 t2; //不需要加struct
t1.age = 31;
printf("u32:%d \n", sizeof(u32));
printf("hello....\n");
system("pause");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/38a5c465dc7620af804b0c9a3fce45f9.png)
(3)数据类型的封装
{
char *p2 = NULL;
void *p1 = NULL;
p2 = (char *)malloc(100);
p1 = &p2;
}
{
//void a;//编译器不知道如何分配内存
}
4.变量的本质
(1)变量的概念
- 概念:既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量。
- 变量定义形式: 类型 标识符, 标识符, … , 标识符 ;
- 例如:
- int x ;
- int wordCut , Radius , Height ;
- double FlightTime , Mileage , Speed ;
(2)变量的本质
- 1、程序通过变量来申请和命名内存空间 int a = 0
- 2、通过变量名访问内存空间
- (一段连续)内存空间的别名(是一个门牌号)
- 3、修改变量有几种方法?
- 1) 直接
- 2) 间接。内存有地址编号,拿到地址编号也可以修改内存;于是横空出世了!(编程案例)
- 3) 内存空间可以再取给别名吗?
- 4) 数据类型和变量的关系
- 通过数据类型定义变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main()
{
int a ;
int b;
a = 10; //1 直接赋值 //cpu里面执行
printf("&a: %d\n", &a);
//2间接赋值 直接通过内存
*((int*)&a) = 200;
printf("a: %d\n", a);
printf("hello...\n");
system("pause");
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/58be42b0d363282e64b27c4150c03b88.png)
5.程序的内存四区模型
(1)内存四区的建立流程
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/0cefd5956d3ef45bb9a605dcb38cfc76.png)
- 流程说明
- 1、操作系统把物理硬盘代码load到内存
- 2、操作系统把c代码分成四个区
- 3、操作系统找到main函数入口执行
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/9765956d2212199b7ca830fd41a893f2.png)
(2)静态存储区案例理解
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * getStr1()
{
char *p1 = "abcdefg";
//char *p1 = "abcdefg2";
return p1;
}
char *getStr2()
{
char *p2 = "abcdefg2";
return p2;
}
void main()
{
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
//打印p1 p2 所指向内存空间的数据
printf("p1:%s , p2:%s \n", p1, p2);
//打印p1 p2 的值
printf("p1:%d , p2:%d \n", p1, p2);
printf("hello...\n");
system("pause");
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/9ebbf61448c687d2ebb77f9f25e817a3.png)
- 把char *p1 = “abcdefg”;改为char *p1 = “abcdefg2”;发现指针所指地址一样。
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/adb6e1c56922170d210fa4d53c1bf153.png)
静态存储器内存四区图
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/4ff6d1c84f70f74a16608d43022e9fb4.png)
(3)堆栈案例理解
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//堆
char *getMem(int num)
{
char *p1 = NULL;
p1 = (char *)malloc(sizeof(char) * num);
if (p1 == NULL)
{
return NULL;
}
return p1;
}
//栈
//注意 return不是把内存块 64个字节,给return出来,而是把内存块的首地址(内存的标号0xaa11) ,返回给 tmp
// 理解指针的关键,是内存. 没有内存哪里的指针
//
char *getMem2()
{
char buf[64]; //临时变量 栈区存放
strcpy(buf, "123456789");
//printf("buf:%s\n", buf);
return buf;
}
void main()
{
char *tmp = NULL;
tmp = getMem(10);
if (tmp == NULL)
{
return ;
}
strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据
//tmp = getMem2();
tmp = 0xaa11;
printf("hello..tmp:%s.\n", tmp);
system("pause");
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
堆栈图解
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/cbc44604a0e893cf89469cf11a21a68d.png)
(4)指针
指针是一种数据类型
- 1) 指针也是一种变量,占有内存空间,用来保存内存地址
- 2)*p操作内存
- 在指针声明时,*号表示所声明的变量为指针
- 在指针使用时,*号表示 操作 指针所指向的内存空间中的值
- *p相当于通过地址(p变量的值)找到一块内存;然后操作内存
- *p放在等号的左边赋值(给内存赋值)
- *p放在等号的右边取值(从内存获取值)
- 3)指针变量和它指向的内存块是两个不同的概念
- //含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++
- //含义2 给*p赋值*p=’a’; 不会改变指针变量的值,只会改变所指的内存块的值
- //含义3 =左边*p 表示 给内存赋值, =右边*p 表示取值 含义不同切结!
- //含义4 =左边char *p
- //含义5 保证所指的内存块能修改
- 4)指针是一种数据类型,是指它指向的内存空间的数据类型
- 含义1:指针步长(p++),根据所致内存空间的数据类型来确定
- p++=->(unsigned char )p+sizeof(a);
- 结论:指针的步长,根据所指内存空间类型来定。
- 注意:
- 不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。
测试
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void main()
{
int a = 10;
char *p1 = 100; //分配4个字节的内存
char ****p2 = 100;
int *p3 = NULL;
p3 = &a;
*p3 = 20; //间接的修改a的值
//*就像一把钥匙 通过一个地址(&a),去修改a变量的标示的内存空间
{
int c = 0;
c = *p3; //c=20
//*p放在=号左边 写内存
//*p放=号的右边 读内存
printf("c:%d \n", c);
}
{
char *p4 = NULL;
p4 = (char *)malloc(100);
p4 = (char *)malloc(200); //0xcc11
}
printf("a:%d , p1:%d , p2: %d", sizeof(a), sizeof(p1), sizeof(p2));
printf("hello...\n");
system("pause");
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
运行结果
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/f5e620483ebf520b3b19ccc3db269203.png)
保证所指的内存块能修改
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char *getStr()
{
char *tmp = NULL;
tmp = "abcdefgf";
return tmp;
}
void main()
{
char *p = getStr();
printf("p:%s \n", p);
*(p+2) = 'r'; //经常出现的错误 保证指针所指向的内存空间 可以被修改
system("pause");
return ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
运行结果
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/b46c6eb70e19ed5bfb591d842586c028.png)
图解
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/25ffd4f14df6750dd1eb2ee0b92775c4.png)