前言

在学习的过程中,我或多或少会遇到一些问题,当我解决后,希望留个方便的地方记录一下,方便以后查找,故写下此备忘录。 2023-10-13

c语言输出文件中的内容到终端

使用fgets()函数可以达到目的

    FILE *fp = fopen("scores.txt", "r");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    char buffer[1024];
    while (fgets(buffer, 1024, fp)) {
        printf("%s", buffer);
    }

    fclose(fp);

fgets()用法

char* fgets(char* str, int STRLEN, File* fp);

第一个参数str是一个字符串指针,用于存放读取的内容。第二个参数STRLEN指定读取的长度,第三个参数是一个 FILE指针,指向要读取的文件。

fgets()读取 STRLEN - 1个字符之后,或者遇到换行符与文件结尾,就会停止读取,然后在已经读取的内容末尾添加一个空字符\0,使之成为一个字符串。注意,fgets()会将换行符(\n)存储进字符串。—form 网道 2023-10-13

二分法


#include<stdio.h>
long long int a[200005];
void solve()
{
long long int n, x;
scanf("%lld %lld", &n, &x);
long long int i;
for (i = 0; i < n; i++)
    scanf("%lld", &a[i]);
long long int min = -1, max = 1e10, mid;
long long int sum;
while (max - min > 1)//二分法的判断不可以写成max - min > 0
{
    mid = (max + min) / 2;
    sum = 0;
    for (i = 0; i < n; i++)
        if (a[i] < mid)
            sum += mid - a[i];
    if (sum <= x)
        min = mid;
    else
        max = mid;
}
printf("%lld\n", min);
return;
}
    int main()
{
    int t;
    scanf("%d", &t);
    for (; t > 0; t--)
    solve();
return 0;
}

数组存中文问题

写作业的时候经常会遇到数组存中文的情况wwww,将中文字符存入文件里面简直就是天坑,在我的编译环境里面。用utf-8存是死活存不进去,最后直接问ai告诉你得用utf-16le存,搞了一下午+一早上这才搞好,贴个例子

上面代码在vscode里还得用外置的终端打开….宽字符的处理是真的麻烦….

天坑vscode打开格式是utf-8,而你打字输入的中文是gbk导致编码不一样,得改编码。。。
参考这篇
已经存在的文件全部使用gbk编码重新保存。
settings.json文件添加以下内容,使文件全部变成gbk编码:


{
    "files.encoding": "gbk"
}

launch.json中修改以下内容,使用外置控制台运行编译后程序:

 {
    "configurations": [
        {
            ...
            "externalConsole": true,
            ...
        }
    ],
    "version": "2.0.0"
}

内存的动态分配

用字符指针存数据。

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

int main() {
    char *str;
    char maxChar;
    int hasInput = 0;
    size_t len = 0;
    size_t size = 10001;  // 初始大小

    str = (char *)malloc(size * sizeof(char));
    if (!str) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // 获取输入
    while (1) {
        char c = getchar();
        if (c == EOF || c == '\n') {
            str[len] = '\0';
            break;
        }
        str[len++] = c;

        if (len == size - 1) { // 如果接近分配的大小,重新分配更多的内存
            size *= 2;
            char *new_str = (char *)realloc(str, size * sizeof(char));
            if (!new_str) {
                printf("Memory reallocation failed\n");
                free(str);
                return 1;
            }
            str = new_str;
        }
    }

    // 如果字符串是空的
    if (len == 0) {
        printf("N/A\n");
        free(str);
        return 0;
    }

    // 初始化maxChar为字符串的第一个字符
    maxChar = str[0];

    // 遍历字符串找到ASCII码最大的字符
    for (size_t i = 1; i < len; i++) {
        if (str[i] > maxChar) {
            maxChar = str[i];
            hasInput = 1;
        }
    }

    // 输出结果
    if (hasInput) {
        printf("%c\n", maxChar);
    } else {
        printf("N/A\n");
    }

    free(str);
    return 0;
}

为什么没有赋值的字符指针用malloc分配空间后就可以赋值了?

为了理解这个问题,我们需要深入了解字符指针(或任何指针)和malloc函数的工作原理。

  1. 指针的本质: 一个指针变量存储的是内存地址。当我们声明一个指针变量,如char *ptr;ptr只是一个能够存储地址的变量,但此时它尚未初始化,所以它包含的地址是不确定的(通常称为野指针)。

  2. 赋值给指针: 当你尝试通过一个未初始化的指针赋值,如*ptr = 'a';,你实际上是在尝试向一个不确定的地址写入数据,这是危险的,并且通常会导致程序崩溃。

  3. malloc的作用: malloc函数用于动态分配内存。当你调用malloc,它为你保留一块指定大小的连续内存,并返回这块内存的首地址。例如,char *ptr = (char *)malloc(10 * sizeof(char));ptr分配了可以存储10个字符的空间,并返回这块空间的地址。

  4. 指针赋值后的使用: 一旦你为指针分配了内存,你就可以安全地使用这块内存了。例如,你可以这样做ptr[0] = 'a';,因为你知道ptr指向的地址现在是你已经分配的内存。

总结:一个未初始化的指针没有指向任何已知的、安全的内存位置。通过使用malloc,我们为指针分配一块确定的、已知的内存空间,这使我们能够安全地在那个地址处存储和检索数据。但请注意,使用完malloc分配的内存后,应使用free函数释放它,以避免内存泄漏。

那为什么赋值后的字符串不能修改,而上述问题的可以修改

这个问题涉及到字符串字面量和动态分配的内存的不同。

  1. 字符串字面量: 当我们使用字符串字面量,例如:

    char *str = "Hello";
    

    str 指向的是程序的常量区域(或称为文本段),其中存储的数据是只读的。因此,尝试修改通过字符串字面量初始化的指针指向的内容会导致未定义的行为(通常是程序崩溃)。

  2. 动态分配的内存: 当我们使用malloc(或calloc)为字符串分配内存,例如:

    char *str = (char *)malloc(6 * sizeof(char));
    strcpy(str, "Hello");
    

    这种情况下,str 指向的是堆上的一块内存,这块内存是可以读写的。因此,你可以修改str指向的内容,例如str[0] = 'h';

另一种情况是当我们使用字符数组来存储字符串时:

   char str[] = "Hello";

在这种情况下,str 是一个数组,并在栈上为其分配了内存。这块内存是可以读写的,所以我们可以修改字符串内容。

总之,字符串的可修改性取决于它存储的位置:字符串字面量是只读的,而在堆或栈上分配的字符串是可以修改的。

字符的输入

%

 printf("%%");

三种方法把int 转为二进制数

不补零


#include<stdio.h>
#define uint32 unsigned int
#define uint8 unsigned char
int ShortDivOutPutBin(uint32 input){

    uint8 temp[33]={0};
    int i=0;
    //用短除法的思想得到二进制,之后将数据从后往前读取
    while (input)   
    {
        temp[i]=input % 2; //取余数存放到数组中,此为得到的二进制数
        input = (uint32)input/2; //短除,while中判断是否除尽
        i++; //存储了一个二进制数,自加存储下一个
    }
    for(i--;i>=0;i--){ //由于最后一次iput为无效,1还是自加了,因此最后一次自加的值是无用的,所以先自减,然后将余数从后往前读取
        printf("%d",temp[i]);
    }

}

此方法可自行加0

第二种方法

 #include<stdio.h>
void bit(int n){
    int i=0;
    int arr[33]={ 0 };
    for ( i = 1; i < sizeof(int)*8; i++)
    {
        arr[i]=n&1;
        n=n >> 1;
    }
    int k = 0;

    for ( k = i-1; k >=1 ; k--)
    {
        printf("%d",arr[k]);
    }

}

一个好奇的人