1.VSCode无法正常调试 241011

解决方法:调试步骤:

1.先在终端中编译文件到debug的文件夹中(一定添加-g,否则大多数参数无法显示)

此为编译指令

gcc -g YOUR_PROGRAM.c -o e:\YOUR_PATH\build\Debug\outDebug.exe

2.确保launch.json中路径正确

3.点击开始调试,就可以正常开始调试了

PS:vscode初始配置我是看下面的视频,一遍搞定,全站质量最高,不是什么傻逼营销号,强烈推荐!

https://www.bilibili.com/video/BV1kR4y1M7R8

2.刷题网站和本地运算结果不同 1012

这是一段我求自守数的题目和代码:

/*Q431.(语言: C)自守数是指一个数的平方的尾数等于该数的自然数。求200000以内的自守数。
**输入格式要求:提示信息:"It exists following automorphic numbers smaller than 200000:\n"
**输出格式要求:"  %ld"
程序运行示例如下:
It exists following automorphic numbers smaller than 200000:
  0  1  5  6  25  **  376  ***  9376  ***25  109376*/
#include <stdio.h>
#include <math.h>

int length(long long num){ //测量数字长度
    int length=0;
    if (num==0){ //0也有一位
        return 1;
    }
    while (num!=0){
        num/=10;
        length++;
    }
    return length;
}

long long fetch(long long squared_num,int behind_length){ //取出平方后数字和其本身长度相同的后几位数
    long long fetched=0;
    fetched=(squared_num)%(long long)pow(10,behind_length);
    return fetched;
}


int is_zishoushu(long long num){
    if (fetch(num*num,length(num))==num){ //判断平方之后数字的后几位是否和平方之前的数字相等
        return 1;
    } else {
        return 0;
    }
}

int main(){
    printf("It exists following automorphic numbers smaller than 200000:\n");
    for (long long j=0;j<=200000;j++){
        if (is_zishoushu(j)==1){
            printf("  %ld",j);
        }
    }
    printf("\n"); // 输出换行
    return 0;
}

本地的输出结果和刷题网站上面的输出结果总是不同,这让我非常疑惑。询问了GPT,是这段代码出现了问题:

long long fetch(long long squared_num,int behind_length){ //取出平方后数字和其本身长度相同的后几位数
    long long fetched=0;
    fetched=(squared_num)%(long long)pow(10,behind_length);
    return fetched;
}

GPT原话:

  • pow() 函数的使用pow() 函数返回的是浮点数,而在涉及大数运算时,浮点数计算精度容易出现微小误差。这种误差可能导致不同平台上的输出不同。在 C 中使用整数时,尽量避免使用浮点运算来保证精度。
  • 平方数尾数的提取 :你在 fetch() 函数中使用了 pow() 函数来取模运算,但由于 pow() 返回浮点数,可能会引发误差。

于是,我听取了他的建议,把这段代码改成了这样:

long long fetch(long long squared_num,int behind_length){ //取出平方后数字和其本身长度相同的后几位数
    long long mod = 1;
    while (behind_length--) {
        mod *= 10; // 用乘法代替 pow()
    }
    return squared_num % mod;
}

避免使用精度差的pow函数,转而使用乘法来进行指数运算,使结果相同了。

3.int爆了 1012

题目和代码和上面的一样,大家有没有注意到我的long long?这是我更改了许多int的结果。

GPT原话:

long longint 在 C 语言中的范围主要区别在于它们能存储的整数值的大小。具体如下:

int

  • 大小 : 通常是 4 字节 (32 位)。
  • 有符号 int 的范围

    • 最小值 : -2,147,483,648
    • 最大值 : 2,147,483,647
  • 无符号 unsigned int 的范围

    • 最小值 : 0
    • 最大值 : 4,294,967,295

long long

  • 大小 : 通常是 8 字节 (64 位)。
  • 有符号 long long 的范围

    • 最小值 : -9,223,372,036,854,775,808
    • 最大值 : 9,223,372,036,854,775,807
  • 无符号 unsigned long long 的范围

    • 最小值 : 0
    • 最大值 : 18,446,744,073,709,551,615

总结区别:

  1. int 通常是 32 位 ,表示的范围较小,适合较小范围的整数计算。
  2. long long 通常是 64 位 ,可以表示更大范围的整数,适合处理更大规模的数值。

在使用时,如果你要处理非常大的数字,long long 是一个更合适的选择,而对于一般范围的整数运算,int 就已经足够了。

所以,在使用时要注意数字范围。

4.二分查找和数据类型的烦人碰撞 1013

在我学习python时,我一直认为二分查找最终总会有个结果。

结果发现是我记混了,那是二叉树的二分查找,最后当然有结果。

有时候二分查找是只能近似近似再近似,程序在达到你设定的精度后(例如106)才会自己停下。

而且,由于浮点数计算精度的问题,再加上昨天pow()函数带来的不精确,原本答案是2的方程最后只能解出个2.00几。

看题目:

Q1309.(语言: C)用二分法求方程2x^3-4x^2+3x-6=0在(-10, 10)之间的根。
**输入格式要求:"%f,%f" 提示信息:"请输入x1,x2的值:"
**输出格式要求:"方程的根=%6.2f\n"
程序的运行示例如下:
请输入x1,x2的值:-10,10
方程的根=  xxx

答案一眼就能看出来是2。我的代码如下:

#include <stdio.h>
#include <math.h>
#include <windows.h>  // 仅适用于 Windows 系统
double f(double x){
    return 2*pow(x,3)-4*pow(x,2)+3*x-6;
}

int main(){
    SetConsoleOutputCP(65001);
    double x1,x2,mid;
    double eps=1e-6;
    printf("请输入x1,x2的值:");
    scanf("%lf,%lf",&x1,&x2);
    if (f(x1)*f(x2)>0){
        printf("无根");
    }
    while (fabs(f(x1)-f(x2))>eps){
        mid=(x1+x2)/2;
        if (f(mid)==0){
            break;
        } else if (f(mid)*f(x1)<0) {
            x2=mid;
        } else {
            x1=mid;
        }
    }
    printf("方程的根=%6.2f\n",mid);
    return 0;
}

但是控制台输出的就是2.000几。

而且,我在其中更改了很多次数据类型(和昨天一样!!!)为了让我对数据更加熟悉,我又从gpt那里偷来一个表格:

数据类型对比

记住这个表格,应该是没啥问题了。

对于近似二分查找的算法,我还是有些不熟悉,日后需要再熟悉熟悉。

5.控制台乱码 10.13

这也是一个困扰了我很久(指2天)的问题。

为啥学校的刷题网站就能正常输出,不乱码,而我本地就乱码?

网上的system("chcp 65001")命令有时候有效有时候直接错误,这又是为什么?

好在,GPT给我提供了一个新的命令,同样是<windows.h>头文件,只需要用这个命令(已经出现在上面的代码中):SetConsoleOutputCP(65001);

这样我也是成功正确输出了。

6.直接删除字符串子串太困难了,我选择直接复制

一切源于这道很有意思的题目:

Q3696.(语言: C)判断字符串str2是否是字符串str1的子串,如果是则从str1中删除str2,并输出更新后的str1;否则输出原字符串str1。输入为两个字符串str1和str2(字符串内不含空格),中间用空格间隔,输出为删除操作后的str1.假设字符串的最大长度不超过20.
程序运行样例1:
abccdffi cd
abcffi

程序运行样例2:(如果str2出现多次要全部删除)
abcslfkjbcd bc
aslfkjd

输入输出格式:scanf("%s",......
    scanf("%s",......
    printf("%s\n",......

直接删除字符串需要用到内存操作,目前我还没学到这里,所以我不想用这个,这是gpt的代码:

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

void removeSubstring(char *str, const char *sub) {
    char *pos;
    int len_sub = strlen(sub);
  
    // 查找子字符串的位置
    while ((pos = strstr(str, sub)) != NULL) {
        // 将后面的部分移动到前面
        memmove(pos, pos + len_sub, strlen(pos + len_sub) + 1); // +1 是为了移动结束符'\0'
    }
}

int main() {
    char str[100] = "Hello, this is a sample string.";
    const char *sub = "sample ";
  
    printf("原始字符串: %s\n", str);
  
    removeSubstring(str, sub);
  
    printf("删除后的字符串: %s\n", str);
  
    return 0;
}

需要使用内存删除的函数。内存操作目前对我来说还是太超前了,于是我决定:把主串里面的内容,跳过子串,复制到新的字符串里面去。

在这中间我遇到了以下两个问题(或者说是犯了两个错误):

1.'\0'是单个字符

代码写着好好的,结果编译器天天报错,一问gpt,原来这玩意是单个字符,我之前一直用的双引号"\0"

2.在跳过的过程中,不能直接比较字符本身,指针位置才是最准确的

Error

为啥会不通过呢?因为我的代码是这样的:

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

int main() {
    char str1[21], str2[21], str3[21];
    int p1, p3;

    // 输入两个字符串
    scanf("%s", str3);
    scanf("%s", str2);

    // 初始化 str1
    str1[0] = '\0';

    // 使用指针 p 查找子串 str2 在 str3 中的位置
    char *p = strstr(str3, str2);

    // 循环查找并删除所有出现的子串
    while (p != NULL) {
        // 复制 str3 中 str2 之前的部分
        p1 = 0; // 重置 p1
        p3 = 0; // 重置 p3

        // 复制 str3 中 str2 之前的部分
        while (str3[p3] != *p) {
            str1[p1] = str3[p3];
            p1++;
            p3++;
        }

        // 跳过 str2 的部分
        p3 += strlen(str2);

        // 继续复制 str3 中 str2 之后的部分
        while (str3[p3] != '\0') {
            str1[p1] = str3[p3];
            p1++;
            p3++;
        }

        // 添加字符串结束符
        str1[p1] = '\0';

        // 将 str1 的内容复制回 str3,以便继续查找
        strcpy(str3, str1);

        // 查找下一个子串
        p = strstr(str3, str2);
    }

    // 输出结果
    printf("%s\n", str1);

    return 0;
}

而系统给出的例子中,两个c是连续的,这样,按照我代码寻找跳过点的逻辑,在第一个c就停下来了,必定出错。

我问gpt怎么办,它没想出来,结果我自己想出来了:比较指针在数组中的位置。

但是怎么比较,我就想不出来了。这又不是python,strstr()函数返回的可是指针的位置啊,我的p3指针和p指针地址又不一样,咋比。

结果我让gpt想一下,它一下子就想出来了:直接用p指针减去str字符串就行了啊!

因为字符串如果被当做指针使用,它会指向字符串首个字符的地址。所以这样相对一减,p的下标就出来了。

然后我就绕过了这个bug。代码如下:

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

int main(){
    char str2[21],str1[21],str3[21];
    int p1=0,p3=0;
    scanf("%s",str3);
    scanf("%s",str2);
    char *p=strstr(str3,str2);

     // 初始化 str1
    str1[0] = '\0';

    while (p!=NULL) {

        p1=0,p3=0;
  
        // 计算 str2 在 str3 中的位置
        int index = p - str3; // p 指向的地址减去 str3 的地址,得到下标

        while (p3<index) {
        str1[p1]=str3[p3];
        p1++;
        p3++;
        }
        p3+=strlen(str2);
        while (str3[p3]!='\0') {
            str1[p1]=str3[p3];
            p1++;
            p3++;
        }
        str1[p1]='\0';

        strcpy(str3,str1);


        p=strstr(str3,str2);
    }
    str1[p1]='\0';
    printf("%s\n",str1);
    return 0;
}

问题总算是解决了一部分。最后应该只剩下多个子串挤在一起出现的问题了。这个我也没啥思路,如果有思路欢迎在评论区提出来。

真是酣畅淋漓的一次解决问题啊。。。

7.致敬Python屎山——半小时拉了坨大的 1021

题目:

Q3943.(语言: C)输入一个数字(0<num<4000),转换成罗马数字并存储在字符串中输出,
在罗马数字中有其中不同的符号:I,V,X,L,C,D,M,分别对应阿拉伯数字,
Sybol            Value
I                1
V                5
X                10
L                50
C                100
D                500
M                1000,
所以1表示为”I”,而2则表示为”II”,即”I”+”I”,直到4,不再这样直接相加,而是表示为5-1,即”IV”, 超过5以后,分别用VI表示 6,VII表示 7,VIII表示 8,而9则表示为10-1,即“IX“,以此类推,40表示为”XL”, 80表示为“LXXX",90表示为”XC”,100表示为”C",300表示为“CCC”,400表示 为“CD”,600表示为“DC”,900表示为“CM”…


输入提示:"Please input number:\n"
输入格式: "%d"
输出格式: "%s"

程序运行结果实例1:
Please input number: ↙
3999
MMMCMXCIX
程序运行结果实例2:
Please input number: ↙
149
CXLIX
程序运行结果实例3:
Please input number:↙
138
CXXXVIII

我花了半小时时间,写了一坨:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
    int num,first_num,strp=0;
    char str[20];
    printf("Please input number:\n");
    scanf("%d",&num);
    while (num>0){
        if (num/1000>=1){
            first_num=num/1000;
            num=num%1000;
            for (int i=0;i<first_num;i++){
                    str[strp]='M';
                    strp+=1;
            }
        } else if (num/100>=1){
            first_num=num/100;
            num=num%100;
            if (first_num==4 || first_num==9){
                if (first_num==4){
                    str[strp]='C';
                    strp+=1;
                    str[strp]='D';
                    strp+=1;
                } else {
                    str[strp]='C';
                    strp+=1;
                    str[strp]='M';
                    strp+=1;
                }
            } else if (first_num<4) {
                for (int i=0;i<first_num;i++){
                    str[strp]='C';
                    strp+=1;
                }
            } else if (first_num==5) {
                str[strp]='D';
                strp+=1;
            } else {
                str[strp]='D';
                strp+=1;
                for (int i=0;i<first_num-5;i++){
                    str[strp]='C';
                    strp+=1;
                }
            }
        } else if (num/10>=1){
            first_num=num/10;
            num=num%10;
            if (first_num==4 || first_num==9){
                if (first_num==4){
                    str[strp]='X';
                    strp+=1;
                    str[strp]='L';
                    strp+=1;
                } else {
                    str[strp]='X';
                    strp+=1;
                    str[strp]='C';
                    strp+=1;
                }
            } else if (first_num<4) {
                for (int i=0;i<first_num;i++){
                    str[strp]='X';
                    strp+=1;
                }
            } else if (first_num==5) {
                str[strp]='L';
                strp+=1;
            } else {
                str[strp]='L';
                strp+=1;
                for (int i=0;i<first_num-5;i++){
                    str[strp]='X';
                    strp+=1;
                }
            }
        } else {
            first_num=num;
            num=0;
            if (first_num==4 || first_num==9){
                if (first_num==4){
                    str[strp]='I';
                    strp+=1;
                    str[strp]='V';
                    strp+=1;
                } else {
                    str[strp]='I';
                    strp+=1;
                    str[strp]='X';
                    strp+=1;
                }
            } else if (first_num<4) {
                for (int i=0;i<first_num;i++){
                    str[strp]='I';
                    strp+=1;
                }
            } else if (first_num==5) {
                str[strp]='V';
                strp+=1;
            } else {
                str[strp]='V';
                strp+=1;
                for (int i=0;i<first_num-5;i++){
                    str[strp]='I';
                    strp+=1;
                }
            }
        }
    }
    str[strp]='\0';
    printf("%s",str);
}

这边也是致敬我初学py的时候了。

我想不出更简洁的实现了,如果有人想出来可以打在评论区。我稳gpt它是这样想的:

#include <stdio.h>

int main() {
    int num;
    char *roman[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX",
                     "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
                     "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
                     "M", "MM", "MMM"};
  
    printf("Please input number:\n");
    scanf("%d", &num);
  
    if (num <= 0 || num > 3999) {
        printf("Invalid input. Please enter a number between 1 and 3999.\n");
        return 1;
    }
  
    // 计算千位、百位、十位和个位
    printf("%s", roman[num / 1000 + 27]); // M: 1000
    printf("%s", roman[(num % 1000) / 100 + 20]); // C: 100
    printf("%s", roman[(num % 100) / 10 + 10]); // X: 10
    printf("%s\n", roman[num % 10]); // I: 1

    return 0;
}

真的挺讨厌这种题目的。。。

8.我学会了C语言中的结构体和链表 1024

在网课的反复观看和gpt的帮助,我终于学会了这个抽象的东西。。。

以下是我自己写的示例代码,基本每一行代码都有注释。

#include <stdio.h>
#include <stdlib.h>
typedef struct Link
{
    int data;
    struct Link* Next;
}Link;


int main(){
    Link *head=NULL,*tail=NULL,*p=NULL;
    //1.创建链表12345
    head=(Link*)malloc(sizeof(Link));//给head分配内存空间,成为第一块链表
    head->data=1;//把1赋值给第一块链表的数据部分
    head->Next=NULL;//第一块链表的next指向空
    tail=head;//尾节点指针指向第一块链表
    for (int i=0;i<5;i++){//循环5次,创建长度为5的链表
        p=(Link*)malloc(sizeof(Link));//给p分配下一块链表的空间
        tail->Next=p;//上一个节点的next指向新节点
        p->data=i+2;//给当前节点的数据赋值
        tail=p;//上一个节点指针转移为本节点
    }
    tail->Next=NULL;//创建结束,最后一块节点的next指向null
    //2.遍历链表
    p=head;//活动指针先指向第一个节点
    while (p!=NULL){//直到遍历到尾节点才结束
        //Link *temp=p;//将指针temp指向p,为了free内存
        printf("%d->",p->data);//输出链表内容
        p=p->Next;//节点往下遍历
        //free(temp);//现场删除上一块内存
    }
    printf("\n");
    //3.插入数据在头节点(插个0)
    p=(Link*)malloc(sizeof(Link));//给0节点分配内存
    p->data=0;//给0节点赋值数据0
    p->Next=head;//0节点的next指向原先链表的头节点
    head=p;//对3无关紧要,为4插入数据准备头节点
    while (p!=NULL){//直到遍历到尾节点才结束
        //Link *temp=p;//将指针temp指向p,为了free内存
        printf("%d->",p->data);//输出链表内容
        p=p->Next;//节点往下遍历
        //free(temp);//现场删除上一块内存
    }
    //4.插入数据在中间(在3和4中间插入3)
    Link *insert;//定义要插入的数据位Link类
    insert=(Link*)malloc(sizeof(Link));//给待插入的数据分配内存
    insert->data=3;//把3赋值给待插入数据的data
    p=head;//动态指针指向头节点
    while (p->data<3 && p!=NULL){//寻找合适插入位置
        p=p->Next;//动态指针往后遍历,在指到3时停下
    }
    insert->Next=p->Next;//待插入数据next指向3后面的4
    p->Next=insert;//原链表中3指向待插入的3
    printf("\n");
    p=head;//动态指针指向头节点
    while (p!=NULL){//直到遍历到尾节点才结束
        Link *temp=p;//将指针temp指向p,为了free内存
        printf("%d->",p->data);//输出链表内容
        p=p->Next;//节点往下遍历
        free(temp);//现场删除上一块内存
    }
    //5.插入数据在最后(大同小异,懒得写)
    return 0;
}

就算之后忘记了看这个应该也能想起来。

9.又是一道链表题目 1031

又是一道链表题目
站在10月的尾巴上,我花了两天时间做出这道链表题目。
并不是因为这道题目有多难,而是因为:我尽力的在寻找他的逻辑错误,结果发现是我大括号的位置在我复制粘贴代码的时候被改变了。
这导致我删除A链表中元素的程序只删除了第一个元素就直接结束了。
这道题目还是比较经典的,所以发上来作纪念。

/*Q3794.(语言: C)3.    编程实现链表基本操作,并自定义函数实现以下功能
(1)建立链表A和B,输入用空格隔开,-1结束。
(2)求2个链表的差A-B。具体做法是,对于链表A中的每个元素e,在链表B中进行查找,
若存在与e相同的元素,则从A中将其删除。
(3)输出链表中的元素
(4)释放链表所占内存空间。
结构体定义为:
typedef struct LST
{
    int num; 
    struct LST *next;
} LST;
输入提示:"请输入链表数据(整型)并以空格空开,以-1为最后一个数,回车结尾:\n"
输入格式:"%d"
输入提示:"请输入链表数据(整型)并以空格空开,以-1为最后一个数,回车结尾:\n"
输入格式:"%d"
输出提示:"输出A链表中删除后的结点信息:\n"
输出格式:"%4d"*/

#include <stdio.h>
#include <stdlib.h>
typedef struct LST
{
    int num; 
    struct LST *next;
} LST;

int main(){
    LST *headA=NULL,*headB=NULL,*pA=NULL,*pB=NULL,*temp=NULL,*prevA=NULL,*p2A=NULL;
    int count=0;
    //create link A
    printf("请输入链表数据(整型)并以空格空开,以-1为最后一个数,回车结尾:\n");
    while (1) {
        if (count==0){
            headA=(LST*)malloc(sizeof(LST));
            scanf("%d",&headA->num);
            count=1;
            headA->next=NULL;
            pA=headA;
            continue;
        }
        temp=(LST*)malloc(sizeof(LST));
        scanf("%d",&temp->num);
        if (temp->num==-1){
            pA->next=NULL;
            break;
        }else {
            pA->next=temp;
            pA=temp;
        }
    }
    //create link B
    printf("请输入链表数据(整型)并以空格空开,以-1为最后一个数,回车结尾:\n");
    count=0;
    while (1) {
        if (count==0){
            headB=(LST*)malloc(sizeof(LST));
            scanf("%d",&headB->num);
            count=1;
            headB->next=NULL;
            pB=headB;
            continue;
        }
        temp=(LST*)malloc(sizeof(LST));
        scanf("%d",&temp->num);
        if (temp->num==-1){
            pB->next=NULL;
            break;
        }else {
            pB->next=temp;
            pB=temp;
        }
    }
    //delete
    printf("输出A链表中删除后的结点信息:\n");
    pA=headA;
    prevA=headA;
    pB=headB;
    int found=0;
    while (pA!=NULL){
        found=-1;
        pB=headB;
        while (pB!=NULL){
            if (pA->num==pB->num){//if found
                found=pB->num;
                break;//run away
            }
            pB=pB->next;
        }
        if (found!=-1){
            p2A=headA;
            while (p2A->num!=found && p2A!=NULL){//finding...
                prevA=p2A;
                p2A=p2A->next;
            }
            if (p2A==headA){//head
                headA=p2A->next;
            }else if (p2A->next==NULL){//tail
                prevA->next=NULL;
            }else {//middle
                prevA->next=p2A->next;
            }
        }
        pA=pA->next;
    }
    pA=headA;
    while (pA!=NULL){
        printf("%4d",pA->num);
        pA=pA->next;
    }
    return 0;
}

10.Transfer points in functions 1105

To prove the Goldbach Conjecture within 1000.

Code:

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

int is_prime(int num){
    int flag=0;
    for (int i=2;i<num;i++){
        if (num%i==0){
            flag=1;
            return 0;
        }
    }
    if (flag==0){
        return 1;
    }
}

int* create_prime(int n){
    int *a=(int*)malloc(sizeof(int)*1000);
    a[0]=2;
    int ap=1;
    for (int i=3;i<1000;i+=2){
        if (is_prime(i)==1){
            a[ap]=i;
            ap+=1;
        }
    }
    return a;
}

int* is_goldbach(int num){
    int *a=create_prime(1000);
    int *b=(int*)malloc(sizeof(int)*3);
    for (int i=0;i<1000;i++){
        if (a[i]==NULL){
            break;
        }
        for (int j=0;j<1000;j++){
            if (a[i]+a[j]==num){
                b[0]=1;
                b[1]=a[i];
                b[2]=a[j];
                return b;
            }
        }
    }
    b[0]=0;
    return b;
}

int main(){
    printf("Now let's start");
    for (int i=4;i<=1000;i+=2){
        int *a=is_goldbach(i);
        if (a[0]==0){
            printf("Not true!");
            return 0;
        }
        printf("%d=%d+%d\n",i,a[1],a[2]);
    }
    printf("True!");
}

持续更新中

最后修改:2024 年 11 月 05 日
如果觉得我的文章对你有用,请随意赞赏