指针基础知识(笔记)

news2024/11/25 10:32:39

文章目录

  • 1. 概念理解
  • 2. 空指针和野指针
  • 3. 计算
  • 4. 小结
  • 5. size_t
  • 6. 案例一: 指针查找并返回指定元素索引
  • 7. 指针访问多维数组(涉及 int (*ptr)[3]解析)
  • 8. 指针数组
  • 9. 函数的值传递与地址引用传递
    • ① 函数的值传递(pass by value)
    • ② 地址传递(pass by reference)
  • 10. 案例二:指针作为函数返回值
  • 11. 案例三:游戏案例
  • 12. 案例四:更新分数
  • 13. 案例五:收藏奖杯(char*可以保存字符串)
  • 14. 内容出处

1. 概念理解

① 指针的作用:外部服务的提供者
② 我们总是希望外部提供给我们良好的服务,我们只需要提供给ta地址(或金钱等), ta就可以帮我们解决一切困扰,省去我们亲自动手的麻烦。
③ 问:直接building_floor[2] = 106,不是更快么, 为什么还要引入指针?
    答: 此处将数组与指针联系在一起只是为了方便理解。当我们解决更复杂的生活问题时,指针的妙用就会凸显。例如:我们点外卖或者网购时,我们当然也可以自己到店里或者生产地去取,可是为了方便,我们会选择向骑手或者网店付运费,让人家帮我们送到家门口。这种情况下,骑手和网店也可以理解为指针,我们向ta们付了钱,ta们给我们提供服务,省去我们来回奔波的麻烦。
④ windows的快捷方式是指针的一个最典型、最简单的应用。创建快捷方式相当于把程序的绝对地址赋值给那个指针变量(假如是 char *ptr = …);双击该快捷方式的图标相当于 *ptr; 程序打开的过程相当于把 *ptr作为一个参数传递给程序启动函数

#include<stdio.h>
int main(){
    int building_floor[5] = {101, 102, 103, 104, 105};
    //建群
    for(int i = 0; i < 5; i++){
        printf("%d : my house number is %d\n", i, building_floor[i]);
    }
    //群里发福利,一人一袋大米,103住户不在,请别人帮忙放门口
    int target_floor = 103;
    for(int i = 0; i < 5; i++){
        if(building_floor[i] == target_floor){
            printf("Ok!\n");
            break;
        }
    }
    //都在忙,请了个快递代拿,这个时候需要告诉人家准确地址
    int *courier = &building_floor[2];
    printf("%p\n", (void *)courier);
    printf("%p\n", &building_floor[2]);
    //推荐快递员
    for(int i = 0; i < 5; i++){
        printf("%d 's address is %p\n", building_floor[i], (void *)&building_floor[i]);
    }

    //我搬家了,搬到了106
    int *company = courier;
    *company = 106;
    printf("%d\n", building_floor[2]);
    //搬回来了
    *courier = 103;
    printf("%d\n", building_floor[2]);
    printf("%p\n", (void *)courier);
    printf("%d\n", *courier);
    courier += 1;
    printf("%d\n", *courier);
    int *courier2 = &building_floor[3];
    printf("%d\n", *courier2);
    return 0;
}

2. 空指针和野指针

#include<stdio.h>
int main(){
    //空指针: 还没有指向一个有效内存地址
    int *ptr = NULL;
    printf("%p \n", (void *)ptr);
    // 指向实际地址
    int x = 100;
    ptr = &x;
    printf("%p %d\n", &x, x);
    printf("%p %d\n", (void *)ptr, *ptr);


    // 野指针: 指向一个无效的内存地址或者已经被释放的内存地址
    // 野指针指向了一个无法描述的内存空间,可能产生无法预测的行为
    // 野指针非常危险, 程序员必须解决这个问题

    {
        int y = 104;
        ptr = &y;
        printf("%p %d\n", (void *)ptr, *ptr); // 1
    }
    // 脱离了上述作用域之后,y这个变量就不复存在了, t它相应的内存空间也会被释放. 无法确定*ptr所占空间是否有了新的数据, 贸然使用可能会导致程序崩溃
    // 此时的ptr就是一个野指针
    //printf("%p %d\n", &y, y);
    printf("%p %d\n", (void *)ptr, *ptr); // 2. 哪怕1、2输出结果相同也不行
    return 0;
}

3. 计算

#include<stdio.h>
int main(){
    int numbers[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int *ptr = numbers;
    // ptr存的是数组首地址,因为数组在内存中是back to back 的
    printf("%p \n", (void *)ptr);
    printf("%p \n", (void *) &numbers[0]);
    printf("%d \n", *ptr);

    // 可以不写数组大小的原因
    // sizeof(numbers): 统计整个数组所占内存空间大小,单位字节
    // sizeof(numbers[0]); 统计第一个元素所占内存空间的大小
    int size = sizeof(numbers) / sizeof(numbers[0]);
    printf("%d %d\n", sizeof(numbers), sizeof(numbers[0]));
    printf("%d \n", size);


    /*地址之间的加减法跳跃元素*/ 
    // 指针加法
    int *start_ptr = &numbers[0];
    printf("%d \n", *(start_ptr + 1));
    int offset = 2;
    printf("%p \n", start_ptr + offset); // 实际增加的字节数是offset *4
    printf("%p \n", &numbers[0] + offset);// 如果想要+1代表加一个字节,需要用到强制类型转换,强制转换成(char *)
    printf("%d \n", *(start_ptr + offset));// 不过转换增加了代码复杂度,可读性也差,因而实际编码过程中不常见
    for(int i = 0; i < 10; i++){
        printf("%d: %p\n", i + 1, (void *)&numbers[i]);
    }

    // 指针减法.访问第二个元素
    printf("%d \n", *(start_ptr + offset - 1));

    // 计算指针首尾地址之间的距离. 
    // 微软专门给了一个数据类型ptrdiff_t(有符号整型)来表示指针之间的距离(在32位系统中它通常是int类型, 64位-long int) ,便于跨平台使用
    int *end_ptr = &numbers[size - 1];
    printf("%td \n", end_ptr - start_ptr);

    // 通过指针比较元素位置前后
    if(start_ptr < end_ptr){
        printf("start_ptr is ahead of end_ptr\n");
    }else{
        printf("start_ptr is behind end_ptr\n");
    }

    int x = 78;
    int y = 120;
    int *ptr_x = &x;
    int *ptr_y = &y;
    printf("x: %p \n", (void *)ptr_x);
    printf("y: %p \n", (void *)ptr_y);
    if(ptr_x < ptr_y){
        printf("ptr_x is ahead of ptr_y\n");
    }else{
        printf("ptr_x is behind ptr_y\n");
    }

    // 指针顺序遍历
    for(int *i = start_ptr; i <= end_ptr; i++){
        printf("%d ", *i);
    }
    printf("\n");
    
    // 指针逆序遍历
    for(int *i = end_ptr; i >= start_ptr; i--){
        printf("%d ", *i);
    }
    printf("\n");
}

4. 小结

上述都是指针与数组的关系(数组名作为指针的使用)

5. size_t

        size_t:一个无符号的整数类型,专门用来表示大小、长度和索引。
        c语言设计它的初衷:提高程序在不同平台(跨平台)的可移植性和安全性。
         i++与++i:相同点:效果相同。差异:对于整型循环器而言,两者在性能上差异不大。但如果使用迭代器的话, ++i 在性能上可能会有一些微小的优势。(从定义上来讲,后缀递增 i++需要先去存储原始的值,然后再去返回它,在理论上可能会多一点开销)
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#include<inttypes.h>
int main(){
    int numbers[] = {10, 20, 30, 40};
    size_t numbers_size = sizeof(numbers) / sizeof(numbers[0]);
    int *ptr = numbers;
    // 输出数组元素原来的值
    for(size_t i = 0; i < numbers_size; ++i){
        printf("%" PRId32 " ", *(ptr + i));
    }
    printf("\n");

    // 将数组里每个元素的值都加5, 输出改变后数组元素的值
    for(size_t i = 0; i < numbers_size; ++i){
        *(ptr + i) += 5;
        printf("%" PRId32 " ", *(ptr + i));
    }
    return 0;
}

6. 案例一: 指针查找并返回指定元素索引

在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#include<inttypes.h>
#include<stdbool.h>
int main(){
    int32_t values[] = {10, 20, 30, 40, 50};

    int32_t *ptr = values;
    int32_t target_value = 30;
    int32_t *target_ptr = NULL;

    size_t values_size = sizeof(values) / sizeof(values[0]);
    size_t index = 0;

    bool found = false;// 与<stdbool.h>配套使用

    for(size_t i = 0; i < values_size; ++i){
        if(*(ptr + i) == target_value){
            index = i;
            target_ptr = ptr + i;
            found = true;
            break;
        }
    }
    // 专门输出size_t类型的数据
    if(found){
        printf("element %" PRId32 " 's index is: %zu \n ", target_value, index);
    }else{
        printf("element %" PRId32 " not found!\n", target_value);
    }
    return 0;
}

7. 指针访问多维数组(涉及 int (*ptr)[3]解析)

定义一个指针操作一个多维数组

#include<stdio.h>
#include<inttypes.h>
#include<stdbool.h>
int main(){
    int building_floor[2][3] = {
        {1, 2, 3}, 
        {4, 5, 6}
    };
    // (*ptr)[3]:ptr是一个指针,它指向一个包含3个int元素(数组长度为3)的一维数组
    // 一维数组指向数组首地址,二维数组指向第一行(二维数组的首地址就是它的第一行数据)
    // int *ptr[3]:声明了三个指针(即声明了一个包含三个元素的指针数组)
    int (*ptr)[3] = building_floor;
    // printf("%p \n", (void *)ptr);
    // printf("%p \n", &building_floor[0][0]);
    // printf("%p \n", &building_floor[0][1]);
    
    for(int i = 0; i < 2; ++i){
        for(int j = 0; j < 3; ++j){
            //不带*的原因:ptr[i]已经相当于地址了,它代表让指针跳到第i行
            printf("%d ", ptr[i][j]);
        }
        printf("\n");
    }
    return 0;
}

8. 指针数组

定义多个指针操作不同的数组

#include<stdio.h>
#include<inttypes.h>
int main(){
    int32_t department1[] = {1001, 1002, 1003};
    int32_t department2[] = {2001, 2002, 2003, 2004};
    int32_t department3[] = {3001, 3002, 3003, 3004, 3005};

    int32_t* department_ptrs[] = {department1, department2, department3};
    size_t department_sizes[] = {
        sizeof(department1) / sizeof(int), 
        sizeof(department2) / sizeof(int), 
        sizeof(department3) / sizeof(department3[0])
    };
    for(size_t i = 0; i < 3; ++i){
        printf("department%zu: ", i + 1);
        // 此处的变量类型老是搞混
        for(size_t j = 0; j < department_sizes[i]; ++j){
            //printf("%" PRId32 " ", *(department_ptrs[i] + j));
            printf("%" PRId32 " ", department_ptrs[i][j]);
        }
        printf("\n");
    }
    return 0;
}

9. 函数的值传递与地址引用传递

① 函数的值传递(pass by value)

必须借助返回值才能改变数值

#include<stdio.h>
#include<inttypes.h>
void add_five(int32_t value);
int add_five_2(int32_t value);
int main(){
    int32_t my_value = 10;
    printf("original value: %" PRId32 "\n", my_value);
    add_five(my_value);
    printf("present value: %" PRId32 "\n", my_value); // 输出结果为10(与函数的作用域有关)

    int32_t number = add_five_2(my_value);
    printf("present value: %" PRId32 "\n", number); // 输出结果为15

    my_value = add_five_2(my_value);
    printf("present value: %" PRId32 "\n", my_value); // 输出结果为15

    my_value = add_five_2(my_value);
    printf("present value: %" PRId32 "\n", my_value); // 输出结果为20
	
	return 0;
}
void add_five(int32_t value){
    value += 5;
}

int add_five_2(int32_t value){
    return value += 5;
}

② 地址传递(pass by reference)

指针作为函数参数使用。函数相当于提供外部服务的东西(真正的外部服务–函数),所以指针在函数里写的是最多的

#include<stdio.h>
#include<inttypes.h>
void add_five(int32_t* value);
int main(){
    int32_t my_value = 10;
    printf("original value: %" PRId32 "\n", my_value);
    add_five(&my_value);
    printf("present value: %" PRId32 "\n", my_value); // 输出结果为15
    return 0;
    
}
void add_five(int32_t* value){
    *value += 5;
}

10. 案例二:指针作为函数返回值

① 需考虑函数的参数类型以及返回值类型是否需要写成指针形式。这个其实我还是拿捏不准。
② 仿写过程中出现的问题:习惯指针的写法以后,很难返回之前的模式。例如 void print_salary(uint32_t* salary) 这个函数打印数组的数值时,会下意识写成printf(“%” PRIu32 " “, *(salary + i))这种形式,printf(”%" PRIu32 " ", salary[i])原先的这种写法就算后续在脑子里一闪而过,也会因为想到指针而怀疑这种写法的正确性。之前听到指针就头疼,现在反而觉得(就上述例子而言),指针的写法好像比 salary[i]更容易理解。
③ 学到现在突然有点懵:为什么 salary[i] 和 *(salary + i)是等效的? 上述函数中salary保存的是数组首地址,为什么访问数组元素时 salary[i] 不需要加 * 号?
答(gpt): *(salary + i):对指针 salary 加上索引 i,然后解引用它,可以得到数组的第 i 个元素; salary[i]:在 salary[i] 中,salary 已经是一个指向 uint32_t 的指针,用于访问数组的第 i 个元素。在这种语法中,编译器会自动进行指针解引用,所以你不需要手动使用 * 运算符来解引用 salary。

#include<stdio.h>
#include<inttypes.h>
#define EMPLOYEE_COUNT 5

// 集体涨工资
void increase_salary(uint32_t* salary, uint32_t increment);
// 打印工资
void print_salary(uint32_t* salary);
// 返回工资最高的员工
uint32_t* find_highest_salary(uint32_t* salary);
// 返回年终奖
// 因为这个数据用到的不多,因此函数的参数也可以不用写成指针形式
uint32_t cal_bonus(uint32_t* salary);
int main(){
    uint32_t salary[EMPLOYEE_COUNT] = {3000, 3100, 3200, 3300, 3400};
    
    printf("original salary: ");
    print_salary(salary);

    uint32_t increment = 10000;
    increase_salary(salary, increment);
    printf("present salary: ");
    print_salary(salary);

    printf("highest salary: %" PRIu32 "\n", *find_highest_salary(salary));
    
    printf("highest bonus: %" PRIu32, cal_bonus(find_highest_salary(salary)));
}
void increase_salary(uint32_t* salary, uint32_t increment){
    for(size_t i = 0; i < EMPLOYEE_COUNT; ++i){
        //*(salary + i) += increment;
        salary[i] += increment;
    }
}

void print_salary(uint32_t* salary){
    for(size_t i = 0; i < EMPLOYEE_COUNT; ++i){
        //printf("%" PRIu32 " ", *(salary + i));
        printf("%" PRIu32 " ", salary[i]);
    }
    printf("\n");
}

uint32_t* find_highest_salary(uint32_t* salary){
    uint32_t* highest = salary;
    for(size_t i = 0; i < EMPLOYEE_COUNT; ++i){
        // if(*(salary + i) > *highest){
        //     highest = salary + i;
        // }
        if(salary[i] > *highest){
            *highest = salary[i];
        }
    }
    return (uint32_t*) highest;
}


uint32_t cal_bonus(uint32_t* salary){
    return (*salary) / 10;
}

11. 案例三:游戏案例

// 玩家通过解决谜题来提升等级, 指针和函数搭配使用去更新玩家的经验值和等级
/* 游戏开发的基本概念:
    玩家属性:exp(经验值)、level(等级)
    解谜:每当玩家解开一个谜题,ta就可以获得一定数量的经验值
    等级提升:当玩家通过解谜获得的经验值达到一定的极限,就让ta等级提升
    游戏目标:玩家游戏等级达到一定等级时,会给ta相应奖励(例如:一个奖杯)
*/ 
/*
    代码实现应该有三个函数:
    1. 更新玩家经验值
    2. 检查是否有足够的经验值确保玩家升级
    3. 玩家每提升一级,给ta相应的礼品
*/
/*
    设计思路:
    1. 从main函数入手,写一些基础性的内容(例如:定义玩家初始经验值和等级)
    2. 考虑函数如何设计(根据实际需求明确函数是否需要返回值以及返回值类型、函数参数)
    3. 设计函数过程中,完善代码逻辑(例如:多少经验值可以升级?游戏最高等级是多少?宝藏提示的数量有多少?)
    4. 宝藏提示函数(用到了表驱动法):所有玩家在升到相同等级时,获得的宝藏全都相同,因此函数前面可以写一个const
        函数里用static的原因:函数里所有的东西都早已固定好,不需要每次升级都把函数重新定义一遍
*/

#include<stdio.h>
#include<inttypes.h>
#include<stdbool.h>

#define MAX_LEVEL 10
#define EXP_PER_LEVEL 100
#define HINTS_COUNT 10

void increase_exp(int32_t* exp, int32_t increment);
bool check_level_up(int32_t* exp, int32_t* level);
const char* get_treasure_hint (int32_t level);
int main() {
	// 初始经验值和等级
	int32_t player_exp = 0;
	int32_t player_level = 1;

	// 玩家解谜获得经验值
	increase_exp(&player_exp, 75);
	increase_exp(&player_exp, 100);

	// 当前玩家是否可以升级(其实每次经验值增加后都应该进行这个判断)
	if (check_level_up(&player_exp, &player_level)) {
		// 获得相应提示
		printf("%s\n", get_treasure_hint(player_level));
	}else {
		printf("经验值不足,无法升级!\n");
	}


	return 0;
	
}
void increase_exp(int32_t* exp, int32_t amount) {
	*exp += amount;
}


bool check_level_up(int32_t* exp, int32_t* level) {
	while (*exp >= EXP_PER_LEVEL && *level < MAX_LEVEL) {
		*exp -= EXP_PER_LEVEL;
		(*level)++;
		printf("恭喜您的等级升到了%" PRId32 "级\n", *level);
		return true;
	}
	return false;
}

const char* get_treasure_hint(int32_t level) {
	static const char* hints[HINTS_COUNT] = {
		"提示一:宝藏在...",
		"提示二:宝藏在...",
		"提示三:宝藏在...",
		// ......
	};
	if (level > 0 && level <= HINTS_COUNT) {
		return hints[(size_t)level - 1];
	}
	
	return "未知提示:请确保你的等级在有效范围内才能解锁宝藏提示";
}

12. 案例四:更新分数

游戏里经常会有一些模块:更新分数、比较分数、分数倍增等
仿写时出现的问题:分数比较模块返回值写成 “return (int32_t)(*player1_score > *player2_score) ? *player1_score : *player2_score” ,多加了 * 号

#include<stdio.h>
#include<inttypes.h>

void update_score(int32_t* player_score, int32_t points);
int32_t* compare_score(int32_t* player1_score, int32_t* player2_score);
void double_score(int32_t* player_score);

int main(void){
	int32_t player1_score = 100;
	int32_t player2_score = 150;

	// 更新分数
	update_score(&player1_score, 20);

	// 比较分数
	int32_t* higher_score = compare_score(&player1_score, &player2_score);
	printf("higher score: %" PRId32 "\n", *higher_score);

	// 分数倍增
	double_score(&player2_score);
	
	return 0;
}

void update_score(int32_t* player_score, int32_t points){
	*player_score += points;
	printf("updated score: %" PRId32 "\n", *player_score);
}

int32_t* compare_score(int32_t* player1_score, int32_t* player2_score){
	return (int32_t)(*player1_score > *player2_score) ? player1_score : player2_score;
}

void double_score(int32_t* player_score){
	*player_score *= 2;
	printf("score after multiplication: %" PRId32 "\n", *player_score);
}

13. 案例五:收藏奖杯(char*可以保存字符串)

① 游戏中的用途:添加成就、显示所有成就效果
② const在函数参数中的用途:防止函数内部被有意或无意地修改(变量被声明为const意为该变量在今后仅可读,不可以被修改,即可读不可写);保护传入的数据
③ 指针变量不仅可以保存地址,也可以保存字符串
在这里插入图片描述

#include<stdio.h>

#define MAX_ACHIEVEMENT_COUNT 10
// 此处往数组里添加元素的方式类似于面向对象编程里的接口设计
const char* achievements[MAX_ACHIEVEMENT_COUNT];
void add_achievement(const char* new_achievement);
size_t achievement_count = 0;

void print_achievements();

int main(void) {
	add_achievement("完成第一个挑战奖杯");
	add_achievement("找到了所有的隐藏宝箱");

	print_achievements();

	return 0;
}

void add_achievement(const char* new_achievement) {
	if (achievement_count < MAX_ACHIEVEMENT_COUNT) {
		achievements[achievement_count++] = new_achievement;
		printf("已添加新成就:%s\n", new_achievement);
	}
	else {
		printf("成就数组已满,无法添加新的成就!\n");
	}
}

void print_achievements() {
	printf("显示所有已有成就:\n");
	for (size_t i = 0; i < achievement_count; ++i) {
		printf("%zu: %s\n", i + 1, achievements[i]);
	}
}

14. 内容出处

我是从p165地址这一小结开始看的指针这一部分
        虽然很早就学过c语言了,但是学的效果用四个字评价就是“一坨狗屎”。前几天我在听frank的数据结构的课程,听完了链表这一部分,原本想着理解了它的内核及应用场景后,代码部分应该也就不成问题了,其实一切本该如此,但是我突然发现我还是写不出来,基础知识部分太差劲了,例如:我只是知道有指针这个东西,但是让我具体解释,我真的会傻眼。虽然之前在学c语言的时候,也专门听过指针这部分的网课,但怎么说呢,跟着up主把代码敲了一遍(那代码我现在还有,但是那次写完之后再也没看过🤣),该不懂还是不懂,甚至于当时刷题看见指针这个标签就会直接跳过。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初学Vue

1.v-text 2.v-html 可以解析标签 3.v-pre 4.class绑定 1.字符串绑定 效果 2.对象绑定 效果 3.数组 还可以用data数据带class加上去 4.三元表达式 5.style绑定 1.字符串 2.对象绑定 3.数组绑定 6.计算属性 调用函数 函数如下 面试&#xff1a;计算属性特点 只要值 没有改变…

【Week-G7】Semi-Supervised GAN 实践,使用MNIST数据集

文章目录 一、基础知识二、代码实现2.1 导入所需模块 & 设置网络初始参数2.2 初始化权重2.3 定义算法模型2.4 配置模型2.5 训练模型2.6 训练结果 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导…

使用 Claude3.5 只需 2 分钟快速构建仪表盘

这是用 claude 生成的图表&#xff0c;只花了 2 分钟 目录 Claude何时使用Artifacts&#xff1f;我如何使用Artifacts&#xff1f;我的例子让claude导出本地部署结尾 关键还可以分享 这是分享之后的链接&#xff1a; https://claude.site/artifacts/1cf37377-1d00-4ab2-b8dd-a…

PMP考试一定要考到3A吗?怎么备考?

PMP&#xff08;Project Management Professional&#xff09;认证是全球公认的项目管理专业人士资格认证&#xff0c;它代表着项目管理领域的高水平标准。 在备考PMP考试时&#xff0c;有些赛宝关心是否需要考到3A&#xff08;即三个领域均为Above Target&#xff0c;超出目标…

【中项】系统集成项目管理工程师-第10章 项目整合管理-10.7结束项目或阶段

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

[Python学习日记-3] 编程前选择一个好用的编程工具

[Python学习日记-3] 编程前选择一个好用的编程工具 简介 PyCharm IDE的安装 PyCharm IDE安装后的一些常规使用 简介 在踏上 Python 编程的精彩旅程之前&#xff0c;选择一款得心应手的编程工具无疑是至关重要的一步。这就如同战士在出征前精心挑选趁手的武器&#xff0c;它将…

Unity补完计划 之 音效

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 首先&#xff0c;音频这块组件较少&#xff0c;但是内容很重要&#xff0c;因为对于任何一款非特殊面向人群的游戏来说&a…

SQLiteStudio 连接sqlite3数据库(真机数据库可视化调试)

SQLiteStudio安装 官网链接&#xff1a;https://sqlitestudio.pl/ 下载后&#xff0c;直接按部就班&#xff0c;打开即可使用 用户手册&#xff08;工具如何使用直接看这份就可以了&#xff09;&#xff1a;https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual 其…

GoFly快速开发框架代码市场使用说明

说明 我们框架坚持开源的项目绝不能存在收费项目&#xff0c;所以我们gofly快速开发开源版没有内置代码仓插件&#xff0c;因此需要使用代码市场中的代码包需要再企业版中使用&#xff0c;代码市场插件如下&#xff1a; 图1、社区-代码市场​​​​ 他和企业版管理后台的代码仓…

Component和Loader

文章目录 文章内容效果图代码 文章内容 效果图 代码 import QtQuick 2.15 import QtQuick.Window 2.15 import FluentUI import QtQuick.Controls 2.5Window {visible: truewidth: 320height: 240// 自定义组件:需要手动加载Component{id:comRectangle{id:rectwidth: 80heigh…

关闭Windows安全中心

打开Windows安全中心的病毒和威胁防护。 打开该选项的管理设置。 关闭实时保护。

【RTOS面试题】RTOS和Linux的区别

实时操作系统&#xff08;RTOS, Real-Time Operating System&#xff09;与Linux操作系统&#xff08;一种典型的普通操作系统&#xff0c;General-Purpose Operating System, GPOS&#xff09;之间存在一些显著的区别。这两种操作系统各有侧重&#xff0c;适用于不同的应用场景…

循环执行时数据的同步方式

在dataX-web中循环执行时数据的同步方式 解决中文comment中文乱码 在mysql中 # &#xff08;0&#xff09;修改库注释 alter table DBS modify column desc varchar(256) character set utf8; alter table DATABASE_PARAMS modify column PARAM_VALUE varchar(256) characte…

用python创建极坐标平面

极坐标的介绍 http://t.csdnimg.cn/ucau3http://t.csdnimg.cn/ucau3这个文章里可以知道极坐标的基本知识&#xff0c;接下来实现极坐标的绘制 PolarPlane 是 Manim&#xff08;一个用于数学动画的Python库&#xff09;中的一个类&#xff0c;用于创建极坐标平面。与笛卡尔…

汇昌联信数字做拼多多运营怎么做?

在当今电商竞争激烈的环境下&#xff0c;如何有效地在拼多多这样的平台上进行运营&#xff0c;是许多商家和品牌都在思考的问题。汇昌联信数字作为一家致力于提供数字化解决方案的公司&#xff0c;其在拼多多上的运营策略值得深入探讨。本文将详细分析汇昌联信数字在拼多多上的…

【HBZ分享】Spring启动时核心refresh方法流程

refresh核心代码所在位置 在AbstractApplicationContext类中的refresh方法中 refresh的业务流程编排 调用obtainFreshBeanFactory()去创建一个全新的BeanFactory工厂&#xff0c;类型为DefaultListableBeanFctory&#xff0c;其功能为【解析xml】将里面bean标签内容解析成【…

信息学奥林匹克竞赛详解-CSP、NOIP、NOI、IOI是什么

近年来&#xff0c;随着计算机在教育领域的影响力越来越大&#xff0c;信息学奥林匹克竞赛也越来越受关注。 山东省在2017年秋季正式出版了《小学信息技术》&#xff0c;大幅度引入了Scratch、Python等编程语言。 浙江省在2018年的高考选考科目中新增了信息技术&#xff0c;包…

【Qt】图形化和纯代码实现Hello world的比较

本篇文章使用俩种方式实现Qt上的Hello world&#xff1a; 通过图形化的方式&#xff0c;在界面上创建出一个控件&#xff0c;显式Hello world通过纯代码的方式&#xff0c;通过编写代码&#xff0c;在界面上创建控件&#xff0c;显示Hello world 图形化方式 双击Forms文件中的…

CTFHUB-web-RCE-读取源代码

开启题目 网页发现了源代码&#xff0c;还是和前几题一样是 php:// &#xff0c;提示说 flag 在代码中&#xff0c;并且在 /flag 文件夹中&#xff0c;题目名字也叫读取源代码。 php://filter 是一种元封装器&#xff0c;专门用于数据流的过滤和筛选。与传统的文件操作函数相比…

selenium的UI自动化框架入门

环境准备 python、pycharme、chromedriver google下载的官网地址 https://google.cn/chrome/ chromedriver chromedriver的下载 https://chromedriver.storage.googleapis.com/index.html chromedriver配置环境变量 C:\Users\Administrator\.cache\selenium\chromedrive…