跳转至

Problem 1

你的代码有几个问题:

  1. fe_name数组中的元素应该是指向字符串的指针,但你声明的是指针数组。
  2. scanf用于读取字符串时,需要提供数组而不是指针的地址。
  3. printf时引用字符串的方式错误。

这里是修正后的代码:

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

int main() {
    int n;
    int m;
    scanf("%d %d", &n, &m); // 读取女歌星和男歌星的人数

    char fe_name[n][100]; // 设定每个名字最大长度为99
    int fe_vote[n];

    for (int i = 0; i < n; i++) {
        scanf("%s %d", fe_name[i], &fe_vote[i]);
        printf("%s %d\n", fe_name[i], fe_vote[i]);
    }

    // 测试语句,输出女歌星的列表
    // for (int j = 0; j < n; j++) {
    //     printf("%s %d\n", fe_name[j], fe_vote[j]);
    // }

    return 0;
}

修正的要点: 1. 使用char fe_name[n][100]定义一个二维字符数组,以存储每个歌星的名字,每个名字最长为99个字符。 2. 在scanf中直接使用fe_name[i]来存储名字,而不是取地址符&。 3. 在printf中直接使用fe_name[i]而不是*fe_name[i]

这样修改后,你的代码应该能正确地读取和输出女歌星的名字和票数。

Problem 2 字符转数字

在C语言中,可以通过减去字符'0'来将字符'1'转换为整数1。这是因为字符'0'到'9'在ASCII码表中的值是连续的,从48到57。因此,'1'的ASCII码值是49,而'0'的ASCII码值是48,将'1'减去'0'的ASCII码值结果就是整数1。

以下是一个示例代码:

C
1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main() {
    char c = '1';
    int num = c - '0';

    printf("字符'1'转换为整数:%d\n", num);
    return 0;
}

在这个例子中,变量c保存字符'1',通过c - '0',我们得到了整数1,并将其存储在变量num中。然后通过printf将结果打印出来。

运行这段代码会输出:

Text Only
字符'1'转换为整数:1

这样,字符'1'就成功转换为了整数1。

Problem 3

一些和GPT Debug的聊天记录

Problem 4

今天的题有C程的宏定义

https://blog.csdn.net/Mrsgflmx/article/details/135995345

今天上午的目标是写完+整理自己这两天遇到的不会的语法/测试方法,丰富自己C程的知识,汇编看完,用结构优化自己的算法

在C语言中,宏定义是一种预处理器指令,用于定义常量、函数和表达式等。宏定义使用#define指令。C语言中的三目运算符(或条件运算符)?:用于在宏定义中实现条件判断和比较。

三目运算符 ?:

三目运算符的语法为:

C
condition ? expression1 : expression2
解释: - condition:一个表达式,返回 truefalse。 - expression1:当 conditiontrue 时执行的表达式。 - expression2:当 conditionfalse 时执行的表达式。

宏定义求最大值示例

我们可以使用三目运算符在宏定义中实现求两个数的最大值。下面是一个示例宏定义:

C
#define MAX(a, b) ((a) > (b) ? (a) : (b))

过程解析

  1. 宏定义展开:使用宏定义时,预处理器会将代码中的宏替换为定义的表达式。假设我们调用 MAX(3, 5),预处理器会将其展开为 ((3) > (5) ? (3) : (5))

  2. 条件判断:然后进行条件判断。对于这个示例,(3) > (5)false,所以三目运算符返回 5

  3. 结果:最终,MAX(3, 5) 将被替换为 5

代码示例

以下是一个包含 MAX 宏定义的完整代码示例:

C
#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))

int main() {
    int x = 10;
    int y = 20;
    int max_value;

    max_value = MAX(x, y);
    printf("The maximum value is: %d\n", max_value);

    return 0;
}

代码说明

  1. 宏定义:定义了一个名为 MAX 的宏,用于求两个数的最大值。
  2. 主函数:在 main 函数中,定义了两个变量 xy,并使用 MAX 宏求它们的最大值。
  3. 打印结果:使用 printf 函数打印最大值。

运行此代码将输出:

Text Only
The maximum value is: 20

注意事项

在使用宏定义时,有几个需要注意的点: - 括号的使用:为了确保在宏展开时表达式的正确性,应当使用括号将每个参数和整个宏表达式括起来。 - 副作用:如果宏参数是表达式而不仅仅是变量,可能会有副作用。例如,MAX(x++, y) 在展开后会对 x 进行两次递增操作。

通过这种方式,我们可以在C语言中方便地定义一些常用的操作,提高代码的可读性和可维护性。

在C语言中,当你定义一个结构体时,你可以同时声明一个或多个结构体变量。a 是一个结构体变量名,表示 struct student 类型的一个实例。

具体说明

C
1
2
3
4
5
6
struct student
{
    char name[10];
    int no;
    float score;
} a;
- struct student: 这是结构体类型的定义。它定义了一个名为 student 的结构体,其中包含三个成员:name(字符数组)、no(整数)、score(浮点数)。 - a: 这是一个结构体变量。通过在结构体定义的结尾添加 a,你实际上是在定义这个结构体类型的同时,声明并创建了一个名为 a 的结构体变量。

这意味着你可以直接使用变量 a 来访问和操作这个结构体实例的成员。例如:

C
#include <stdio.h>

struct student
{
    char name[10];
    int no;
    float score;
} a;

int main() {
    // 给结构体变量 a 的成员赋值
    a.no = 1;
    a.score = 95.5;
    snprintf(a.name, sizeof(a.name), "Alice");

    // 打印结构体变量 a 的成员
    printf("Name: %s\n", a.name);
    printf("No: %d\n", a.no);
    printf("Score: %.2f\n", a.score);

    return 0;
}

解释

  1. 定义结构体struct student 定义了一个包含 namenoscore 的结构体类型。
  2. 声明变量:在定义结构体类型的同时,声明了一个结构体变量 a
  3. 赋值:在 main 函数中,给结构体变量 a 的各个成员赋值。
  4. 打印:使用 printf 函数打印 a 的成员值。

通过这种方式,你可以在定义结构体类型的同时立即创建一个或多个结构体变量,从而简化代码的书写和结构。


  • 直接将一个结构体变量赋值给另一个结构体变量是合法的

结构是真没学好,这几道选择题只能靠GPT,等我上午做完PTA有空把结构从头到尾再学一遍,CSDN/GPT/书/PTA/csdiy

在C语言中,scanf函数用于从标准输入读取数据。它的格式是scanf(format_string, argument_list),其中format_string是一个字符串,指定要读取的数据类型和格式,argument_list是要存储读取数据的变量的地址。

对于你提供的两个scanf调用,需要考虑变量a的类型。如果变量a是结构体类型,则需要分别处理每个成员。

假设结构体定义如下:

C
1
2
3
4
5
struct student {
    char name[10];
    int no;
    float score;
} a;

对于上述结构体类型,a是一个struct student类型的变量。因此,要读取a的成员,需要使用成员运算符.来访问每个成员。

正确的用法

要从输入中读取namenoscore,应分别为每个成员调用scanf函数。如下所示:

C
scanf("%s %d %f", a.name, &a.no, &a.score);

分析你的代码

C
C. scanf("%s,%d,%f", a);
这种写法是不合法的,因为a是一个结构体类型的变量,不能直接传递给scanf。此外,格式字符串中的逗号,表示输入中需要有逗号分隔符,但一般我们使用空格分隔。

C
D. scanf("%s,%d,%f", &a);
这种写法也是不合法的。同样的原因,&a是一个指向结构体的指针,不能直接传递给scanf来读取不同类型的成员。

合法的代码示例

正确的读取结构体成员的方法如下:

C
#include <stdio.h>

struct student {
    char name[10];
    int no;
    float score;
} a;

int main() {
    // 读取输入到结构体成员
    printf("Enter name, no, score: ");
    scanf("%s %d %f", a.name, &a.no, &a.score);

    // 打印读取的值
    printf("Name: %s\n", a.name);
    printf("No: %d\n", a.no);
    printf("Score: %.2f\n", a.score);

    return 0;
}

解释

  1. 格式字符串"%s %d %f"指定了读取一个字符串(name),一个整数(no)和一个浮点数(score)。各个格式说明符之间用空格分隔。
  2. 参数列表a.name是字符数组,不需要取地址符&,因为数组名本身就是指向数组首元素的指针。而&a.no&a.score分别是整数和浮点数成员的地址。

总结

在C语言中,使用scanf读取结构体成员时,必须对每个成员分别调用并传递相应的地址。直接将结构体或其地址传递给scanf是非法的。


在C语言中,char** 表示指向指针的指针(pointer to a pointer),通常用于表示指向字符串数组的指针。具体解释如下:

  1. 指向指针的指针

    • 一个char*是一个指向字符的指针,通常用来表示一个字符串(字符数组)。
    • 一个char**是一个指向char*的指针,也就是说,它指向一个指针数组,这个指针数组中的每个元素指向一个字符串。
  2. 应用场景

    • char**常用于表示一组字符串。例如,命令行参数(argv)就是使用char**来表示的。
    • 例如,定义char* argv[]表示一个字符指针数组,char** argv则是指向这个字符指针数组的指针。
  3. 例子

    • 假设有如下代码:
    C
    1
    2
    3
    4
    char* str1 = "Hello";
    char* str2 = "World";
    char* strArray[] = { str1, str2, NULL };
    char** ptrToStrArray = strArray;
    

    这里,str1str2是指向字符串的指针,strArray是一个字符指针数组,而ptrToStrArray是指向这个字符指针数组的指针。

  4. 访问方式

    • 访问char**指向的字符串数组中的每个字符串,可以通过两层解引用来实现。例如:
    C
    printf("%s\n", ptrToStrArray[0]); // 输出 "Hello"
    printf("%s\n", *(ptrToStrArray + 1)); // 输出 "World"
    

总结来说,char**在C语言中表示一个指向指针的指针,主要用于处理字符串数组或者动态分配的多维字符数组。

在C语言中,charchar*是两种不同的数据类型,代表不同的含义:

  1. char

    • char是基本数据类型,表示单个字符。它占用1个字节(8位)。
    • 例如,char c = 'A'; 这是一个字符变量,存储字符'A'。
  2. char*

    • char*是指向字符的指针,表示一个字符数组的起始地址。通常用于处理字符串。
    • 例如,char* str = "Hello"; 这是一个指针变量,指向字符串"Hello"的第一个字符'H'的地址。

具体区别可以总结如下:

  • 存储内容
  • char存储单个字符。
  • char*存储一个内存地址,这个地址指向一个或多个字符(通常是字符串的首地址)。

  • 用法

  • char用于单个字符变量,例如:char letter = 'A';
  • char*用于字符串操作,例如:char* name = "Alice";,这里的name是一个指向字符串"Alice"的指针。

  • 内存分配

  • char变量直接存储字符数据。
  • char*指针需要指向一个有效的字符数组或字符串。指针本身占用存储地址,但它指向的字符串在别的内存位置。

例子:

C
#include <stdio.h>

int main() {
    char c = 'A';         // 单个字符
    char* str = "Hello";  // 字符串(字符数组)

    printf("Character: %c\n", c);   // 输出单个字符
    printf("String: %s\n", str);    // 输出字符串

    return 0;
}

希望这些解释能帮助你理解charchar*之间的区别。


圆圈报数感觉链表更方便,到时候把书上的链表示例代码过一遍……C程书还是得认认真真学啊!

链表是一种常见的数据结构,用于动态地存储一组数据。与数组不同,链表中的元素(称为节点)在内存中不是连续存储的,而是通过指针连接在一起。链表的主要优点是插入和删除操作效率高,因为不需要移动元素的位置。下面是关于链表的详细讲解:

单向链表(Singly Linked List)

基本结构

一个单向链表中的每个节点包含两个部分: 1. 数据域(存储数据) 2. 指针域(存储下一个节点的地址)

节点结构定义

在C语言中,节点可以定义为一个结构体:

C
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构体
struct Node {
    int data;            // 数据域
    struct Node* next;   // 指针域,指向下一个节点
};

创建和操作链表

创建新节点
C
1
2
3
4
5
6
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}
插入节点

将新节点插入到链表的头部:

C
1
2
3
4
5
void insertAtHead(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}
遍历链表

打印链表中的所有元素:

C
1
2
3
4
5
6
7
8
void printList(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}
删除节点

删除指定值的节点:

C
void deleteNode(struct Node** head, int key) {
    struct Node* temp = *head;
    struct Node* prev = NULL;

    if (temp != NULL && temp->data == key) {
        *head = temp->next;
        free(temp);
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return;

    prev->next = temp->next;
    free(temp);
}

示例程序

一个完整的示例程序来演示链表的创建、插入、遍历和删除操作:

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

// 定义链表节点结构体
struct Node {
    int data;
    struct Node* next;
};

// 创建新节点
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 插入节点到链表头部
void insertAtHead(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

// 打印链表
void printList(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

// 删除指定值的节点
void deleteNode(struct Node** head, int key) {
    struct Node* temp = *head;
    struct Node* prev = NULL;

    if (temp != NULL && temp->data == key) {
        *head = temp->next;
        free(temp);
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return;

    prev->next = temp->next;
    free(temp);
}

int main() {
    struct Node* head = NULL;

    insertAtHead(&head, 1);
    insertAtHead(&head, 2);
    insertAtHead(&head, 3);

    printf("链表内容: ");
    printList(head);

    deleteNode(&head, 2);
    printf("删除节点2后的链表内容: ");
    printList(head);

    return 0;
}

总结

链表是一种灵活的数据结构,适用于需要频繁插入和删除操作的场景。上面的例子介绍了单向链表的基本操作,包括节点创建、插入、遍历和删除。了解这些基本操作后,你可以进一步学习双向链表和循环链表,以处理更复杂的数据存储需求。

循环链表

你在创建循环链表时有一些问题。特别是在循环插入和访问节点时存在错误。此外,While应该是while。下面是修正后的代码,以及一些详细解释:

修正后的代码

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

// 定义一个链表节点 
struct Node {
    int data; // 编号
    struct Node* next; // 指针,指向下一个节点 
};

// 创建新节点
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
} 

// 插入节点到链表头部
void insertAtHead(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

// 创建循环链表
struct Node* createCircularList(int n) {
    struct Node* head = NULL;
    struct Node* temp;
    for (int i = n; i >= 1; i--) {
        insertAtHead(&head, i);
    }
    temp = head;
    while (temp->next != NULL) {
        temp = temp->next;
    }
    temp->next = head; // 将最后一个节点指向头节点,形成循环链表
    return head;
}

// 删除指定值的节点(适用于循环链表)
void deleteNode(struct Node** head, int key) {
    if (*head == NULL) return;

    struct Node* temp = *head;
    struct Node* prev = NULL;

    // 找到需要删除的节点
    do {
        if (temp->data == key) {
            if (prev == NULL) { // 删除头节点
                struct Node* tail = *head;
                while (tail->next != *head) {
                    tail = tail->next;
                }
                if (tail == *head) { // 只有一个节点
                    free(*head);
                    *head = NULL;
                    return;
                }
                tail->next = temp->next;
                *head = temp->next;
                free(temp);
            } else {
                prev->next = temp->next;
                free(temp);
            }
            return;
        }
        prev = temp;
        temp = temp->next;
    } while (temp != *head);
}

int main() {
    int n, m;
    printf("请输入n和m: ");
    scanf("%d %d", &n, &m);

    struct Node* head = createCircularList(n);

    struct Node* current = head;
    int cnt = 0;
    while (cnt < m && current != NULL) {
        printf("当前节点编号: %d\n", current->data);
        current = current->next;
        cnt++;
    }

    return 0;
}

主要修改点

  1. 修正循环插入和访问错误
  2. 原代码中While应改为while
  3. 在插入节点时,从n1进行插入,确保按顺序创建链表。

  4. 创建循环链表

  5. 通过一个辅助函数createCircularList,先创建一个单向链表,再将最后一个节点的next指针指向头节点,形成循环链表。

  6. 修正循环遍历问题

  7. 在遍历时,while (cnt < m && current != NULL)确保访问不超过m次,避免无限循环。

解释

  • createNode:分配并初始化一个新节点。
  • insertAtHead:将新节点插入到链表的头部。
  • createCircularList:创建一个循环链表,从n1的顺序插入,然后将最后一个节点的next指针指向头节点,形成循环。
  • deleteNode:删除链表中指定值的节点,适用于循环链表。
  • main:读入nm,创建一个包含n个节点的循环链表,然后遍历m次并打印当前节点的编号。

这样修改后,你的循环链表的创建和访问就可以正常运行了。

这块理解还是有点问题…… 我应该思考一下到时候去补补课而不是在这里瞎抄代码

约瑟夫环:最终代码

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

 //定义一个链表节点 
struct Node {
        int data; //编号
        struct Node* next; //指针,指向下一个节点 
};

// 创建新节点
struct Node* createNode(int data) {
        struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->data = data;
        newNode->next = NULL;
        return newNode;
} 

// 插入节点到链表头部
void insertAtHead(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

//创建循环链表
struct Node* createCircularList(int n) {
    struct Node* head = NULL;
    struct Node* temp;
    int i=n;
    for (i=n;i>=1;i--){
        insertAtHead(&head,i);
    } 
    temp = head;
    int cnt =0;
    while (temp->next != NULL){
        temp = temp->next;
    } 
    temp->next = head; //循环
    return head; 
}

int main(){
    int n;
    int m;
    printf("请输入n、m:");
    scanf("%d %d",&n,&m);
    int cnt = 1;
    struct Node* head = createCircularList(n);
    struct Node* temp= head;
    struct Node* prev = NULL;
    while (head != head->next){
        for (cnt =1; cnt<m;cnt++){
            prev = temp;
            temp = temp->next;
        }
        if (head == temp){
            head = temp->next;  
        }   
        prev->next = temp->next;
        free(temp); 
        temp=prev->next;
    }
    printf("%d",head->data);
    return 0;
}

Problem 5 (乱入python

在Python中,如果你遇到OptionalList的报错,很可能是因为没有正确导入这些类型提示。OptionalList都是来自typing模块的类型提示,需要先导入它们才能使用。

确保你在代码的开头导入了这些类型提示:

Python
from typing import Optional, List

这里是一个完整的例子,包含了正确的导入和方法定义:

Python
from typing import Optional, List

# 假设有一个TreeNode类定义如下
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def midtransfer(self, root: Optional[TreeNode]) -> List[int]:
        result = []
        self.inorder_traversal(root, result)
        return result

    def inorder_traversal(self, node: Optional[TreeNode], result: List[int]):
        if node:
            self.inorder_traversal(node.left, result)
            result.append(node.val)
            self.inorder_traversal(node.right, result)

在这个例子中:

  • Optional[TreeNode] 表示参数 root 可以是 TreeNode 类型或 None
  • List[int] 表示返回类型是包含整数的列表。

请确保你的代码文件顶部包含from typing import Optional, List这一行,这样Python解释器就能识别这些类型提示,不会报错。