【 数据存储模式与验证方法 & 字符串系列函数 & 指针数组& 数组指针 &冒泡排序】
文章目录
前言
介绍数据存储模式及验证方法(使用指针强转)、大小端问题、指针数组与数组指针、冒泡排序、字符串操作函数、获取随机数、交换函数等操作
一、数据存储模式与验证方法
- 内存划分基本单位 :字节
1. windows数据存储模式
小端存储 : 低地址 向 高地址存储
(低地址位置 存放 低位数据)
低地址
低位
0x78 0x56 0x34 0x12
2. LInux操作系统
一般是大端存储 : 高地址 向 低地址存储
(高地址位置 存放 低位数据)
高地址
低位
0x12 0x34 0x56 0x78
3. 验证方式
(1)指针验证
(2)联合体union验证
#include<stdio.h>
int main()
{
//指针强转
int val = 0x12345678;
char* pc = (char*)&val;
if (*pc == 0x78)
printf("小端存储模式\n");
else
printf("大端存储模式\n");
}
二、指针数组 数组指针 交换数值函数
(1) []的优先级 > 指针 *
(2)指针数组 与数组指针
(3)字符串类型数组
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
//数据下标的封装 交换数据
void Swap_one(int* arr, int j, int i) //将交换的下标传入 java无指针 常用此方法交换数据
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void Swap_str(const char** arr,const char** b)
{
const char *temp = *arr;
*arr = *b;
*b = temp;
}
void Swap_two(const char* arr[], int i, int j)
{
const char* temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void Sort_Str(const char** arr,int len)
{
assert(*arr != NULL); //断言 参数安全的校验 ----debug版本调试版本有效 release版本无效
int i = 0, j = 0;
const char* temp;
bool flag;
for (i = 1; i < len-1; i++)
{
flag = false;//一趟
for (j = 0; j <len- i - 1; j++)
{
if (strcmp(arr[j],arr[j+1])>0) //字符串的比较
{
/*temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;*/
//Swap_str(&arr[j], &arr[j + 1]);
Swap_str(arr + j, arr + j + 1);
//Swap_two(arr, j, j + 1);
flag = true;
}
}
if (!flag) //flag==false !逻辑非
break;
}
for (int i = 0; i < len; i++)
{
printf("%s ",*arr);
arr++;
}
}
int main()
{
// []的优先级 > 指针*
//【指针数组】
int brr[3]; //[int][int][int]
int* pb = brr; //&brr[0]
//pb+1 --> + 1*sizeof(int)
int *arr[3]; //[int*][int*][int*]
//指针数组
int** pa = arr; //&arr[0]
///pa+1能力 +sizeof(int*)
//【数组指针】
int(*pc)[3] = &brr; //区别于&brr[0]
//pc+1 能力 +sizeof(int[3]) 12字节
//【字符串类型数组】
//定义字符串类型的数组:"abc","hello","zs";
const char* pstr = "hello";
const char* crr[] = { "hello","abc","zs" };
int length = sizeof(crr) / sizeof(crr[0]);
Sort_Str(crr,length);
/*printf("%s", *crr);
printf("\n%s", *(crr + 1));*/
}
三、 冒泡排序
(1)整型数组为例:交换:前者>后者 (升序)
悬挂指针(野指针):int* p;
不能对野指针进行指针赋值操作 *p=1//err
空指针: int *p=NULL; //#deifne NULL 0
不能对野指针 和空指针 进行解引用
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
void Swap(int* arr, int* b)
{
int temp = *arr;
*arr = *b;
*b = temp;
}
void BubbleSort(int* arr, size_t len)
{
assert(arr != NULL); //断言 参数安全的校验 ----debug版本调试版本有效 release版本无效
int i = 0, j = 0, temp = 0;
bool flag;
for (i = 0; i < len - 1; i++)
{
flag = false;//一趟
for (j = 0; j < len - i - 1; j++)
{
if (arr[j ] > arr[j+1])
{
flag = true;
Swap(arr + j, arr + j + 1);
//Swap(&arr[j],&arr[j+1]);
}
}
if (!flag) //flag==false !逻辑非
break;
}
}
void Printf(int *arr,size_t len)
{
printf("\n打印: ");
for (size_t i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
}
int main()
{
//数组冒泡排序(升序) 时间复杂度:O(n^2) 空间复杂度O(1) //4与4是否交换 导致的数据的稳定性
int arr[] = { 1,4,5,3,6,4,7,8,10 };
int brr[] = { 1,3,5,7,8,9};
size_t len = sizeof(arr) / sizeof(arr[0]);
size_t len2 = sizeof(brr) / sizeof(brr[0]);
BubbleSort(arr, len); //考虑传参arr是空地址的情况
BubbleSort(brr, len2); //优化问题 传入数组已经是升序数组
Printf(arr, len);
Printf(brr, len2);
}
四、字符串操作函数 及 获取随机数:
1. str系统函数:
strlen 求字符串长度 (int Str_Length(char* arr))
strcmp 字符串比较 (void Str_Copy(char* arr, char* brr))
strcpy 字符串拷贝 (int Str_cmp(char* arr, char* brr))
strcat 字符串连接 (void Str_Cat(char* arr, char* brr))
2. mem内存系列函数:
memset 内存初始化逐字节
memcpy 内存拷贝
memmove 内存移动
3. 其他相关函数:
atoi() 字符串类型 转 整型
itoa() 整型 转 字符串
strtok()—>分割 头文件 string.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
//打印数组
void Show(int arr[], int len) //int *arr -->地址别名 数组传参 退化成指针,地址传递比值传递节省存储空间;
{
//int len = sizeof(arr) / sizeof(arr[0]); //arr退化成指针,数组不在同一作用域,求出的len值为1(4/4=1);
for (int i = 0; i < len; i++)
{
printf("%d\t ", arr[i]);
}
}
//打印字符串
void Show(char* arr, int len) //int *arr -->地址别名 数组传参 退化成指针,地址传递比值传递节省存储空间;
{
for (int i = 0; i < len; i++)
{
printf("%c ", arr[i]);
}
}
//统计数据内奇数的个数
size_t Data_Number(int* arr, int len)
{
size_t count = 0;
for (int i = 0; i < len; i++)
{ //奇数的二进制末端为1 偶数的二进制末端为0
if (arr[i] % 2 != 0) //若用二进制来判断 (arr[i]&0x1)==1 (奇数) 按位与&
{
count++;
}
}
return count;
}
//统计字符串长度
int Str_Length(char* arr)
{
int count = 0, i = 0;
while (arr[i] != '\0')
{
count++;
i++;
}
return count;
}
//拷贝字符串
void Str_Copy(char* arr, char* brr)
{
int i = 0;
while (brr[i] != '\0')
{
arr[i] = brr[i];
i++;
}
/*int i = 0; //第二种写法
while (arr[i] = brr[i])
{
i++;
}*/
/*int i = 0, j = 0; //第三种写法
while (arr[i++] = brr[j++]); '\0'==0 */
arr[i] = '\0';
}
//字符串连接函数
void Str_Cat(char* arr, char* brr)
{
int i = 0, j = 0;
while (arr[i] != '\0') //法一
i++;
while (arr[i] = brr[j])
{
i++;
j++;
}
arr[i] = '\0';
/*while (brr[j] != '\0') //法二
{
arr[i] = brr[j];
i++;
j++;
}*/
/*while (arr[i++] = brr[j++]);*/ //法三
//int i = 0, j = 0; //法四
//size_t len = strlen(arr);
//i += len; //i定位到arr数组有效数据的后方\0的位置
//while (arr[i] = brr[j])
//{
// i++;
// j++;
//}
}
//字符串比较函数
int Str_cmp(char* arr, char* brr)
{
int i = 0;
while (arr[i] == brr[i])
{
if (arr[i] == '\0')
return 0;
i++;
}
return arr[i] < brr[i] ? -1 : 1;
/*while (('\0' != arr[i]) || ('\0' != brr[i]))
{
if (arr[i] > brr[i]) {
return 1;
}
else if (arr[i] < brr[i]) {
return -1;
}
i++;
}
return 0;*/
}
int main()
{
//【获取随机值】
int drr[10];
srand(10);//随机种子,10定值 输出也为随机定值 运行将10每次都改变 可获得随机数
time_t t; //time_t :定义的typedef long long time_t ; 实际上就是long long类型,所以我们可以理解为创建一个64位的时间变量nowtime。
time(&t);
srand((unsigned int)t);
int num=rand()%100; //rand()产生随机数
printf("\n随机值: %d \n", num); //伪随机值
//【atoi函数】 字符串 转 整型
int val = atoi("-100");
printf( "atoi函数: %d \n", val);
//【_itoa函数】整型 转 字符串
// 100 8 "144"
// 100 4 "64"
char buff[128];
_itoa(-1, buff, 2);
printf("_itoa函数: %s\n", buff);
//【strtok函数】
char prr[] = "2023-11-07 20:53:20";
/*char* res = strtok(prr, "-");
printf("strtok函数 : %s\n", res);
char* res2= strtok(NULL, "-"); ///给NULL 以上一次分割位置 继续以“-”分割
printf("strtok函数 : %s\n", res2);
strtok(NULL, "-");*/
strtok(prr, " ");
//strtok(NULL, " "); //得到“20:53:20”
char * res4=strtok(NULL, ":");
printf("strtok函数 : %s\n", res4); //得到20
size_t lenone = strlen("hello"); //5 //size_t是sizeof关键字运算结果的类型。(注:sizeof是关键字,并非运算符)
int arr[] = { 1,2,3,4,5 };
int len = sizeof(arr) / sizeof(arr[0]); //只有在同一作用域 才能求数组长度
Show(arr, len); //函数名即函数入口地址
size_t count= Data_Number(arr, len);
printf("\n数组奇数个数:%d\n\n", count);
char brr[] = "hello";
int n=Str_Length(brr);
Show(brr, n);
printf("\n字符串数组长度:%d\n", n);
char a[20];
memset(a, 0, sizeof(char) * 20); //等价于char a[10]={0};
strcpy(a, "hello");
printf("\n原数组a: %s\n", a);
char b[] = "world";
Str_Copy(a, b);
printf("\n拷贝后数组a: %s\n", a);
char c[] = "student";
Str_Cat(a, c);
printf("\n连接后数组a: %s\n", a);
int ab = Str_cmp(a,b);
printf("\n两数组: %d\n", ab);
}
五、补充知识点
-
指针大小 x86 4字节 ;x64 8字节
-
地址总线 =》找内存地址
-
win32 win64 win128(范围逐渐增大)
-
x86–win32 地址总线 2^32寻址能力 32位操作系统
-
(内存) 2^32字节=4GB 0X0000 0000 0Xffff ffff
-
x64–win64 8字节表示寻址
-
Linux win32系统 0X0000 0000
-
【3G 内部】
128M :非法访问区(禁止访问区) 代码区(存汇编语言) :高级语言-->汇编语言-->机器码(01组合) 数据区域.data :存全局变量 静态局部变量 静态全局变量 ( static )字符串常量 (eg: const char*="hello") 堆区.heap:内存由自己申请(malloc realloc calloc) 自己释放(free) (堆的内存默认:1.5~1.9G) 动态内存开辟 (内存泄漏检测功能)vld检测 (内存的分配方式:低地址->高地址) 栈.stack :函数局部变量 内存由系统分配 系统回收 (栈的内存默认:windows:1M Linux:10M) (内存的分配方式:高地址->低地址)
-
【1G 】内核使用
-
0xffff ffff