C语言字符串(0基础到深入剖析)---字符串系列合集(函数+指针+数组)

前言

本篇旨在帮助不了解字符串或者逻辑梳理不够透彻的伙伴们理出一条脉络。选择能看懂的部分即可,建议收藏,后期学习完C语言方便回顾

适用范围:0基础C语言(刚学字符串)- 学过函数 - 学过指针 ---大致了解了数据内存(栈、堆、静态区、常量区) --- C语言语法大成者。

只是梳理逻辑,代码相对简单,对字符串的算法题型(洛谷,力扣)不涉及

这里不在赘述字符,字符数组的东西了。因为最开始学数据类型和数组时已经

  我们知道C语言中字符串是一种重要的数据类型,它的一些相关特点我们将在本篇重新介绍梳理,C库提供了大量的字符串函数供我们操作,比如strlen就是计算字符串长度的函数。后面还有大量的字符串函数,比较字符串,拷贝字符串,查找字符串的有关函数。还有通过指针模拟实现一些函数,以此熟悉。

字符串概念

几乎每C相关的书籍都会都会单独为字符串开设一篇专题,可见字符串的重要性可见一般。前面有提过字符(char )和字符数组(char []);常量字符串和变量字符串的概念是否了解呢?

这里整合字符串一系列的知识,处理字符串的便捷方法。

引入(两个疑问)

0.空字符是以下哪个?

'\0'     '0'    ' '

这里的空指的是null ,即对应ASCII十进制为0的字符,是'\0'

后面'0'是字符0,' '是空格字符。

#include<stdio.h>
int main(void)
{
    printf("%d %d %d", '\0', '0', ' ');
    return 0;
}

1.字符串和字符的关系?

字符是形如a,b,c,!,@,.,/的一系列符号。在C中用单引号括起来,如char s1 = 'a' ;

字符串顾名思义就是一串字符,即字符的序列。只不过术语称其为“字符串”。

2.字符串和字符数组的关系?

字符串在C中特指以双引号引起来的字符序列。如"abcd",需要注意的是这种写法会默认最后补上一个null(空字符)。

从C来说,它会将字符串当作字符数组处理,即如果一个字符串长度为n就为其开辟n+1的内存空间,(多的1放'\0')。结论是字符串是字符数组,而通过前面的学习知道一般的字符数组不一定是字符串。

既然字符串被当作数组存储,那么对于一个字符串"abcd",编译器会将其视为char* 的指针。

char* p = "abcd";

"abcd"是字符数组,那么上面的语句就是将首元素的地址赋值给字符指针p;

至于"abcd"具体存储内存那个位置,下面再谈。

一、字符串表示(概念)

字符串是'\0'结尾的char类型的数组。'\0'称为空字符,这个我们初学C语言了解字符串已经知道了。

如下图,如果以这样的方式初始化一个字符数组,末尾有'\0'就是字符串, 没有末尾的空字符,这个数组单纯就是一般的字符数组。

#define N 20
const char arrary[N] = {'h','e','l','l','o',' ','w', 'o','r','l','d','\0'};
char arrary2[] = "hello world";
char* arr = "hello world";

 双引号括起来的内容也是字符串,叫常量字符串(字符串常量)。双引号内的字符和编译器结尾默认添加空字符,都将字符串存储在内存中。

由于双引号引起来的后面默认添加'\0',如果存储在字符数组中,请确保实际数组元素个数比引起来的字符个数至少多一。如果字符数组空间足够大,则双引号为填充完的部分默认都为'\0'。

首先我们要了解常量字符串是在静态储存区(常量区),这意味着使用在常量字符串会在内存中存储一次。常量字符串的生命周期是变量被存储到程序结束。

Q:怎么证明常量字符串只被存储一次呢?

声明两个字符指针变量同时指向它,如果它被存储一次,说明两个指针指向同一个内存块(存储的地址相同),那么可以进行指针减法,且结果为零。

#include<stdio.h>
int main()
{
    char* arr1 = "abcd";
    char* arr2 = "abcd";
    printf("%d", arr2 - arr1);
    return 0;
}

需要注意的是,两个指针在main函数声明创建,是在栈区。它们指向(存储)的地址是常量区的常量字符串(实际存储的是常量字符串首字符的地址) 。

char arrary2[] = "hello world";
char* arr = "hello world";

如果将这个用第一种方式,理解为创建一个arrary2字符数组向内存申请空间,将常量字符串的内容拷贝一份,这么写数组大小交给编译器确定,否则请确保数组元素个数大于字符串中已经填入的字符个数。(编译器后面会添加'\0',至少数组元素个数要比字符数多一)

事实上,常量字符串(双引号括起来的部分被视为指向该字符串的指针),所以第二种方式就可以理解了。这里意思是让arr指向字符串中的第一个字符。

第一种和第二种它们的位置是一样的吗?

显然不是,一个在栈,另一个在静态区

如果不了解栈堆静态区,可以了解C语言动态内存分配,C/C++数据在内存中的分布

字符串与数组

一种对于字符串当作数组的理解

#include<stdio.h>
int main(void)
{
    for (int i = 0; i < 4; i++)
    {
        printf("%c ", "abcd"[i]);
    }
    return 0;
}

 字符串被视为字符数组,同样可以用处理数组的方式处理它。"abcd"当作这个字符数组的数组名,也就是数组首元素的地址。可以用下标引用操作符和指针+整数来访问字符串中的每一个字符。


#include<stdio.h>
int main(void)
{
    for (int i = 0; i < 4; i++)
    {
        printf("%c ", *("abcd"+i));
    }
    return 0;
}

 把字符数组当作字符串处理的难处

有些编程语言为字符串单独开了一个数据类型string,很遗憾,根据现在我们了解。C语言并没有字符串类型,而是把它当作数组类型。

用字符数组来处理字符串,可能有以下问题。

1.字符数组最后一个元素必须为空字符。

2.如果字符串长度确定,确保字符数组空间至少大一,确保每个字符数组以空字符结尾。

由于C中关于字符串函数都有'\0'的标志结尾,如果不注意空字符,很容易在调用这些函数上出问题。记住字符串函数是用来处理字符串的,不能用来处理一般的字符数组。

字符数组和字符指针

指针篇曾回答了下列问题,先看一下下面的图片,稍后补充一些东西。

 这里提供了我们操作字符串的另一种方式,即通过字符指针的形式。

比如上面的p1就指向"hello world",就可以访问字符串了,只是不能修改字符串常量中的字符。

这里建议用const强调一下。 const char* p1 = "hello world";

第二种就是字符指针指向用字符数组处理的字符串,即p2。这里就可以将p2作为字符串任意使用了。这里p2指向的是定长数组arr,还可以让p2指向动态内存分配的字符串。

字符串与函数

一、字符串“最好用”的两个IO函数gets , puts(适合C语言萌新)

据说每一个C语言新手都要掌握的6个(I/O)函数:

printf      scanf

gets       puts

getchar putchar

1.1  输入函数(Input)

1.1.1 "单词函数"scanf函数

转换说明%s,可以将字符串写入字符数组,或者动态分配的内存空间。

通过下面说明scanf输入字符串的问题。

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    char* p = (char*)malloc(sizeof(short) * 10);
    scanf("%s", p);
    puts(p);
    return 0;
}

尝试在屏幕上输入 hello world

观察结果

按理说puts应该打印hello world。结果却不如所愿,这说明scanf读到空格就不往后读了 。整行输入只读到前面hello这个单词。scanf函数处理不了类似英语中的句子短语,只能处理小小的单词。

所以称其为"单词输入"函数。

scanf函数在输入时会跳过最开始的空格,开始往后读字符直到遇到空字符,换行符,制表符。会在读入最后的一个字符后面补上'\0',确保其是字符串。

按回车键会立刻结束输入。

scanf的缺点:通常不能读入整行输入,遇到空格符就不读了。

这个时候就需要gets函数来解决这个问题了。

1.1.2 "抛开缺点不谈巨好用"的gets函数

标准输入是什么?

简单理解就是从键盘上获取数据。

参数是字符指针,逐字符从键盘上读取(可以读取空字符),将其放入数组内或者动态分配的内存。按回车键停止输入。

gets不会像scanf跳过最开始的空白字符,一直读取字符直到遇到换行符。

读到换行符停止读取,并将换行符丢弃换成空字符。确保是字符串。

gets和puts天生一对,基本上配对使用。后面会说明puts函数。

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    char* p = (char*)malloc(sizeof(short) * 10);
    gets(p);
    puts(p);
    return 0;
}

 

 gets函数的问题

你可能关注到上面的文字,已经逐步取消了gets函数的使用。这里说明原因:

gets传入参数的字符指针合法使用的空间不知道,极有可能越界访问。比如上面开辟了20字节的空间,可以合法输入19个字符,最后一个放空字符。但大多数情况我们不知道空间是多少,稍不注意就越界了。如果出现字符串过长,就会有缓冲区溢出的问题。如果占有的未分配的空间,问题还不算大;如果占有另外已经使用的空间,可能会引起严重程序事故。

你可能要问scanf不会出现字符串过长的问题吗?

只用%s可能出现问题,但可以用%.ns指定scanf读取的最大字符数,避免出现越界访问。

可惜gets天生不安全。虽然C标准取消了gets,但多数编译器照顾以前的代码还是能使用gets函数。

gets只要注意不越界就是即看即用,参数简单,输入字符串非常方便的函数。

总结:gets函数很方便,会使用,注意避免出现问题即可。

1.1.3 "文件操作"的fgets函数(优化了gets,但变复杂了)

由于gets不能指定输入最大字符数,所以fgets加入参数限制了读入字符个数。

第一个参数:同gets

第二个参数:读入字符的最大数量,实际读入num-1个字符,最后一个放空字符

第三个参数:文件指针,本质是结构体指针,这里你认为默认stdin(标准输入流) 即可。

标准输入流认为从输入设备(键盘)读取数据。

关于fgets函数更常见使用在C文件操作那一块。

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    char* p = (char*)malloc(sizeof(short) * 10);
    fgets(p,6,stdin);
    puts(p);
    return 0;
}

1.2输出函数(Ouput)

1.2.1 老朋友printf函数

printf提供转换说明%s,格式化打印字符串。我们以现在的视角重新观察以下代码。

#include<stdio.h>

int main(void)
{
    char arr[20]="What can I say";
    printf("%s\n",arr);
}

 printf的第二个参数传的是地址,打印结束条件是'\0'。printf格式化打印字符串的功能是从当前起始位置逐个写入字符到格式化字符串并往下继续写直至遇到'\0',最后写入完毕打印格式字符串到屏幕上。

#include<stdio.h>

int main(void)
{
    char arr[20]="What can I say";
    char* p=arr+5;
    printf("%s\n",p);
}
1.2.2 “神中神”puts函数

printf并不是唯一一个能输出字符串的函数,C库提供了一个更完美的函数puts。

这里功能已经说明很清楚了,需要传入字符串的地址。可以用字符指针或者字符数组的形式。

1.stdout标准输出,如果不了解就简单认为是打印到显示屏上。

2.打印完毕会自行换行,不用像printf那样额外加入'\n' 

示例

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    char* s1 = "hello world";
    puts(s1);
    printf("haha");
    return 0;
}
1.2.3 文件操作 fputs函数

这个放文件操作说明。这里大致说一下fputs函数怎么用。

 FILE* 是文件指针,stream是流。不清楚没关系,意思是fputs函数可以指定输出设备,就不止是输出到屏幕上,还可以是文件等。第一个参数和返回值和puts一样。

如果我们还想要打印到屏幕上,那么第二个参数就是stdout标准输出流。

还有一个点fputs在输出完毕后不会加上换行符,这也是和puts的一个区别

#include<stdio.h>
int main(void)
{
    char* s1 = "hello world";
    fputs(s1,stdout);
    printf("hehe");
    return 0;
}

二、(处理)字符串的常用函数

字符串长度:字符串的首个字符到'\0'之前的那个字符的长度,strlen计算的结果就是字符串的长度。

下面说明处理字符串的10个常见函数。以下仅针对字符串,必须'\0'结尾的字符数组。

2.1strlen函数

size_t strlen (const char* str)

1.strlen求字符串的长度,统计'\0'前面的字符个数。

2.返回类型是size_t ,size_t是无符号整型。

3.包含头文件:string.h

忽视返回类型size_t的错点

看完下面代码,尝试回答一下。

#include <stdio.h>
int i;
int main()
{
    i--;
    if (i > sizeof(i))
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
    return 0; 
}

 结果是>,为什么呢?

首先全局变量我们不初始化它,默认初始化为0,i--之后,i变为-1。我们知道sizeof(变量名),计算的是变量名的类型,单位是字节,但是sizeof返回类型是size_t。它是一个无符号整型。

不同数据类型进行运算要先转换成同一类型。显式整型转换我们了解(不了解的话可以查一下显隐式类型转换和整型提升的内容,还有二进制),这里涉及到另一种,隐式类型转换。i为int类型(有符号整型),size_t无符号整形,在表达式中比较,int会转换成unsigned int。这里i中-1在无符号整型会转化成很大的整数。

模拟strlen实现方法
1.计数法
size_t my_strlen(char* p)
{
	size_t count = 0;
	while (*p != '\0')
	{
		p++;
		count++;
	}
	return count;
}
2.指针-指针
size_t my_strlen(const char* p)
{
    char* src = p;//记录初始位置
    char* dst = p;//遍历到'\0'的位置
    while (*dst)
    {
        dst++;
    }
    return dst - src;//终点减起点即结果。
}

3.函数递归
#include<assert.h>
#include<stdio.h>
size_t my_strlen(char* p)
{
	assert(p != NULL);
	if (*p != '\0')
		return 1 + my_strlen(p + 1);
	return 0;
}



int main()
{
	char arr[] = "abcdef";
	size_t len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

 铺垫

接下来说明三个处理字符串的函数以及与之对应另外三个函数

strcpy,strcat,strcmp

strncpy,strncat,strncmp

如何记住这些函数的功能呢?

下面请看每个函数的详解

2.2strcpy函数

char* strcpy(char* destination,const char * source );

功能将源字符串拷贝到目标字符数组上。

1.soure必须为字符串,确保有'\0'。

2.destination必须有足够大的空间够拷贝。

3.该函数返回目标字符数组首元素的地址。

4.目标字符指针不得指向常量字符串,即它能被修改。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
    char arr[20]="hello world";
    char* p=(char*)malloc(20);
    puts(strcpy(p,arr));
}
模拟strcpy实现 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

char* my_strcpy(char* dst, const char* src)
{
    assrty(dst && src);
    char* ret = dst;//记录当前目标空间的起始地址
    while (*src != '\0')
    {
        *dst = *src;
        dst++;
        src++;
    }
    *dst = '\0';//结尾放'\0'
    return ret;//返回目标字符串的起始地址
}
int main(void)
{
    char arr[20] = "hello world";
    char* p = (char*)malloc(20);
    puts(my_strcpy(p, arr));
}


 2.3strcat函数

char * strcat ( char * destination, const char * source );

形式和strcpy一致。

该函数实现的功能:将源字符串添加到目标字符串的末尾

1.返回值:返回目标字符串的地址

2.destination要有足够大的空间追加源字符串。

3.目标空间必须可修改。

4.不能自己和自己追加,目标空间和源空间不能有重叠。

#include<stdio.h>
#include<string.h>
int main()
{
    char arr[80];
    strcpy(arr,"Good");
    strcat(arr," Morning!");
    strcat(arr,"\nhello ");
    strcat(arr,"world\n");
    printf("%s",arr);
    return 0;
}

 

 尝试自己与自己追加,strcat函数内部死循环了后非法访问内存,程序崩溃了。

 

 模拟实现strcat
char* my_strcat(char* dst, const char* src)
{
    assert(dst && src);
    char* ret = dst;
    while (*dst != '\0')//先找到目标字符串的'\0'
    {
        dst++;
    }
    while (*src != '\0')//从目标字符串的'\0'处开始追加字符。
    {
        *dst++ = *src++;
    }
    *dst = '\0';//末尾补上'\0'确保是字符串。
    return ret;//返回目标字符串的起始地址
}

2.4strcmp函数

strcmp函数的比较原理:

比较两个参数字符串的对应位置的字符大小(比较对应的ASCII码值) 

"abc"和"eq",先比较a和e,由于字符e的ASCII码值大于a所以返回负值。

"abc"和"abc",依次比较,a和a,b和b,c和c,最后'\0'和'\0',空字符了,比较结束,返回0。

示例

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


int main()
{
    char arr1[20] = "abcdef";
    char arr2[20] = "abq";
    printf("%d", strcmp(arr1, arr2));
    return 0;
}

 模拟实现strcmp
int my_strcmp(const char* dst, const char* src)
{
    assert(dst && src);
    while (*dst++ == *src++)
    {
        if (*dst == '\0')
            return 0;
    }
    return *dst - *src;

}

2.5strncpy函数

char * strncpy ( char * destination, const char * source, size_t num );
功能和strcpy一样,只不过有长度限制,多了一个参数num来限制拷贝源字符串的字符个数。
如果源字符串的字符个数小于num,则拷贝完源字符串往后继续补'\0'直到个数满足num。

2.6strncat函数

char * strncat ( char * destination, const char * source, size_t num );
功能和strcat一样,也限制了长度,也是多一个参数num来限制追加字符的个数
如果源字符串的字符个数小于num,则追加完源字符串往后继续补'\0'直到个数满足num。
#include <stdio.h>
#include <string.h>
int main()
{
    char str1[20];
    char str2[20];
    strcpy(str1, "To be ");
    strcpy(str2, "or not to be");
    strncat(str1, str2, 6);
    printf("%s\n", str1);
    return 0;

2.7strncmp函数

int strncmp ( const char * str1, const char * str2, size_t num );
比较指定前num个字符。和strcmp功能相似,可以指定比较多少位。
strcmp一一比较对应的字符,直到的发现不同。完全相同返回0,有任一一位不同返回非0。(正负取决参数的位置,和相应位的ASCII码值)。
如果num均大于等于两个字符串各自总个数,功能就和strcmp完全一样了。

2.8strstr函数

char * strstr ( const char * str1, const char * str2);

功能在str1中查找str2,在一个字符串中查找另一字符串。

返回值:返回字符串str2在字符串str1第一次出现的位置。若没找着则返回空指针。

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

int main()
{
    char* p1="Hello";
    char* p2="el";
    char* ret = strstr(p1,p2);
    printf("%s",ret);
    return 0;
}

 

 模拟实现有点复杂,可以看一下KMP算法。

char* my_strstr(const char* str1,const char* str2)
{
    assert(str1 && str2);
    const char* s1=NULL;
    const char* s2=NULL;
    const char* cur = str1;
    if(*str2=='\0')
    return (char*)cur;
    while(*cur)
    {
        s1 = cur;
        s2 = str2;
        while(*s1!='\0'&&*s2!='\0'&&*s1==*s2)
        {
            s1++;
            s2++;
        }
        if(*s2=='\0')
        return (char*)cur;


        cur++;
    }
    return NULL;
}

2.9strtok函数

下面一篇写得足够详细,我们只需要知道如何使用strtok函数即可,不需要掌握模拟实现。

字符分割函数strtok-CSDN博客

3.0streeror函数

char * strerror(int errnum);

头文件:string.h

 这个函数可以把参数部分对应的错误码信息的字符串地址返回来。

在不同系统和C语言标准库的实现中都规定了一些错误码,一般是放在errno.h这个头文件中说明的C语言程序启动的时候会用一个全局变量errno来记录程序的错误码,程序启动时,errno的值为0,表示没有错误,如果我们使用标准库函数的时候发生了一些错误,就会将相应的错误码存放到errno中,而一个错误码都有对应的错误信息,strerror函数就可以将错误信息的字符串返回。

 

 errno.h文件中的错误码信息,但我们并不知道这些错误码到底对应了什么,这个时候借助strerror

#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		printf("%s\n", strerror(i));
	}
}

打印 0~10的错误码信息,结果如下图,strerror会把错误信息的字符串地址返回,用printf打印到屏幕上。通过错误信息,我们就可以知道犯了哪些错误。

试着打印一遍所有错误码对应的错误信息吧。

下面只是提供一个例子,不需要掌握文件知识,只是了解一下文件打开失败,错误码的对应的错误信息

#define _CRT_SECURE_NO_WARNINGS 1
#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
	//以只读方式打开"test.txt",如果文件不存在则打开失败。
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读文件

	//关闭文件
	fclose(pf);
	return 0;

}

perror函数(推荐用这个函数) 

什么意思呢?

perror只要调用就可以自动打印errno错误码的信息,并且该函数的参数为字符指针,我们可以自己输入字符串(自定义消息),还是如下例子。

#define _CRT_SECURE_NO_WARNINGS 1
#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
	//以只读方式打开"test.txt",如果文件不存在则打开失败。
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");//改为perror函数
		return 1;
	}
	//读文件

	//关闭文件
	fclose(pf);
	return 0;

}

由此可见perror可以直接打印错误信息还可以自定义信息,而streeror还需要和printf配合。

功能上可以理解为 perror==printf+streeror;

perror先打印自定义信息(即perror参数部分的常量字符串),后面跟着冒号在打印错误码对应的错误信息。不想打印自定义信息可以输入空字符串

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos7 安装Git、使用

Centos7 安装Git 一、安装步骤1.1 查看版本1.2 卸载1.3 安装 二、创建仓库2.1 新增仓库2.2 新增配置项 三、管理文件3.1 文件创建3.2 文件修改、add、commit3.3 tree结构探索 四、分支4.1 创建分支&#xff1a;4.2 查看分支4.3 切换分支4.4 删除分支4.5 合并冲突 一、安装步骤 …

FusionMamba: Efficient Image Fusion with State Space Model【文献阅读】

论文&#xff1a;FusionMamba&#xff1a;一种基于SSM的有效图像融合方法 arXiv&#xff1a;https://arxiv.org/abs/2404.07932 作者单位&#xff1a;中国科学院自动化研究所、模式识别重点实验室、电子科技大学 推荐阅读&#xff1a;深入浅出一文图解Vision Mamba Abstract 图…

3.自动驾驶-局部路径规划

1. 规划planning 2. 局部路径规划模块实现-模块外围&#xff1a;输入 3. 局部路径规划模块实现模块外围:输出 4. 控制control 5. 系统分类 6 系统分类

C 认识指针

目录 一、取地址操作符&#xff08;&&#xff09; 二、解引用操作符&#xff08;*&#xff09; 三、指针变量 1、 指针变量的大小 2、 指针变量类型的意义 2.1 指针的解引用 2.2 指针 - 整数 2.3 调试解决疑惑 认识指针&#xff0c;指针比较害羞内敛&#xff0c;我们…

自定义SpringBoot的starter

案例需求&#xff1a;自定义redis-stater。要求当导入redis坐标时&#xff0c;SpringBoot自动创建Jedis的Bean。 实现步骤&#xff1a; 1、创建redis-spring-boot-autoconfigure模块 2、创建redis-spring-boot-starter模块&#xff0c;依赖redis-spring-boot-autoconfigure的…

Android 文件传输

经常写adb命令传文件&#xff0c;结果发现Android studio有自带的文件管理器&#xff0c;可以上传下载文件。

程序包的创建

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 前面很多范例中都用到的 dbms output.put_line 实际上就是一个典型的程序包应用&#xff0c; 其中 dbms output是程序包的名称&#xff0c;put_line 是该程序包中定义的一个…

碳纤维复合材料的纳米纤维膜

碳纤维复合材料的纳米纤维膜是一种具有良好性能和应用前景的新材料。以下是关于这种材料的详细介绍&#xff1a; 制备方法&#xff1a;碳纤维复合材料的纳米纤维膜可以通过多种方法制备&#xff0c;包括化学气相沉积法、固相合成法、模板法等。其中&#xff0c;化学气相沉积法是…

十三、大模型项目部署与交付

1 硬件选型 CUDA 核心和 Tensor 核心 CUDA 核心&#xff1a;是NVIDIA开发的并行计算平台和编程模型&#xff0c;用于GPU上的能用计算&#xff0c;可做很多的工作。应用在游戏、图形渲染、天气预测和电影特效Tensor 核心&#xff1a;张量核心&#xff0c;专门设计用于深度学习…

YOLOv5入门(四)训练自己的目标检测模型

前言 通过前面几篇文章&#xff0c;已经完成数据集制作和环境配置&#xff08;服务器&#xff09;&#xff0c;接下来将继续实践如何开始训练自己数据集~ 往期回顾 YOLOv5入门&#xff08;一&#xff09;利用Labelimg标注自己数据集 YOLOv5入门&#xff08;二&#xff09;处…

【PyTorch与深度学习】2、PyTorch张量的运算API(上)

课程地址 最近做实验发现自己还是基础框架上掌握得不好&#xff0c;于是开始重学一遍PyTorch框架&#xff0c;这个是课程笔记&#xff0c;这个课还是讲的简略&#xff0c;我半小时的课听了一个半小时。 1. 张量 1.1 张量操作 &#xff08;1&#xff09;chunk&#xff1a;将一…

华为手机ip地址怎么切换

随着移动互联网的普及&#xff0c;IP地址成为了我们手机上网的重要标识。然而&#xff0c;在某些情况下&#xff0c;我们可能需要切换手机的IP地址&#xff0c;以更好地保护个人隐私、访问特定地区的内容或服务&#xff0c;或者出于其他网络需求。华为手机作为市场上的热门品牌…

Kafka客户端工具:Offset Explorer 使用指南

Kafka作为一个分布式流处理平台&#xff0c;在大数据处理和实时数据流应用中扮演着至关重要的角色。管理Kafka的topics及其offsets对于维护系统稳定性和数据一致性至关重要。Offset Explorer是一个强大的桌面应用程序&#xff0c;它使得管理和监控Kafka集群变得简单直观。本文将…

2023 广东省大学生程序设计竞赛(部分题解)

目录 A - Programming Contest B - Base Station Construction C - Trading D - New Houses E - New but Nostalgic Problem I - Path Planning K - Peg Solitaire A - Programming Contest 签到题&#xff1a;直接模拟 直接按照题目意思模拟即可&#xff0c;为了好去…

【Unity】修改模型透明度

在 Unity 中修改模型透明度主要有两种方法&#xff1a;通过材质和通过着色器。以下是两种方法的步骤和解释&#xff1a; 方法 1&#xff1a;通过材质 在 Unity 编辑器中&#xff0c;选择你想要修改透明度的模型。在 Inspector 窗口中&#xff0c;找到模型的 Renderer 组件&am…

海康WEB3.3控件开发包 V3.3 前端vue项目调用实时监控画面

公司业务迭代, 需要前端vue项目里增加一个查看实时监控模块, 这个需求是之前离职的前端小哥没有研究明白的, 现在落在了我的肩上, 压力还是有的. 但是压力归压力, 问题还是要解决的. 一、调研设备和方案 第一步: 调研大佬们已经实现的方案, 找设备对接. 公司后端大佬提出用官…

Jenkins邮件发送失败问题解决

如下提示为 Extended E-mail Notification开启Debug模式下显示的错误信息&#xff0c; (Debug模式设置方法&#xff1a;Dashboard-> manage Jenkins->configure System)DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM XOAUTH2 DEB…

Unity3d 学习之按钮绑定事件

创建测试脚本 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class myTest : MonoBehaviour {// Start is called before the first frame updatepublic Button _codeBindBtn null;void Start(){if (_codeBi…

LeetCode 213 —— 打家劫舍 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题是 LeetCode 198—— 打家劫舍 的升级版&#xff0c;多了一个首尾相连的设定。 因为首尾相连&#xff0c;所以第一个房屋和最后一个房屋只能偷窃其中一个。 所以&#xff0c;第一种方案就是不偷窃最后一个房…

每日OJ题_DFS爆搜深搜回溯剪枝⑧_力扣980. 不同路径 III

目录 力扣980. 不同路径 III 解析代码 力扣980. 不同路径 III 980. 不同路径 III 难度 困难 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a; 1 表示起始方格。且只有一个起始方格。2 表示结束方格&#xff0c;且只有一个结束方格。0 表示我们可以走过的空…
最新文章