终点亦是起点[C完结]这一刻 我也变成了光

编程入门 行业动态 更新时间:2024-10-17 09:51:52

终点亦是起点[C完结]这一刻 <a href=https://www.elefans.com/category/jswz/34/1768284.html style=我也变成了光"/>

终点亦是起点[C完结]这一刻 我也变成了光

来深入一下长度不受限制的字符串函数
//1. strlen字符串长度函数  

#include<stdio.h>
#include<string.h>
int main() {if (strlen("abc") - strlen("abcdef") > 0) {printf(">\n");//返回值是无符号类型   size_t(unsigned int)     所以打印结果是>}else {printf("<\n");}return 0;
}

//  模拟实现strlen函数

#include<stdio.h>
int my_strlen(const char* array) {//计算变量的长度 不修改 constassert(array != NULL);//让代码更加健康int count = 0;//计数器实现strlenwhile (*array != '\0') {count++;array++;}return count;
}
int main() {char array[] = "abc";int much = my_strlen(array);printf("%d\n", much);return 0;
}

//2.  strcpy拷贝函数    string字符串   copy拷贝

#include<stdio.h>#include<string.h>
int main() {char array[20] = "###################";//strcpy(array, "hello");//这么写没毛病  但有点小别扭char array_one[] = "hello";strcpy(array, array_one);printf("%s\n", array);//调试你会发现  '\0'  也拷贝进去了return 0;
}

//3.  strcat字符串追加  追加时先找到目标文件的  '\0'  再把源数据追加进去

#include<stdio.h>
#include<string.h>
int main() {char array1[30] = "hello \0#########";char array2[] = "world";strcat(array1, array2);printf("%s\n", array1);//调试你会发现  '\0'  也追加进去了  并且在 \0 后面追加的return 0;
}

//模拟实现  strcat

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* array, const char* array1) {//追加又不修改  更加健康char* start = array;//追加函数完成后会返回目标文件起始地址assert(array && array1);//断言一下 预防空指针//1.找到目标的  '\0'while (*array) {array++;}//2.追加字符串,包含  '\0'while (*array++ = *array1++) {;}return start;
}
int main() {char array[20] = "hello";char array1[] = "world";printf("%s\n", my_strcat(array, array1));return 0;
}

//4. 模拟实现字符串比较函数  strcmp

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* array1,const char* array2) {//  strcmp函数返回大于或小于 或等于的数字assert(array1 && array2);//健康while (*array1 == *array2) {if (*array1 == '\0') {return 0;}array1++;array2++;}if (*array1 > *array2) {return 1;}else {return -1;}
}
int main() {char* array1 = "abcde";char* array2 = "able";int number = my_strcmp(array1, array2);if (number > 0) {printf("array1 > array2\n");}else if (number < 0) {printf("array1 < array2\n");}else {printf("array1 = array2\n");}return 0;
}

//长度受限制的字符串函数  相对较于安全  可控
//1. strncpy拷贝函数

#include<stdio.h>#include<string.h>
int main() {char array1[20] = "abcdef";char array2[] = "ghk";strncpy(array1, array2, 5);//不够五个  将\0拷贝过去printf("%s\n", array1);return 0;
}

//2.strncat 追加函数

#include<stdio.h>#include<string.h>
int main() {char array1[30] = "hello \0##############";char array2[] = "world";strncat(array1, array2, 8);//   /0也追加过去printf("%s\n", array1);return 0;}

//3.strncmp  你想比较几个字符就比较几个字符


//模拟实现strstr函数  在array1中查找是否有array2数组

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* array1, const char* array2) {//只找到不修改assert(array1 && array2);const char* point1 = NULL;const char* point2 = NULL;char* start = array1;if (*array2 == '\0') {return array1;}while (*start) {point1 = start;point2 = array2;while (*point1 && *point2 && (*point1 == *point2)) {point1++;point2++;}if (*point2 == '\0') {return start;}start++;}return NULL;
}
int main() {char array1[] = "abcdefabcdef";char array2[] = "cdef";char* point = my_strstr(array1, array2);if (point == NULL) {printf("没找到\n");}else {printf("找到了:%s\n", point);}return 0;
}

//strtok字符串切割函数  找到标记会用\0结尾,返回一个指向这个标记的指针

#include<stdio.h>
#include<string.h>
int main() {char array[] = "110120@qq";char* point = "@.";char alternatives[20] = { 0 };strcpy(alternatives, array);//strtok函数会改变被操作字符串,所以使用它切分的字符串一般都是临时拷贝的内容并可以修改char* point1 = NULL;//point = strtok(alternatives, point);//printf("第一次切割 %s\n", point);//point = strtok(NULL, point);//strtok函数第一个函数为NULL,则在标记处保存的位置开始,找下一个标记//printf("第二次切割 %s\n", point);//point = strtok(NULL, point);//printf("第三次切割 %s\n", point);//如果字符串不存在更多标记,返回NULL指针for (point1 = strtok(alternatives, point); point1 != NULL; point1 = strtok(NULL, point)) {printf("%s\n", point1);}return 0;
}

//使用库函数的时候,调用失败都会有错误码  errno
//strerror  错误码转换为错误信息

#include<stdio.h>
#include<string.h>//strerror头文件
#include<errno.h> //errno头文件  全局错误码
#include<stdio.h> //perror头文件int main() {//printf("%s\n", strerror(0));      // No error//printf("%s\n", strerror(1));     //Operation not permitted//printf("%s\n", strerror(2));     //No such file or directory//printf("%s\n", strerror(3));     //No such process//printf("%s\n", strerror(4));     //Interrupted function call//printf("%s\n", strerror(5));	 //Input / output errorFILE* point = fopen("test.txt", "r");//打开文件 读的形式打开  打开失败会返回NULL指针if (point == NULL) {/*printf("%s\n", strerror(errno));*/perror("fopen");//   错误码转化为错误信息,打印错误信息  一步到位return 1;//调用失败就不用往下走了 程序结束}fclose(point);//关闭文件point = NULL;return 0;
}

//讲一下字符分类函数

#include<stdio.h>
#include<ctype.h> //isdigit头文件  
int main() {char judge = '#';int number = isdigit(judge);//isdigit 如果是数字字符0-9返回非零值  不是返回0printf("%d\n", number);return 0;
}

//字符转换函数

#include<stdio.h>
#include<ctype.h>//isupper大写字母字符分类函数头文件
int main() {char array[20] = { 0 };scanf("%s", array);int frequency = 0;while (array[frequency] != '\0') {if (isupper(array[frequency])) {array[frequency] = tolower(array[frequency]);//tolower将大写转换为小写}printf("%c ", array[frequency]);frequency++;}return 0;
}

//内存函数
//内存拷贝  memcpy  拷贝不重叠的内存  VS中重不重叠都可以拷贝   memory记忆在程序中为内存  cpy(copy)复制,拷贝

//   memmove函数可以处理重叠内存 

#include<stdio.h>
#include<string.h>//memcpy头文件
#include<assert.h>
void* my_memcpy(void* target, const void* source, size_t number) {// 我不知道内存拷贝的类型  用void*   ; size_t无符号整数void* start = target;assert(target && source);while (number--) {*(char*)target = *(char*)source;target = (char*)target + 1;source = (char*)source + 1;}return start;
} 
void* my_memmove(void* target, const void* source, size_t number) {void* start = target;assert(target && source);if (target < source) {//前->后while (number--) {*(char*)target = *(char*)source;target = (char*)target + 1;source = (char*)source + 1;}}else {//后->前while (number--) {*((char*)target + number) = *((char*)source + number);}}return start;
}
int main() {/*int array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };int array2[10] = { 0 };memcpy(array2, array1, 20);*///模拟实现int array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };int array2[10] = { 0 };//my_memcpy(array2, array1, 20);//my_memcpy(array1+2, array1, 20);//自己写的不能拷贝重叠的内存//memmove(array1 + 2, array1, 20);//模拟实现memmovemy_memmove(array1 + 2, array1, 20);return 0;
}

//memcmp 内存比较   memset内存设置

#include<stdio.h>
#include<string.h>//内存函数头文件
int main() {int array1[] = { 1, 2, 3, 4, 5 };int array2[] = { 1, 1, 4 };int judge = memcmp(array1, array2, 8);//  和strcmp字符串比较类似printf("%d\n", judge);int array3[10] = { 0 };memset(array3, 1, 20);//以字节为单位进行内存设置return 0;
}

//结构体深刨
//1.只有关键字 没有名字 这种被称为匿名结构体类型

struct person
{char name[20];int age;double height;struct//匿名结构体类型{char phone[12];char address[20];};
};
#include<stdio.h>
int main() {struct person one = { "one",18,180.00,{"110120","中国大陆"} };printf("%s\n", one.address);return 0;
}//结构体对象 one 可以通过 one.address 直接访问匿名结构体成员变量 phone,代码相对比较简洁//反之则必须通过 jim.结构体名字.phone 来访问结构体成员变量

//2.结构体自引用  不是包含同类型的变量,而是包含同类型的指针

//数据结构:数据在内存中存储的结构 ; 线性数据结构有一种是顺序表 就是 1,2,3,4…… 一个挨一个存放;第二个是链表,没有相邻,而是你在这个位置,我在那个位置,每个数据前半段是存放数据的数据域,后半段是指针域(你可以找到我,我也可以找到你)
struct person
{
    char name[20];
    int age;
    struct person* next;//如果用 struct person next,这不是死递归嘛
    //          指针变量大小是可算得,  struct person* next可以找到和自己同类型的结构
}

//3.结构体类型对齐 

#include<stdio.h>
struct student1
{char one;//第一个成员在结构体变量偏移量为0的地址处,其他成员变量要对齐到对齐数(编译器默认对齐数与该成员大小的较小值,VS是8)的整数倍处int two;char three;
};//结构体总大小为最大对齐数的整数倍  如果嵌套了结构体,则找结构体最大对齐数就可以了
struct student2
{char one;char three;int two;
};
int main() {struct student1 one = { 0 };struct student2 two = { 0 };printf("%d\n", sizeof(one));//12printf("%d\n", sizeof(two));//8   student1和2的成员一摸一样,但所占总空间还是有些区别的 让占用空间小的尽量集中在一起return 0;
}

/*
   为什么存在内存对齐?
   1.平台原因:不是所有的硬件可以访问任意地址的数据;某些硬件只能只能获取特定的数据,否则硬件会出现异常
   2.性能原因:访问未对齐需要两次访问,访问对齐需要一次就可以了
   总的来说:结构体对齐就是用空间来换取时间的做法
*/

//修改默认对齐数  和 offsetof(计算变量在首地址的偏移)宏  模拟实现offsetof

#include<stdio.h>
#include <stddef.h>//offsetof头文件
//#pragma pack(2)//修改默认对齐数为8
struct student1
{char one;int two;char three;
};
//#pragma pack()//修改回来#define OFFSETOF(struct_name,member_name)     (int*)&(((struct_name*)0)->member_name)int main() {//printf("%d\n", sizeof(struct student1));//8//printf("%d\n", offsetof/*小写给人误以为是函数*/(struct student1, one));//printf("%d\n", offsetof(struct student1, two));//printf("%d\n", offsetof(struct student1, three));printf("%d\n", OFFSETOF(struct student1, one));printf("%d\n", OFFSETOF(struct student1, two));printf("%d\n", OFFSETOF(struct student1, three));return 0;
}

/*4.位段 
    1.成员:int   ;  unsigned int  ;signed  int; char 
    2.位段成员名后边有一个冒号和数字
    3.位段的空间是按照4个字节(int)或者1个字节(char)来开辟的

    4.位段不跨平台的:第一int位段当作有符号还是无符号不确定
                     第二位段最大数目不确定(16位机器最大16,32位机器32)
                     第三位段的成员从左向右分配还是从右向左分配尚未定义
                     第四:当一个结构有两个位段,第二个位段比较大,无法容纳第一个位段剩余位时,是舍弃还是利用不确定
    

*/

#include<stdio.h>
struct word
{int a : 2;//成员a占2个bit位int b : 5;//成员b占5个bit位int c : 30;//成员c占30个bit位
};
int main() {printf("%d\n", sizeof(struct word));return 0;
}

//位段可以更好的节省空间,但有跨平台的问题

/*  枚举的优点:
             1.增加代码的可读性和维护性
             2.有类型检查,更为严谨
             3.便于调试
             4.使用方便,一次可定义多个变量

*/ 

enum Color
{RED,GREEN,BLUE,};
#include<stdio.h>
int main() {enum Color one = BLUE;printf("%d\n", RED);printf("%d\n", GREEN);printf("%d\n", sizeof(one));return 0;
}

//联合体(共用体)  特征是 公用同一块空间

union body
{char one;int two;
}u;
#include<stdio.h>
int BigSmall() {u.two = 1;return u.one;
}
int main() {//union body test;//printf("%d\n", sizeof(test));//打印结果是4//printf("%p\n", &test);//printf("%p\n", &(test.one));//printf("%p\n", &(test.two));//地址一样int number = BigSmall();if (number == 1) {printf("小端存储\n");}else {printf("大端存储\n");}return 0;
}

//联合体大小计算  联合体的大小至少为最大成员的大小 , 当最大成员大小不是最大对齐数的倍数时,要对齐到最大对齐数的倍数
/*
    写一个通讯录  1.可以存放1000个人信息(名字+性别+年龄+电话+地址) 2.增删查改
    AddressBook.h 函数声明    

#pragma once#include<stdio.h>
#include<stdlib.h>//动态用到的头文件
#include<string.h>#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELEPHONE 12
#define MAX_ADDRESS 30
#define MAX 1000//动态版本
#define CAPACITY 3
#define SIZE 2//联系人定义
typedef struct person
{char name[MAX_NAME];char gender[MAX_GENDER];int age;char telephone[MAX_TELEPHONE];char address[MAX_ADDRESS];
}person;//静态通讯录定义
//typedef struct AddressBook
//{
//	person app[MAX];//存放人的信息
//	int size;//记录当前通讯录有效信息个数
//}AddressBook;//动态通讯录定义
typedef struct AddressBook
{person* app;//存放人的信息int size;//记录当前通讯录有效信息个数int capacity;//记录当前通讯录的最大容量
}AddressBook;//初始化通讯录
void InitializationAddressBook(AddressBook* point);//增
void AddPerson(AddressBook* point);//打印
void PrintfPerson(const AddressBook* point);//打印不修改 代码更健康//删
void DelPerson(AddressBook* point);//查
void SearchPerson(AddressBook* point);//改
void ReviesPerson(AddressBook* point);//动态释放空间
void FreePerson(AddressBook* point);//保存通讯录信息
void SavePerson(AddressBook* point);//加载文件
void LoadAddressBook(AddressBook* point);//增容函数
void CapacityIncrease(AddressBook* point);


    AddressBook.c 函数定义

#define _CRT_SECURE_NO_WARNINGS
#include"AddressBook.h"//静态初始化
//void InitializationAddressBook(AddressBook* point) {
//	point->size = 0;
//	memset(point->app, 0, sizeof(point->app));
//}//动态初始化
void InitializationAddressBook(AddressBook* point) {point->app = (person*)malloc(CAPACITY * sizeof(person));if (point->app == NULL) {perror("InitializationAddressBook");return;}point->size = 0;point->capacity = CAPACITY;//加载文件LoadAddressBook(point);
}//动态释放
void FreePerson(AddressBook* point) {free(point->app);point->app = NULL;point->size = 0;point->capacity = 0;
}//静态增
//void AddPerson(AddressBook* point) {
//	if (point->size == MAX) {
//		printf("通讯录已满,无法添加\n");
//		return;
//	}
//	//增加
//	printf("请输入名字:->");
//	scanf("%s", point->app[point->size].name);
//	printf("请输入性别:->");
//	scanf("%s", point->app[point->size].gender);
//	printf("请输入年龄:->");
//	scanf("%d", &(point->app[point->size].age));//年龄需要取地址
//	printf("请输入电话:->");
//	scanf("%s", point->app[point->size].telephone);
//	printf("请输入地址:->");
//	scanf("%s", point->app[point->size].address);
//
//	point->size++;
//	printf("增加成功\n");
//}//增容函数
void CapacityIncrease(AddressBook* point) {if (point->size == point->capacity) {person* point1 = (person*)realloc(point->app, (point->capacity + SIZE) * sizeof(person));if (point1 != NULL) {point->app = point1;point->capacity += SIZE;printf("增容成功\n");}else {perror("AddPerson");printf("添加联系人失败\n");return;}}
}//动态增
void AddPerson(AddressBook* point) {//增容CapacityIncrease(point);//增加printf("请输入名字:->");scanf("%s", point->app[point->size].name);printf("请输入性别:->");scanf("%s", point->app[point->size].gender);printf("请输入年龄:->");scanf("%d", &(point->app[point->size].age));//年龄需要取地址printf("请输入电话:->");scanf("%s", point->app[point->size].telephone);printf("请输入地址:->");scanf("%s", point->app[point->size].address);point->size++;printf("增加成功\n");
}//打印
void PrintfPerson(AddressBook* point) {//标题打印printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "性别", "年龄", "电话", "地址");//打印数据int frequency = 0;for (frequency = 0; frequency < point->size; frequency++) {printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", point->app[frequency].name,point->app[frequency].gender,point->app[frequency].age,point->app[frequency].telephone,point->app[frequency].address);}
}static int FindName(AddressBook* point, char name[]) {//修饰函数  只在本文件用即可,外部找不到int frequency = 0;for (frequency = 0; frequency < point->size; frequency++) {if (strcmp(point->app[frequency].name, name) == 0) {return frequency;}}return -1;
}//删除
void DelPerson(AddressBook* point) {if (point->size == 0) {printf("通讯录为空,无需删除\n");return;}char name[MAX_NAME] = { 0 };printf("请输入删除人的名字:->");scanf("%s", name);//有没有删除人的信息int who = FindName(point, name);if (who == -1) {printf("删除人不存在\n");return;}//删除int frequency = 0;for (frequency = 0; frequency < point->size - 1; frequency++) {point->app[frequency] = point->app[frequency + 1];}point->size--;printf("删除成功\n");
}//查找
void SearchPerson(AddressBook* point) {char name[MAX_NAME] = { 0 };printf("请输入查找人的名字:->");scanf("%s", name);//有没有查找人的信息int who = FindName(point, name);if (who == -1) {printf("查找人不存在\n");return;}else {printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "性别", "年龄", "电话", "地址");printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n",point->app[who].name,point->app[who].gender,point->app[who].age,point->app[who].telephone,point->app[who].address);}
}//改
void ReviesPerson(AddressBook* point) {char name[MAX_NAME] = { 0 };printf("请输入修改人的名字:->");scanf("%s", name);//有没有修改人的信息int who = FindName(point, name);if (who == -1) {printf("修改人不存在\n");return;}else {printf("请输入名字:->");scanf("%s", point->app[who].name);printf("请输入性别:->");scanf("%s", point->app[who].gender);printf("请输入年龄:->");scanf("%s", &(point->app[who].age));//年龄需要取地址printf("请输入电话:->");scanf("%s", point->app[who].telephone);printf("请输入地址:->");scanf("%s", point->app[who].address);printf("修改成功\n");}
}void SavePerson(AddressBook* point)
{//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL) {perror(SavePerson);return;}//写int frequency = 0;for (frequency = 0; frequency < point->size; frequency++) {fwrite(point->app + frequency, sizeof(person), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}//加载文件
void LoadAddressBook(AddressBook* point) {//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL) {perror(LoadAddressBook);return;}//读文件person middle = { 0 };while (fread(&middle, sizeof(person), 1, pf)) {CapacityIncrease(point);//是否考虑增容point->app[point->size] = middle;point->size++;}//关闭文件fclose(pf);pf = NULL;}


    源.c 通讯录模板

//通讯录--静态版本
#include"AddressBook.h"
//通讯录--动态版本  1.通讯录初始化后,能存放三个人信息  放满后可以增加两个人信息
void menu()
{printf("############ 1.ADD  #############\n");printf("############ 2.DEL  #############\n");printf("############3.SEARCH#############\n");printf("############4.REVIES#############\n");printf("############5.PRINTF#############\n");printf("############ 0.QUIT #############\n");
}
enum Options
{QUIT,ADD,DEL,SEARCH,REVIES,PRINTF
};
int main()
{int input = 0;AddressBook  ab;//创建通讯录InitializationAddressBook(&ab);//初始化通讯录do {menu();printf("请选择:->\n");scanf("%d", &input);switch (input){case ADD://增加人的信息AddPerson(&ab);break;case DEL://删除DelPerson(&ab);break;case SEARCH://查找SearchPerson(&ab);break;case REVIES://修改ReviesPerson(&ab);break;case PRINTF://打印PrintfPerson(&ab);break;case QUIT:SavePerson(&ab);//保存信息FreePerson(&ab);//动态释放空间printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

//-------------动态内存分配(比固态更灵活,动态内存开辟在堆区)

#include<stdio.h>
#include<stdlib.h>//malloc(开辟空间值未被初始化) ,calloc(值被初始化)和realloc(动态内存空间调整)头文件
int main() {//int array[10] = { 0 };//栈区开辟的10个整形空间//int* point = (int*)malloc(10 * sizeof(int));//动态内存开辟  因为malloc返回类型是void*所以强制类型转换//int* point1 = (int*)realloc(NULL, 40);//这个类似与malloc,直接开辟四十个字节int* point = (int*)calloc(10, sizeof(int));if (point == NULL) {//开辟失败返回空指针  所以malloc的返回值要做检查//常见的动态内存错误:1.对NULL指针解引用操作perror("main");return 0;}//使用int frequency = 0;for (frequency = 0; frequency < 10; frequency++) { //常见的动态内存错误:2.对动态内存空间的越界访问printf("%d \n", point[frequency]);*(point + frequency) = frequency;printf("%d ", point[frequency]);}//调整空间  再加点int* start = realloc(point, 10 * sizeof(int));//realloc返回值为调整之后的内存地址(后面有足够的空间直接追加,原来数据不发生变化;如果没有足够的空间,则找一个可以装下的,返回一个新的内存地址)if (start != NULL) {//调整失败返回空指针point = start;}//回收free(point);//malloc和free成对出现  free如果参数是NULL,则函数什么事情都不做//常见的动态内存错误:3.free释放非动态开辟空间或只是放一部分(动态开辟的的指针往后走,释放指针之后的动态空间);对同一块动态开辟的空间多次释放或忘记释放(内存泄漏)//动态开辟的空间,两种回收方式(1.主动释放2.程序结束)point = NULL;//手动置为空指针return 0;
}

//温馨提示:静态库又叫数据段   常量放在代码段

//柔性数组(C99 结构体最后一个成员是未知大小的数组) 柔性数组前面必须至少有一个成员

#include<stdio.h>
#include<stdlib.h>
struct test
{int number;//int array[];//大小是未知int array[0];//也可以写成这样};
int main()
{//printf("%d\n", sizeof(struct test));// 结果是4  sizeof不计算柔性数组的内存struct test* point = (struct test*)malloc(sizeof(struct test) + 10 * sizeof(int));point->number = 10;int frequency = 0;for (frequency = 0; frequency < 10; frequency++) {point->array[frequency] = frequency;}struct test* point1 = (struct test*)realloc(point,sizeof(struct test) + 20 * sizeof(int));if (point1 != NULL) {point = point1;}free(point);point = NULL;return 0;
}

 //牛刀小试
//1.打印X型图案

#include<stdio.h>
int main()
{int number = 0;while (scanf("%d", &number) != EOF) {int frequency1 = 0;for (frequency1 = 0; frequency1 < number; frequency1++) {int frequency2 = 0;for (frequency2 = 0; frequency2 < number; frequency2++) {if (frequency1 == frequency2) {printf("*");}else if (frequency1 + frequency2 == number - 1) {printf("*");}else {printf(" ");}}printf("\n");}}return 0;
}

//2.获取月份天数

#include<stdio.h>
int main()
{int year = 0;int month = 0;int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };while (scanf("%d %d", &year, &month) != EOF) {int day = days[month];if (month == 2) {if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {day ++;}}printf("%d\n", day);}return 0;
}

//3.五科成绩去掉最高和最低求每科平均值

#include<stdio.h>
int main()
{int sum = 0;int score = 0;int frequency = 0;int max = 0;int min = 100;for (frequency = 0; frequency < 7; frequency++) {scanf("%d", &score);sum += score;if (score > max) {max = score;}if (score < min) {min = score;}}printf("%2f\n", (sum - min - max) / 5.0);return 0;
}

//4.一个升序数列,插入一个数,仍是升序

#include<stdio.h>
int main()
{int array[51] = { 0 };int number = 0;//输入数据scanf("%d", &number);int frequency = 0;for (frequency = 0; frequency < number; frequency++) {scanf("%d", &array[frequency]);}//输入要插入的数据int insert_number = 0;scanf("%d", &insert_number);for (frequency = number - 1; frequency >= 0; frequency--) {if (array[frequency] > insert_number) {array[frequency + 1] = array[frequency];}else {array[frequency + 1] = insert_number;break;}}if (frequency < 0) {array[0] = insert_number;}//输出for (frequency = 0; frequency < number + 1; frequency++) {printf("%d ", array[frequency]);}return 0;
}

//5.将一个数的二进制位的奇数和偶数位的交换

#include<stdio.h>
int main()
{int number = 10;int middle = ((number & 0xaaaaaaaa) >> 1) + ((number & 0x55555555) << 1);printf("%d\n", middle);return 0;
}

/*  
    文件:将数据放在电脑硬盘上,做到数据持久化
     磁盘上的文件是文件;在程序设计中有两种(1.程序文件(源程序文件.c)(目标文件.obj)(可执行程序.exe)2.数据文件:程序运行时读写的数据)
     文件名:c:\code(<-文件路径)\test(<-文件主干名).txt(文件后缀)
     一般来说通过FILE的指针来维护FILE结构的变量(文件信息区),定义pf是一个指向FILE类型数据的指针变量,通过文件信息区中的信息来访问该文件
     文件读写之前应先打开文件(fopen),使用结束后应关闭文件(fclose)

*/

#include<stdio.h>
struct student
{int age;char name[20];
};
int main()
{char array[20] = { 0 };struct student one = { 18,"aoteman" };struct student two = { 0 };//打开文件//FILE* pf = fopen("D:\\ShiWeiGeng\\新建文件夹 (11)\\VsCode\\Project1\\test.txt", "r");//绝对路径FILE* pf = fopen("test.txt", "r");//相对路径if (pf == NULL) {perror("fopen");return 1;}//写文件  -------------------------//流(水流):高度抽象的概念;屏幕,硬盘,U盘,光盘,软盘每个都有自己的读写规则,所以为了降低门槛,用流来进行读写//其实C语言程序,只要运行,就默认打开了3个流   stdin(标准输入流->键盘),stdout(标准输出流->屏幕),stderr(标准错误流->屏幕)//1.字符输出函数	fputc	所有输出流/*fputc('h', pf);fputc('e', pf);fputc('l', pf);fputc('l', pf);fputc('o', pf);*//*fputc('h', stdout);//从屏幕上写入fputc('e', stdout);fputc('l', stdout);fputc('l', stdout);fputc('o', stdout);*///2.文本行输出函数	fputs	所有输出流/*fputs("abcdefg\n", pf);fputs("hijklmn\n", pf);*///3.格式化输出函数	fprintf	所有输出流/*fprintf(pf, "%d %s", one.age, one.name);*///fprintf写成printf -> fprintf(stdout, "%d %s", one.age, one.name)   参数不同功能不同//4.二进制输出	fwrite	文件//fwrite(&one, sizeof(struct student), 1, pf);//字符串用二进制写进去和文本写进去一样//读文件---------------------------//1.字符输入函数	fgetc	所有输入流  //文件结束或遇到错误会返回EOF/*int number=fgetc(pf);printf("%c\n", number);number = fgetc(pf);printf("%c\n", number);number = fgetc(pf);printf("%c\n", number);*//*int number = fgetc(stdin);//从键盘上读取printf("%c\n", number);number = fgetc(stdin);printf("%c\n", number);number = fgetc(stdin);printf("%c\n", number);*///2.文本行输入函数	fgets	所有输入流//fgets(array, 4, pf);//读取3个,另外一个放\0//printf("%s\n", array);//fgets(array, 4, pf);//printf("%s\n", array);//3.格式化输入函数	fscanf	所有输入流/*fscanf(pf, "%d %s", &(two.age), two.name);//fscanf写成scanf-> fscanf(stdin, "%d %s", &(two.age), two.name);printf("%d %s\n", two.age, two.name);*///4.二进制输入	fread	文件/*fread(&two, sizeof(struct student), 1, pf);printf("%d %s\n", two.age, two.name);*///文件的随机读写--------------------------------------------//  1.  fseek根据文件指针的位置和偏移来定位文件指针//  2.ftell返回文件指针起始位置的偏移量fseek(pf, 2, SEEK_CUR);//  SEEK_CUR  当前位置   ; SEEK_END  最后位置  ; SEEK_SET  最前位置int number = fgetc(pf);printf("%c\n", number);int number1 = ftell(pf);printf("%c\n", number);fseek(pf, -2, SEEK_END);number = fgetc(pf);printf("%c\n", number);number1 = ftell(pf);printf("%c\n", number);fseek(pf, 2, SEEK_SET);number = fgetc(pf);printf("%c\n", number);number1 = ftell(pf);printf("%c\n", number);//  3.rewind文件指针的位置返回到起始位置rewind(pf);number = fgetc(pf);printf("%c\n", number);//关闭文件-------------------------------fclose(pf);pf = NULL;return 0;
}//      内存程序   (输入/读取)<----------------------------->(输出/写入)  文件(硬盘)

//sprintf  和sscanf

struct student
{char name[20];int age;char gender[10];
};
#include<stdio.h>
int main()
{struct student one = { "aoteman",18,"weizhi" };struct student middle1 = { 0 };char middle2[100] = { 0 };//把一个格式化的数据转化为字符串sprintf(middle2, "%s %d %s", one.name, one.age, one.gender);printf("%s\n", middle2);//从middle2中还原一个结构体数据sscanf(middle2, "%s %d %s", middle1.name, &(middle1.age), middle1.gender);printf("%s %d %s\n", middle1.name, middle1.age, middle1.gender);return 0;}

/*  文件相关知识
1. 一组函数对比
    scanf      针对标准输入的格式化输入语句  stdin
    fscanf     针对所有输入流的格式化输入语句  stdin/文件
    sscanf     从一个字符串中读取一个格式化数据

    printf     针对标准输出的格式化输入语句  stdout
    fprintf    针对所有输入流的格式化输入语句  stdout/文件
    sprintf    把一个格式化的数据,转换为字符串


 2. 数据在在内存中以二进制形式存储,不加转换输出到外存,就是二进制文件(数值既可以二进制存储也可以ASCII形式存储)
   外存以ASCII形式存储的文件就是文本文件(字符)

   比如10000这个数字  ASCII形式存储,需要五个字节(每个字符一个字节);而二进制形式输出,则只要四个字节

 3.文件缓冲区  想磁盘中输出数据先放到文件缓冲区 装满后才一起放到磁盘  提高了效率


 4.文件读取结束判定  feof(在文件读取中,不能用feof函数返回值直接判断文件是否结束,而是判断读取文件结束还是遇到文件结尾结束)

   fgetc函数在读取结束的时候,会返回EOF  ; 正常读取结束后,返回的是读取到字符串的ASCII值

   fgets函数在读取结束的时候,会返回空指针 ; 正常读取结束后,返回字符串空间的起始地址

   fread函数在读取结束后,返回的是实际读取的个数;如果发现读取的个数小于指定的元素个数,这就是最后一次

*/

#include<stdio.h>
int main()
{FILE* pf_read = fopen("test.txt", "r");if (pf_read == NULL) {return 1;}FILE* pf_write = fopen("my_test.txt", "w");if (pf_write == NULL) {//打开这个文件错误,就把上个文件关闭fclose(pf_read);pf_read = NULL;return 1;}//文件打开成功 读写文件int middle = 0;while ((middle = fgetc(pf_read)) != EOF) {//读取成功  写文件fputc(middle, pf_write);}if (feof(pf_read)) {//在设置了与流关联的文件结尾指示符的情况下,将返回非零值。否则,将返回零printf("文件正常结束\n");}else if (ferror(pf_read)) {//在设置了与流关联的错误指示器的情况下,将返回非零值。   否则,将返回零。printf("文件读取失败结束\n");}//关闭文件fclose(pf_read);pf_read = NULL;fclose(pf_write);pf_write = NULL;return 0;
}

//atoi 和模拟实现atoi(字符串转化为整数)

#include<stdio.h>
//#include<stdlib.h>//atoi头文件
#include<assert.h>
#include<ctype.h>//  isspace  isdigit头文件
#include<limits.h>//INT_MAX  INT_MIN头文件enum is_legitimate
{NOOK,//0  非法OK//1     合法
};enum is_legitimate number;//记录my_atoi返回值是否合法int my_atoi(const char* point) {int flag = 1;//1.传的空指针/*assert(point != NULL);*/if (point == NULL) {return 0;}//2.空字符串if (*point == '\0') {return 0;}//3.遇到空白字符while (isspace(*point)) {point++;}//4.正负号问题if (*point == '+') {flag = 1;point++;}else if(*point=='-') {flag = -1;point++;}//5.处理数字字符long long number1 = 0;while (isdigit(*point)) {number1 = number1 * 10 + flag*(*point - '0');if (number1 > INT_MAX || number1 < INT_MIN) {//预防超出范围return 0;}point++;}if (*point == '\0') {number = OK;return (int)number1;}else {//非数字字符return 0;}}
int main()
{const char* point = "  120";int middle = my_atoi(point);if (number == OK) {printf("正常的转换:%d\n", middle);}else {printf("非法转换\n");}return 0;
}

//找出数组只出现一次的数字

#include<stdio.h>
void Find(int array[], int size, int* number1, int* number2)
{//1.把所有数据异或int frequency = 0;int middle = 0;for (frequency = 0; frequency < size; frequency++) {middle ^= array[frequency];}//2.计算middle的哪一位为1int find = 0;for (frequency < 0; frequency < 32; frequency++){if (((middle >> frequency) & 1) == 1) {find = frequency;break;}}//3.在find位为1的放在一个组,为0的放在一个组int one = 0;int two = 0;for (frequency = 0; frequency < size; frequency++) {if (((array[frequency] >> find) & 1) == 1) {one ^= array[frequency];}else {two ^= array[frequency];}}*number1 = one;*number2 = two;
}
int main()
{int array[] = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4 };int size = sizeof(array) / sizeof(array[0]);int number1 = 0;int number2 = 0;Find(array, size, &number1, &number2);printf("%d %d\n", number1, number2);return 0;
}

/*--------------------------预处理(最后的倔强)--------------------------------

    1.   .c文件到.exe文件(一个.c文件通过编译器转换为.obj文件,然后通过链接器(链接库,也可以说成静态库))弄成可执行程序,通过运行环境,获取运行结果

    2.     翻译环境
           
           编译器分为预处理,编译和汇编三个成分
           预处理(预编译):第一完成头文件的包含;
                  第二#define定义的宏和符号的替换;
                  第三注释删除;
                  这些都是文本操作
           编译:把C语言代码转换为汇编代码(1.语法分析
                                         2.词义分析
                                         3.语义分析
                                         4.符号汇总)
           汇编:将汇编代码转换成了二进制指令(机器指令) 生成了符号表

           链接器:把多个目标的头文件进行链接(1.合并段表
                                            2.符号表的合并和重定位)
            
            运行坏境1.程序必须载入内存中,一般由操作系统来完成。在独立坏境中,程序的载入必须手工完成或通过可执行代码完成
                    2.程序执行开始从main函数开始
                    3.系统分配内存空间
                    4.终止程序(正常从main终止或意外终止)
*/

//1.预定义符号

#include<stdio.h>
int main()
{//printf("%s\n", __FILE__);//进行编辑的源文件//printf("%d\n", __LINE__);//文件当前行号//printf("%s\n", __DATE__);//文件被编译的日期//printf("%s\n", __TIME__);//文件被编译的时间//printf("%s\n", __FUNCTION__);//文件被编译的函数名//正确用法--写日记FILE* pf = fopen("test.txt", "a+");//追加数据if (pf == NULL) {perror("fopen\n");return 1;}int frequency = 0;for (frequency = 0; frequency < 10; frequency++) {fprintf(pf, "%d : %s %d %s %s \n", frequency, __FILE__, __LINE__, __DATE__, __TIME__);}fclose(pf);pf = NULL;return 0;
}

//2.#define定义标识符骚操作  

#include<stdio.h>
#define CASE break;case
#define NUMBER 100  
int main()
{int frequency = 0;switch (scanf("%d", &frequency)) {case1:CASE 2 :CASE 3 :break;}
#undef NUMBER//移除宏定义//printf("%d\n", NUMBER);//出错return 0;
}

//3. #(替换变量名为字符串)和##(将两个符号链接在一起)

#include<stdio.h>
#define PRINTF(accept) printf("this letter "#accept" value is%d\n",accept);
#define LINK(one,two) one##two
int main()
{//printf("1.helloworld\n");//printf("2.hello""world\n");//1. 和 2.打印效果相同 int number1 = 10;打印  this letter number1  value is  10//PRINTF(number1);//  #accept 表示"number1"printf("%d\n", LINK(numbe, r1));return 0;
}

/*5.宏和函数区别(宏有的地方和函数和相似  C语言也没有区分两者  我们习惯宏全部大写,函数不要全部大写)

   //优点:1.简单的运算中 ; 宏比函数在程序的规模和速度更胜一筹
           2.函数参数是固定类型  ;而宏的参数和类型无关

   //缺点:1.每次使用宏,一部分宏代码就会插入到程序中,增加了程序的长度;而函数代码只出现一个地方,每次调用会调用那个地方同一份代码
           2.宏不能调试
           3.宏由于类型无关,也会不够严谨,可能还会有优先级的问题
           4.宏不可以递归(宏只做简单的文本替换,且只替换一次,如果出现递归定义,就会无法被完全替换,导致后续编译时原宏名被当作函数)  而函数可以

*/

//6.条件编译(可以嵌套)  调试型代码,删了可惜,不删碍事,所以我们可以选择性编译   

#include<stdio.h>
#define NUMBER 
int main()
{//#if 1-2 //if  常量表达式
//    printf("有这个数字");
//#endif//如果NUMBER定义了,下面参与编译
//#ifdef NUMBER
//    printf("有这个数字\n");
//#endif
//
//#if defined NUMBER
//    printf("有这个数字\n");
//#endif//如果NUMBER没定义,下面参与编译
#ifndef NUMBERprintf("这个数字没定义\n");
#endif#if !defined NUMBERprintf("这个数字没定义\n");
#endif#if 1==2printf("第一个执行\n");//第一个为真  第二个即使为真也不执行
#elif 2==3printf("第二个执行\n");
#elseprintf("第三个执行\n");
#endifreturn 0;
}

//7.文件包含
/*    
      " " 和 < >包含头文件的本质区别是:查找策略不同  
      " " 1.先从自己代码所在的目录查找 2.如果1找不到,则在库函数的头文件目录查找
      < > 直接去库函数头文件所在的目录下查找

      嵌套文件包含   同一个头文件被重复多次包含(意味这代码被拷贝多份,代码冗余)  如何防止呢?
                    1. #pragma once
                    2. #ifndef __AddressBook_H__
                       #define __AddressBook_H__
                       #endif

#include<stdio.h>//库文件包含,C语言库中提供的函数   <>
#ifndef __AddressBook_H__
#define __AddressBook_H__
#include"stdio.h"//本地文件包含,自定义的函数使用  ""  //这样效率有点低了
int main()
{  printf("HelloWorld\n");return 0;
}
#endif

更多推荐

终点亦是起点[C完结]这一刻 我也变成了光

本文发布于:2024-02-13 22:00:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1760694.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:我也   这一刻   终点   变成了   起点

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!