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;
}

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

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

持续更新中

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