? ????????本周首先想到自己实现一下字符串函数,最终代码如下:
?????????strlen:
#include <stdio.h>
int main(void)
{ char str[100];
scanf_s("%s", str, 100);
int j = 0;
while (str[j] != '\0') {
++j;
}
printf("%d", j);
return 0;
}
????????????????这个代码很显而易见的问题就是数组大小带来的安全性问题,可能会出现数组越界的情况,但我的目的只是想看一看这个函数是怎么实现的,所以并没有对此深究,但在实现这个函数时,我发现了一个VS2019上的特性:它的scanf函数输出字符串时,得带上字符数组的大小。
????????不然就会出现这样一个警告,最终经过查询才知道必须得带上数组的大小,这一点以后得注意。
strcmp?
#include<stdio.h>
int isSame(const char str[], const char str1[]);
int main(void) {
char str[100], str1[100];
scanf_s("%s %s", str, 100, str1, 100);
printf("%d", isSame(str, str1));
return 0;
}
int isSame(const char str[], const char str1[]) {
int i = 0;
while (1) {
if (str[i] > str1[i]) {
return 1;
}
else if (str[i] == str1[i]) {
if (str[i] == '\0' && str1[i] == '\0') {
return 0;
}
}
else if(str[i] < str1[i]){
return -1;
}
++i;
}
}
????????利用一个函数大致实现了strcmp函数,但其中的while循环可能还能做优化,由于目的只是想了解这些函数的逻辑,所以这里并没有深究。
? ? ? ? 但在我看一些网课的时候,我发现有些UP主返回的是两个字符的ASCII码的差值,最终在? ? ? ?C Primer Plus上找到了答案:由于系统不同,别人可能是Linux,在Windows上,它只会返回1,0,-1;
strcat
????????写这个函数时遇到了一些小问题,刚开始的代码如下:
#include<stdio.h>
int main(void) {
char str[100], str1[100];
scanf_s("%s %s", str, 100, str1, 100);
int i = 0, j = 0;
while (str[i] != '\0') {
++i;
}
while (str1[j] != '\0') {
++j;
}
int x;
for (x = 0; x < j; x++) {
str[i + x] = str1[x];
}
printf("%s", str);
}
????????看似没啥问题,但运行之后的结果为:
?它出现了乱码,我发现少进行了一次迭代,少读入了'\0',最终代码如下:
#include<stdio.h>
int main(void) {
char str[100], str1[100];
scanf_s("%s %s", str, 100, str1, 100);
int i = 0, j = 0;
while (str[i] != '\0') {
++i;
}
while (str1[j] != '\0') {
++j;
}
int x;
for (x = 0; x <= j; x++) {
str[i + x] = str1[x];
}
printf("%s", str);
}
strcpy:
#include<stdio.h>
int main(void) {
char str[50], str1[100];
scanf_s("%s", str, 50);
int i = 0;
while (str[i] != '\0') {
++i;
}
for (int j = 0; j <= i; j++) {
str1[j] = str[j];
}
printf("复制后为:%s", str1);/*while (str[i] != '\0') {
str1[i] = str[i];
i++;
}
str1[i+1] = '\0';
printf("复制后为:%s", str1);*///有一个问题是这样写为啥会多输出一个?呢,,,没理解
}
? ? ? ? ? 对于多输出一个?的问题,在其他编译器上并不会出现这个问题,我认为这是编译器的问题
?????????至于strncpy等那些限定前几个字符的函数,原理基本相同,就不再写了。
????????本周还分析了汉诺塔问题,刚开始感觉比较抽象,不过最后也是看懂了,代码如下:
#include<stdio.h>
void hanoi(int, char, char, char);
void hanoi(int n, char x, char y, char z) {
if (n == 1) {
printf("%c-->%c\n", x, z);
}
else {
hanoi(n - 1, x, z, y);
printf("%c-->%c\n", x, z);
hanoi(n - 1, y, x, z);
}
}
int main(void) {
int n;
printf("请输入汉诺塔的层数:");
scanf_s("%d", &n);
hanoi(n, 'X', 'Y', 'Z');
}
?????????首先,这个问题采用递归的方法来处理是非常方便的,如果不使用递归,可能就需要一大堆代码才能实现。这个问题看似复杂难懂,但我们只需要知道我们的目的是什么这个问题也就不那么难处理了,我们可以将我们的思路分成几个步骤:
? ? ? ? 1.将前n-1个圆盘借助z移动到y;
? ? ? ? 2.将第n个圆盘移动到c;
????????3.将剩下的圆盘移动到z;
? ? ? ? 当然,这个问题的第三步也可以进行分步处理:
? ? ? ? 1.将前n-2个圆盘借助z移动到x;
? ? ? ? 2.将第n-1个元素移动到z;
? ? ? ? 而这些,我们只需要通过改变函数参数的顺序就能实现,所以,第三步我们可以直接写成:将剩下的圆盘借助x移动到z。由此我们就可以解决汉诺塔问题。
? ? ? ? 快速排序:
#include<stdio.h>
void quickSort(int array[], int left, int right) {
int i = left, j = right;
int temp;
int pivot;
pivot = array[(left + right) / 2];
while (i <= j) {
//从左到右找到大于等于基准点的元素
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
//从右到左找到小于基准点的数
j--;
}
//如果i小于等于j,则互换元素
if (i <= j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
}
if (left < j) {
quickSort(array, left, j);
}
if (i < right) {
quickSort(array, i, right);
}
}
int main(void) {
int array[] = { 73,108,111,118,101,70,105,115,104,67,46,99,111,109 };
int i, length;
length = sizeof(array) / sizeof(array[0]);
quickSort(array, 0, length - 1);
printf("排序后的结果是:");
for (i = 0; i < length; i++) {
printf("%d ", array[i]);
}
putchar('\n');
return 0;
}
? ? ? ? 这里大致分析一下快速排序的思路:它利用的是分治思想,首先找到一个基准点,将基准点以左都换成小于基准点的数,将基准点以右都换成大于基准点的数。最终在左右两边分别再找一个基准点,按同样的思路进行排序。最后形成从大到小排列。
? ? ? ? 高级宏定义
宏定义我们自然是非常熟悉,但高级宏定义听起来就比较nb了,接下来介绍两种:
1.宏定义是可以嵌套的,代码如下:
#include<stdio.h>
#define R 6371
#define PI 3.14
#define V PI * R * R * R * 4/3
int main(void) {
printf("地球的体积为%.2f\n", V);
return 0;
}
????????这里拿一个简单的例子进行举例,非常通俗易懂。
2.宏定义可以带参数:
#include<stdio.h>
#define MAX (x,y) ((x) > (y)? (x) : (y))
int main(void) {
int x, y;
printf("请输入两个整数:");
scanf_s("%d %d", &x, &y);
printf("%d是较大的那个数", MAX(x,y));
return 0;
}
????????我们也可以使用带参数的宏定义,但这样使用时我们要注意一个小细节,拿上面的代码举例:
????????宏定义时我们不能把MAX(x,y)写成MAX? ?(x,y),这样编译器不会认为你的宏定义带参数,因为它认为你所定义的是MAX,而不是MAX(x,y)。
? ? ? ? 但我们在进行宏定义的内容定义时,一定要带上括号,不然在我们要求比如x+1的宏定义时就会因为优先级的问题而出错!
? ? ? ? 另外,在我们使用高级宏定义想提高一些程序的效率,还有一些问题我们要注意:
? ? ? ? 先看这段代码:
#include<stdio.h>
#define SQUARE(x) ((x)*(x))
int main(void) {
int i = 1;
while (i <= 100) {
printf("%d的平方是%d\n",i, SQUARE(i++));
}
}
? ? ? ? 我们的目的是要打印1-100的平方值,我们这里使用了高级宏定义,但运行的结果却让人大跌眼镜:
出现了这种运行结果,仔细思考后,在进行宏定义运算时,运行一次就会进行两次自增运算,才出现了结果错误的现象,所以我们可以将代码改成这种形式
#include<stdio.h>
#define SQUARE(x) ((x)*(x))
int main(void) {
int i = 1;
while (i <= 100) {
printf("%d的平方是%d\n",i, SQUARE(i));
i++;
}
}
?????????这样就解决了我们的问题。
? ? ? ? 结构体:
? ? ? ? 第一个结构体程序:
#include<stdio.h>
struct Book {
char title[120];
char author[40];
float price;
unsigned int date;
char publisher[40];
};
int main(void) {
struct Book book;
printf("请输入书名:");
scanf_s("%s", book.title, 120);
printf("请输入作者:");
scanf_s("%s", book.author, 40);
printf("请输入售价:");
scanf_s("%f", &book.price);
printf("请输入出版日期:");
scanf_s("%d", &book.date);
printf("请输入出版社:");
scanf_s("%s", book.publisher, 40);
printf("\n=====数据录入完毕=====");
printf("书名:%s\n", book.title);
printf("作者:%s\n", book.author);
printf("售价:%.2f\n", book.price);
printf("出版日期:%d\n", book.date);
printf("出版社:%s\n", book.publisher);
return 0;
}
? ? ? ? 这是一个能说明结构体用来干什么的程序,将一组类型不同的、但是用来描述同一件事物的变量聚合在一起,这里引入了一个点运算符,点运算符在我们初始化变量时可以进行选择。
? ? ? ? 这里还有一个箭头运算符,在我i们访问结构体中的变量的时候也可进行选择:
#include<stdio.h>
int main(void) {
struct Stu {
char name[20];
int age;
double score;
} s;
s = {
"张三",
20,
85.5
};
printf("%s %d %g\n", s.name, s.age, s.score);
struct Stu* ps = &s;
printf("%s %d %g\n", (*ps).name, (*ps).age, (*ps).score);
printf("%s %d %g\n", ps->name, ps->age, ps->score);//结构体指针->成员变量名
}
#include<stdio.h>
int main(void) {
struct A {
char a;
int b;
char c;
}a = { 'x',520, '0' };
printf("size of a = %d\n", sizeof(a));
}
? ? ? ? 关于这个代码,在64操作系统下,按照我的想法,它输出的值应该是6,但实际的结果是12,
这是因为编译器有一个内存对齐操作所以就成为了4+4+4=12,每个char类型多填充了三个字节。
但我们将代码改成这种形式:
#include<stdio.h>
int main(void) {
struct A {
char a;
char c;
int b;
}a = { 'x','0', 520 };
printf("size of a = %d\n", sizeof(a));
}
????????它的值就变成了8,同样,用内存对齐我们也可以解释。
????????在我们进行内存对齐时,我们可以改变编译器的默认对齐数,
#pragma pack()
????????采用这种方式我们就可以修改我们的默认对齐数,当我们认为结构的对齐方式不合适时,我们可以更改默认对齐数。
????????我们也可以用宏来计算默认对齐数,代码如下:
#include<stdio.h>
#include<stddef.h>
#pragma pack(2)
struct S {
char c1;
int i;
char c2;
};
#pragma pack()
int main(void) {
printf("%d", offsetof(struct S, c1));
printf("%d", offsetof(struct S, i));
printf("%d", offsetof(struct S, c2));
}
????????采用这种方式我们可以计算我们的偏移量,offsetof在stddef.h头文件下。
? ? ? ? 结构体传参,下面的代码介绍结构体传参的方式:
#include<stdio.h>
struct S {
int data[1000];
int num;
};
struct S s = { {1, 2, 3, 4}, 1000 };
void print1(struct S s) {
printf("%d\n", s.num);//传结构体
}
void print2(struct S* pts) {
printf("%d\n", (*pts).num);//传地址
}
void print3(struct S* pts1) {
printf("%d\n", pts1->num);//传地址
}
int main(void) {
print1(s);
print2(&s);
print3(&s);
}
? ? ? ? 我们可以使用地址穿参,同时我们可以选择'->'与' . '两种方式,我们也可以直接传结构体。
直接传结构体采用的是拷贝的方式,这种方式相对于直接传地址来讲效率更低,所以直接传地址,采用指针是更高效的选择。
? ? ? ? 本周还进行了一些练习
#include<stdio.h>
#define N 10
int main(void) {
int a[N] = { 0,1,2,3,4,5,6,7,8,9 };
printf("原始数组为:");
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
printf("\n");
for (int i = 0; i < N / 2; i++) {
int temp = a[i];
a[i] = a[N - i - 1];
a[N - i - 1] = temp;
}
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}//数组反向输出
}
#include<stdio.h>
int main(void) {
int a[11] = { 1,4,6,9,13,16,19,28,40,100 }, num;
printf("原始数组是:");
for (int i = 0; i < 10; i++) {
printf("%4d", a[i]);
}
printf("请输入你要插入到数组里的元素:");
scanf_s("%d", &num);
for (int i = 0; i < 11; i++) {
if (a[i] > num) {
int temp = a[i];
a[i] = num;
for (int x = i + 1; x < 11; x++) {
int temp2 = a[x];
a[x] = temp;
temp = temp2;
}
break;
}
}
for (int i = 0; i < 11; i++) {
printf("%4d", a[i]);//数组中插入一个新元素
}
}
#include<stdio.h>
int main(void) {
int a[10];
printf("请输入十个数字:");
for (int i = 0; i < 10; i++) {
scanf_s("%d", &a[i]);
}
for (int j = 0 ; j < 10; j++) {
int min = j;
for (int k = 9; k > j; k--) {
if (a[min] > a[k]) {
min = k;
}
}
int temp = a[min];
a[min] = a[j];
a[j] = temp;
}
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);//排序
}
}
? ? ? ? 这就是本周的大致内容!
|