【C语言】第八期——指针、二维数组与字符串

目录

1 初始指针

2 获取变量的地址

3 定义指针变量、取地址、取值

3.1 定义指针变量

3.2 取地址、取值

4 对指针变量进行读写操作

5 指针变量作为函数参数

6 数组与指针

6.1 指针元素指向数组

6.2 指针加减运算(了解)

6.2.1 指针加减具体数字 

6.2.2 指针加减指针

6.3 数组名与数组元素首地址的关系

6.4 数组作为函数参数

7 二维数组以及字符串与指针

7.1 二维数组的定义方法

7.1.1 定义一个二维数组 

7.1.2 访问二维数组

7.2 定义字符串的几种方法

7.3 字符串数组

7.4 strcat 连接字符串

7.5 strcpy 字符串复制(拷贝)函数


1 初始指针

通过前面的教程我们知道变量是用来存储数据的,变量的本质是给存储数据的内存地址起了一个好记的别名

比如我们定义了一个变量 int a= 10 ,这个时候可以直接通过a这个变量来读取内存中保存的10 这个值,在计算机底层a这个变量其实对应了一个内存地址

指针也是一个变量,但它是一种特殊的变量,它存储的数据不是一个普通的值,而是另一个变量的内存地址

每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表 示了在内存中的一个地址

刚开始学C语言的指针操作,我们只需要记住两个符号 :&(取地址) 和 *(根据地址取值 /定义指针变量)


2 获取变量的地址

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。C语言中使用&字符放在变量 前面对变量进行取地址操作

#include <stdio.h>
int main(void)
{int a = 10;printf("a的地址是:%p\n", &a);return 0;
}

3 定义指针变量、取地址、取值

3.1 定义指针变量

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用 来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是 指针

以下是有效的指针声明:

int* ip;    //一个整型的指针
double* dp; //一个 double 型的指针
float* fp;  //一个浮点型的指针
char* ch    //一个字符型的指针

所有指针的值都是一个地址,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是 一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同


3.2 取地址、取值

#include <stdio.h>
int main(void)
{// 定义一个int变量aint a = 10;printf("a的地址是:%p\n", &a);// 定义int类型的指针变量pint* p_a = &a;printf("指针p_a的值:%p\n", p_a);printf("指针p_a的地址:%p\n", &p_a);printf("a的值:%d\n", a);printf("根据指针p_a的值去内存取值得到的结果为:%d", *p_a);return 0;
}

总结:

  • 取地址操作符&和取值操作符是一对互补操作符, & 取出地址, 根据地址取出地址指向的值
  • 对变量进行取地址(&)操作,可以获得这个变量的地址
  • 指针变量的值是地址
  • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值

4 对指针变量进行读写操作

#include <stdio.h>
int main(void)
{int a = 10;int b = 20;int* p1, * p2; // 定义指针变量 p1、 p2p1 = &a;// p1 指向变量 ap2 = p1;// p2 指向变量 aprintf("&a=%p p1=%p p2=%p\n", &a, p1, p2);*p1 = 20;printf("a的值%d,取指针得到的值%d", a, *p1);return 0;
}

运行结果:

&a=000000612A17FA74 p1=000000612A17FA74 p2=000000612A17FA74
a的值20,取指针得到的值20


5 指针变量作为函数参数

在C语言中,函数参数不仅可以是字符型、整型、浮点型等,还可以是指针类型,作用是将变量地址传递给函数形参

#include <stdio.h> 
void modify1(int *c) 
{*c = 20;
}
int main(void) {int a = 10;modify1(&a);printf("%d", a);return 0;
}

6 数组与指针

6.1 指针元素指向数组

数组本质上是一片连续的内存空间,每个数组元素都对应一块独立的内存空间,它们都有相应的地址。

因此,指针变量既然可以指向变量,也就可以指向数组元素

数组的构成本质上是:数组名[偏移量]

数组名就代表第一个元素的地址,偏移量就是在此基础上偏移

数组的元素本质上完全可以当做是单独的变量对待,只不过没有名称而已

int a[5]={1,2,3,4,5}; //定义长度为5的int数组
int *p_a=&a[0]; //定义指向int变量的指针变量p_a,把a数组第0个元素地址赋给指针变量p_a

注意:&a[0]等价于&(a[0]),由于[ ]运算符比取地址运算符&优先级高,因此&(a[0])中的小括号可以省略,简写为:&a[0]

在计算机中内存的最小单位是字节,每个字节都对应一个地址

如果一个变量占用多个字节,就会占用 多个内存地址

例如: char 类型变量占1字节就对应1个地址,short 类型变量占2字节对应2个地址,int 类型变量占4 字节对应4个地址.....·其他类型依次类推

同理,数组元素类型不同占用的内存地址也不同

下面通过例子来验证以上分析

#include<stdio.h>
int main(void)
{char c[5];short s[5];int i;for (i = 0; i < 5; i++){printf("&c[%d]=%p ", i, &c[i]);printf("&s[%d]=%p \n", i, &s[i]);}return 0;
}

运行结果:

&c[0]=000000000061FE17 &s[0]=000000000061FE0C

&c[1]=000000000061FE18 &s[1]=000000000061FE0E

&c[2]=000000000061FE19 &s[2]=000000000061FE10

&c[3]=000000000061FE1A &s[3]=000000000061FE12

&c[4]=000000000061FE1B &s[4]=000000000061FE14

说明:不同设备上面输出的地址可能不一样的,数组中每个元素地址都是连续的


6.2 指针加减运算(了解)

6.2.1 指针加减具体数字 

指针本质上就是内存地址,在32 位操作系统下,内存地址是 4 字节的整数。既然是整数就可以进行 加、减、乘、除等算术运算。不过需要注意的是,在 C 语言中一般只讨论指针加、减运算,乘、除等其 他算术运算都没有意义

在实际开发中,指针加、减运算多用于数组(或连续内存空间)。当指针变量p 指向数组元素时,p+1 表 示指向下一个数组元素,p-1 表示指向上一个数组元素

#include <stdio.h>
int main(void)
{int a[3] = { 1, 2, 3 };int* p = &a[0];// 指针 p 指向 a[0]printf("%p %d\n", p, *p); // 输出 a[0] 的地址 和 a[0] 的值p = p + 1;// p 加 1printf("%p %d\n", p, *p); // 输出 a[1] 的地址 和 a[1] 的值return 0;
}

运行结果:

000000811557F968 1
000000811557F96C 2

注意:实现指针加减的时候需要注意越界问题


6.2.2 指针加减指针

在C语言中,两个指针相加是没有意义的,而两个指针相减却有特殊的意义,不过只有当两个指针都指向同一数组中的元素时才有意义

一个数组中的元素时,对它们进行减法运算,得到的结果是这两个指针所指向元素之间相隔的元素个数 (不是之间有的个数,之间有的元素数要在此基础上减一),而不是它们地址差值的字节数。其计算方式是用两个指针的地址差值除以指针所指向数据类型的大小

用公式表示为:(指针2的地址 - 指针1的地址) / sizeof(指针所指向的数据类型)


6.3 数组名与数组元素首地址的关系

C语言中,数组名与数组首元素地址等价。也就是说,在程序中,输出数组名与输出数组首元素地址是相同的

#include <stdio.h>
int main(void)
{int num[5];printf("%p\n", num);     // 输出数组名printf("%p\n", &num[0]); // 输出数组首元素地址return 0;
}

输出结果:

000000000061FE00

000000000061FE00

我们就可以通过把数组名复制给指针变量,来把数组首地址给指针变量

#include <stdio.h>int main(void){int num[5] = {1, 2, 3, 4, 5};int *p_num = num; // 把num的首地址赋值给指针变量printf("p_num指针的值=%p \n p_num对应数组元素的值%d", p_num, *p_num);return 0;}

我们也可以通过p_num来访问数组里面的每个元素

 #include <stdio.h>int main(void){int num[5] = {1, 2, 3, 4, 5};int *p_num = num; // 把num的首地址赋值给指针变量printf("p_num指针的值=%p ,num的地址是=%p  p_num对应数组元素的值%d\n", p_num, num, 
*p_num);printf("p_num访问第一个元素=%d\n", p_num[0]);printf("p_num访问第二个元素=%d\n", p_num[1]);return 0;}

运行结果:

p_num指针的值=000000000061FE00 ,num的地址是=000000000061FE00  p_num对应数组元素的值1

p_num访问第一个元素=1 p_num访问第二个元素=2


6.4 数组作为函数参数

函数参数不仅可以是变量,也可以是数组,数组作函数参数的作用是将数组首元素地址传给函数作形参。 在 C 语言中,数组作函数参数时,是没有副本机制的,只能传递地址。也可以认为,数组作函数参数时,会退化为指针

#include <stdio.h>
void getSize(int nums[10]) // 定义 getSize 函数
{int size = sizeof(nums); // 计算数组 nums 的总字节数printf("指针 size=%d\n", size);
}
int main(void)
{int nums[10] = { 1, 2, 3, 4, 5 };int size = sizeof(nums); // 计算数组 nums 的总字节数printf("外部 size=%d\n", size);getSize(nums); // 调用 getSize 函数return 0;
}

 运行结果:

外部 size=40

指针 size=8

所以直接把函数的形参的类型设置为指针,来接收数组的第一个地址: 

#include <stdio.h>
void getSize(int* nums) // 定义 getSize 函数
{int size = sizeof(nums); // 计算数组 nums 的总字节数printf("指针 size=%d\n", size);
}
int main(void)
{int nums[10] = { 1, 2, 3, 4, 5 };int size = sizeof(nums); // 计算数组 nums 的总字节数printf("外部 size=%d\n", size);getSize(nums); // 调用 getSize 函数return 0;
}

运行结果:

外部 size=40

指针 size=8

分析:

32位系统中指针变量占4个字节,64位系统中指针变量占8个字节,所以getSize中num的字节数是8。在 C 语言中,数组作函数参数时,是没有副本机制的,只能传递地址,所以 的形参 int *nums应该是指针变量, void getSize方法 getSize(nums) 传入的nums并不是数组的副本,而是数组首元素的地址 

注意:因为没有副本机制,所以如果在函数内部修改数组内容,数组的内容会直接被修改,而不是修改副本

#include <stdio.h>
void getSize(int* nums) // 定义 getSize 函数
{nums[0] = 3;
}
int main(void)
{int nums[10] = { 1, 2, 3, 4, 5 };printf("%d\n", nums[0]);    //加\n是为了换行getSize(nums); // 调用 getSize 函数printf("%d", nums[0]);return 0;
}

练习:封装比较数组最大值函数

#include <stdio.h>
int getMax(int* nums, int length) // 定义函数 getMax
{int i;int max = nums[0]; // 默认 nums[0] 为最大值for (i = 1; i < length; i++) // 下标从 1 开始遍历{if (max < nums[i]) // 比较大小{max = nums[i]; // 覆盖最大值}}return max; // 返回最大值
}int main(void)
{int nums[10] = { 11, 22, 3, 24, 15, 8, 99, 21, 35, 0 };int length = sizeof(nums) / sizeof(nums[0]); // 计算数组长度int max = getMax(nums, length); // 返回最大值printf(" 最大值为 :%d\n", max);return 0;
}

7 二维数组以及字符串与指针

7.1 二维数组的定义方法

C语言中二维数组和一维数组类似,简单理解就是:二维数组由多个一维数组构成

7.1.1 定义一个二维数组 

type arrayName[x][y];

例:

int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

内部嵌套的括号是可选的,下面的初始化与上面是等同的:

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

7.1.2 访问二维数组

#include <stdio.h>
#include <string.h>
void main(void)
{int a[3][4] = { {1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23} };printf("a[0][2]=%d", a[0][2]);
}

运行代码:

a[0][2]=5


7.2 定义字符串的几种方法

我们已经学习的定义方法:

#include <stdio.h>
int main(void)
{char chs1[] = { 'i', 't', 'y', 'i', 'n', 'g', '\0' };char chs2[] = "itying";printf("%s\n", chs1);// 以 %s 格式输出 strprintf("%c\n", chs1[2]); // 以 %c 格式输出一个字符printf("%s\n", chs2);  // 以 %s 格式输出 strprintf("%c", chs2[2]); // 以 %c 格式输出一个字符return 0;
}

我们也可以使用字符指针引用字符串:

#include <stdio.h>
int main(void)
{char chs1[] = "itying";char* str1 = chs1;printf("%s\n", str1);  // 以 %s 格式输出 strprintf("%c\n", str1[2]);   // 以 %c 格式输出一个字符
//---------------------------------------------------------------------------char* str2 = "this is str";printf("%s\n", str2);  // 以 %s 格式输出 strprintf("%c\n", str2[2]); // 以 %c 格式输出一个字符return 0;
}

通过上面示例我们可以通过三种方法定义字符串了

char chs1[] = {'i', 't', 'y', 'i', 'n', 'g', '\0'};
char chs2[] = "itying";
char *chs3 = "itying";

7.3 字符串数组

定义了一个指针数组,即数组中的每个元素都是一个 char 类型的指针:

char *arr[] 

例:

char *s[]={ "马总", "张总", "王麻子" };

当使用 { "马总", "张总", "王麻子" } 对这个数组进行初始化时,会把每个字符串常量的首字符地址分别赋给数组 arr 的各个元素:

  • arr[0] 被赋值为字符串 "马总" 的首字符地址,通过这个指针,就可以访问该字符串的所有字符
  • arr[1] 被赋值为字符串 "张总" 的首字符地址
  • arr[2] 被赋值为字符串 "王麻子" 的首字符地址

    在实际处理中文时,通常会使用多字节字符编码,比如常见的 UTF - 8 编码或 GBK 编码

    UTF - 8 是一种变长编码,一个中文字符通常用 3 个字节来表示。对于字符串 "张总",“张” 字在 UTF - 8 编码下会占用 3 个字节的存储空间,arr[1] 指向的就是这 3 个字节中第一个字节的存储地址


    7.4 strcat 连接字符串

    前面我们已经学习了 strlen 计算字符串数组有效长度、sprintf 字符串格式化函数、字符串拼接、整型转换成字符串等字符串知识,详细见【C语言】第七期——字符数组、字符串、类型转换

    现在我们继续学习相关知识

    原型:

    char *strcat(char *dest, const char *src);    //使用前需先引入头文件<string.h>

    参数:

    • dest:目标字符串的指针,拼接后的结果将存储在这个字符串中。dest 必须有足够的空间来容纳 src 字符串的内容以及拼接后的结果
    • src:源字符串的指针,它将被追加到 dest 字符串的末尾。src 字符串本身不会被修改

    返回值:

    函数返回一个指向目标字符串 dest 的指针

    工作原理:

    strcat 函数会从 dest 字符串的第一个空字符 '\0' 开始,将 src 字符串的内容复制到 dest 的末尾,直到遇到 src 字符串的空字符 '\0' 为止,最后,dest 字符串会以空字符 '\0' 结尾

    #include <stdio.h>
    #include <string.h>int main() {// 定义目标字符串和源字符串char dest[50] = "Hello, ";const char src[] = "World!";// 使用 strcat 函数将 src 追加到 dest 的末尾strcat(dest, src);// 输出结果printf("拼接后的字符串: %s\n", dest);return 0;
    }

    注意事项:

    • 内存空间:dest 数组必须有足够的空间来容纳 src 字符串的内容,否则会导致缓冲区溢出,这可能会引发程序崩溃或安全漏洞
    • 空字符:dest 字符串必须以空字符 '\0' 结尾,否则 strcat 函数无法确定从哪里开始追加
    • 字符串重叠:dest 和 src 所指向的字符串不能重叠,否则会导致未定义行为

    7.5 strcpy 字符串复制(拷贝)函数

    原型:

    char *strcpy(char *dest, const char *src);

    参数:

    • dest:指向目标字符数组的指针,用于存储复制后的字符串。目标数组必须有足够的空间来容纳源字符串及其终止的空字符 '\0'
    • src:指向源字符串的指针,即要被复制的字符串。该参数被声明为 const,表示在函数内部不会修改源字符串

    返回值:

    strcpy 函数返回指向目标字符数组 dest 的指针

    工作原理:

    strcpy 函数会将 src 指向的字符串(包括终止的空字符 '\0')复制到 dest 指向的字符数组中

    复制过程会一直进行,直到遇到源字符串的终止空字符 '\0',并将该空字符也复制到目标数组中

    #include <stdio.h>
    #include <string.h>int main() {// 定义源字符串char src[] = "Hello, World!";// 定义目标字符数组,确保有足够的空间char dest[20];// 使用 strcpy 函数复制字符串strcpy(dest, src);// 输出复制后的字符串printf("Copied string: %s\n", dest);return 0;
    }

    注意事项:

    • 缓冲区溢出风险:使用 strcpy 时需要确保目标数组有足够的空间来容纳源字符串及其终止空字符,否则可能会导致缓冲区溢出,引发未定义行为,为了避免这种风险,可以使用更安全的 strncpy 函数
    • 目标数组的初始化:在使用 strcpy 之前,不需要对目标数组进行初始化,因为 strcpy 会覆盖目标数组中的原有内容

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

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

    相关文章

    SpringBoot——生成Excel文件

    在Springboot以及其他的一些项目中&#xff0c;或许我们可能需要将数据查询出来进行生成Excel文件进行数据的展示&#xff0c;或者用于进行邮箱发送进行附件添加 依赖引入 此处demo使用maven依赖进行使用 <dependency><groupId>org.apache.poi</groupId>&…

    mac 下 java 调用 gurobi 不能加载 jar

    在 mac 电脑中的 java 始终不能加载 gurobi 的 jar 包&#xff0c;java 的开发软件 eclipse&#xff0c;idea 总是显示找不到 gurobi 的 jar 包&#xff0c;但是 jar 包明明就在那里。 摸索了三个小时&#xff0c;最后发现原因竟然是&#xff1a; jar 包太新&#xff0c;替换…

    服务端配置TCP探活,超出探活时间后的行为?

    server端启动 &#xff08;完整源码在最后&#xff09; 配置探活 setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){5}, sizeof(int)); // 空闲60秒后探测setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){10}, sizeof(int)); // 探测间隔10秒…

    LLC谐振变换器恒压恒流双竞争闭环simulink仿真

    1.模型简介 本仿真模型基于MATLAB/Simulink&#xff08;版本MATLAB 2017Ra&#xff09;软件。建议采用matlab2017 Ra及以上版本打开。&#xff08;若需要其他版本可联系代为转换&#xff09;针对全桥LLC拓扑&#xff0c;利用Matlab软件搭建模型&#xff0c;分别对轻载&#xf…

    MySQL 中如何查看 SQL 的执行计划?

    SQL 语句前面使用 EXPLAIN 关键字&#xff1a; EXPLAIN SELECT * FROM users WHERE id 1; 字段 含义 id 查询的序号&#xff08;如果是子查询或联合查询&#xff0c;会有多个 id&#xff09;。 select_type 查询的类型&#xff08;简单查询、子查询、联合查询等&#xff…

    Discourse 中集成 Claude 3.7 Sonnet 模型

    如果 Discourse 实例已经接入了 Anthropic。 那么只需要在后台挑一个不希望继续使用的模型改下就好。 否则需要重新在 Discourse 实例中配置 AI&#xff0c;然后获得 Anthropic 的 key。 进入后台的 AI 然后选择 LLMs 虽然我们这里已经显示成 3.7 了&#xff0c;但实际上所有…

    Oracle 12c Docker安装问题排查 sga_target 1536M is too small

    一、问题描述 在虚拟机环境&#xff08;4核16GB内存&#xff09;上部署 truevoly/oracle-12c 容器镜像时&#xff0c;一切运行正常。然而&#xff0c;当在一台 128 核 CPU 和 512GB 内存的物理服务器上运行时&#xff0c;容器启动时出现了 ORA-00821 等错误&#xff0c;提示 S…

    DeepSeek 提示词:高效的提示词设计

    &#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

    KIMI K1.5:大规模强化学习在大语言模型中的应用与工程实践

    目录 1、核心技术创新:长上下文强化学习 2、策略优化的技术细节 2.1、在线镜像下降变体 2.2、长度惩罚机制 2.3、智能采样策略 3、工程架构创新 3.1、混合部署框架 3.2、代码沙箱与奖励模型 3.3、分布式系统架构 4、实验成果与性能提升 5、结论与未来展望 大语言模…

    从 0 到 1:使用 Docker 部署个人博客系统

    引言 在当今数字化时代&#xff0c;拥有一个个人博客来记录自己的学习、生活和见解是一件非常有意义的事情。然而&#xff0c;传统的博客部署方式往往涉及复杂的环境配置和依赖管理&#xff0c;容易让人望而却步。而 Docker 的出现&#xff0c;为我们提供了一种简单、高效的解…

    多进程网络服务端详细说明文档

    多进程网络服务端详细说明文档 一、概述 本项目实现了一个基于多进程的 TCP 网络服务端&#xff0c;主要用于处理多个客户端的连接请求。为了提高代码的可维护性和可复用性&#xff0c;分成了头文件&#xff08;.h&#xff09;和多个源文件&#xff08;.cpp&#xff09;。具体…

    HDFS数据多目录、异构存储、回收站

    1.NameNode元数据多目录 HDFS集群中可以在hdfs-site.xml中配置“dfs.namenode.name.dir”属性来指定NameNode存储数据的目录&#xff0c;默认NameNode数据存储在${hadoop.tmp.dir}/dfs/name目录&#xff0c;“hadoop.tmp.dir”配置项在core-site.xml中。 我们也可以将NameNod…

    TFChat:腾讯大模型知识引擎(DeepSeek R1)+飞书机器人实现AI智能助手

    效果 TFChat项目地址 https://github.com/fish2018/TFChat 腾讯大模型知识引擎用的是DeepSeek R1&#xff0c;项目为sanic和redis实现&#xff0c;利用httpx异步处理流式响应&#xff0c;同时使用buffer来避免频繁调用飞书接口更新卡片的网络耗时。为了进一步减少网络IO消耗&…

    HTML5 面试题

    1. HTML5 新增了哪些重要特性&#xff1f; 语义化标签&#xff1a;这些标签有助于提高页面的可读性和可维护性。多媒体支持&#xff1a;HTML5 引入了 和 标签&#xff0c;可以直接嵌入音频和视频文件&#xff0c;无需依赖插件。本地存储&#xff1a;引入了 localStorage 和 se…

    【Linux】Linux常用命令

    目录 文件和目录相关命令查看和管理进程磁盘和文件系统管理用户和权限管理网络相关命令文本处理命令系统状态查看命令软件包管理命令计划任务和后台作业其他常用命令 1. 文件和目录相关命令 命令作用示例pwd显示当前工作目录pwdls列出目录内容ls -l 查看详细信息cd切换目录cd…

    布署elfk-准备工作

    建议申请5台机器部署elfk&#xff1a; filebeat(每台app)--> logstash(2台keepalived)--> elasticsearch(3台)--> kibana(部署es上)采集输出 处理转发 分布式存储 展示 ELK中文社区: 搜索客&#xff0c;搜索人自己的社区 官方…

    DeepSeek:我的AI助手之旅

    ★【前言】: 初次使用AI助手帮我写作,就像摸石头过河一样,一点点的前行。我在慢慢的摸索,慢慢的体会中,感悟出的一点个人心得体会现分享给大家。这也说明一个问题,网站上各种使用方法和技巧是对于已经使用过的人来说的方便和快捷,但对于刚刚接触的使用者来说,网上的各…

    esp8266 rtos sdk开发环境搭建

    1. 安装必要的工具 1.1 安装 Git Git 用于从远程仓库克隆代码&#xff0c;你可以从Git 官方网站下载 Windows 版本的安装程序。安装过程中可保持默认设置&#xff0c;安装完成后&#xff0c;在命令提示符&#xff08;CMD&#xff09;或 PowerShell 中输入git --version&#…

    C# | GDI+图像测距辅助线的实现思路

    C# | GDI图像测距辅助线的实现思路 文章目录 C# | GDI图像测距辅助线的实现思路一、辅助线需求概述二、坐标系与角度计算2.1 笛卡尔坐标系2.2 线长和角度计算方法2.3 文本角度矫正计算方法2.4 坐标变换实现步骤 三、与if判断方式对比四、总结 一、辅助线需求概述 在图像测量工…