【C++】理解string类的核心理念(实现一个自己的string类)
目录
一、引言
二、自我实现
1.成员变量的读写
2.构造与析构
3.迭代器
4.插入字符或字符串
尾插
中间插入
5.删除字符或子字符串
6.查找字符或子串
7.获取子串
三、完整代码
四、补充
一、引言
实现自己的 string
类是学习 C++ 语言和面向对象编程的一个好方法。通过编写一个简单的字符串类,可以深入理解类的概念、内存管理、构造函数、析构函数等核心理念。理解了string类的底层逻辑之后会发现,一些在上层看似复杂的操作在底层其实很简单。下面就让我们来实现一个自己的string类吧!
二、自我实现
1.成员变量的读写
string是一个字符串类,所以我们在定义成员变量的时候需要一个char类型的指针,指向存放字符串的空间,为了方便实现对字符串的操作以及内存的管理,还需要定义两个整形变量,一个表示字符串长度,一个表示当前空间大小。
private:char* _str;size_t _size;size_t _capacity;};
这里定义成私有成员变量所以还需要使变量可读:
const char* c_str() const //const关键字进行函数重载,表示const对象也可以调用,不加则不行{return _str;}size_t size() const{return _size;}
这里的 const是一个关键字,作用是对函数进行重载,使其具有普通成员函数以及常量成员函数的双重身份,如果没有常量成员函数,那么常量对象就无法调用不带 const
修饰的成员函数,这可能导致在使用常量对象时的一些限制和不便。
我们需要重载[],完成对指定位置的字符的读或写操作:
char& operator[](size_t pos) //引用返回:返回值出了作用域任然存在,可读可写{assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const //const对象调用这个,只读{assert(pos < _size);return _str[pos];}
这里提供两个版本,一个是普通成员函数,一个是常量成员函数,之所以要分开写是因为他们的返回值类型不同,一个是可读可写,一个是只读不可写。
2.构造与析构
- 默认构造函数
string(const char* str = "") //全缺省,常量字符串末尾默认'\0':_size(strlen(str)),_capacity(_size),_str(new char[_capacity + 1]){strcpy(_str, str);}
其作用是创建一个 string
类对象,该对象的内部包含一个动态分配的字符数组 _str
,存储了传入的 C 字符串的内容,并且记录了字符串的长度 _size
和容量 _capacity
。我们调用无参构造函数时 _str
内部默认存在有字符 '\0'。'\0 '标记了字符串的末尾。
- 拷贝构造函数
string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}
这是一个字符串类的拷贝构造函数的实现。拷贝构造函数用于创建一个新的对象,并以另一个同类型对象的内容为模板进行初始化。具体来说,对于字符串类而言,这段代码的作用是创建一个新的字符串对象,并将其内容初始化为另一个字符串对象 s
的内容的副本。
这里的构造函数都是以深拷贝的方式实现,新对象拥有一个新的内存块,该内存块包含源对象或源字符串的副本。
- 析构函数
~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}
析构函数无需多言,需要注意的是 delete后面一定要加 [],表示释放的是一个字符串的空间。
3.迭代器
string类提供了迭代器(iterator)来遍历字符串的元素,迭代器是一种抽象的、通用的数据访问方式,它可以被用于遍历不同类型的数据结构。在string中,迭代器通常是一个指向字符的指针或类似指针的对象,这里我们模拟实现的是指针类型的迭代器:
//迭代器typedef char* iterator;typedef const char* const_iterator;
同样也有普通指针和常量指针两个版本
iterator begin(){return _str;}iterator end(){return _str + _size;} const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}
begin() 和 end()分别返回指向字符串首元素以及尾元素的后一位,由于返回值的不同,普通成员函数与常量成员函数要分开写。
其实实现了迭代器也就实现了基于范围的for循环,不信可以看看以下代码:
#include<iostream>
using namespace std;#include"string.h"void text_iterator()
{bit::string a("Hello world!");bit::string::iterator it = a.begin();while (it != a.end()){cout << *it;it++;}cout << endl;for (auto ch : a){cout << ch;}cout << endl;
}int main()
{text_iterator();return 0;
}
此时输出结果是:
看到了吗,两个循环的结果是一样的,我们没有做任何操作,就实现了基于范围的for循环诶,其实,实现了迭代器之后,第二个循环体与前一个循环体对编译器来看是一样的,这是给编译器设计好的,不需要我们进行多余的操作。
4.插入字符或字符串
在进行插入操作时,我们要先判断字符串的空间大小,如果插入的字符/字符串的长度大于所剩余的空间,就需要进行扩容,在string中,reserve成员函数实现上述功能:
//扩容void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;//可以直接指针复制,令两者指向同一块空间_capacity = n;}}
如果需要扩容,我们的做法是开辟一块新的空间,存放原字符串的副本,并且对原字符串进行空间释放,再进行指针复制,令_str指向新开辟的那块空间。
尾插
接下来就可以进行尾部插入字符或字符串的操作了:
//插入字符void push_back(char ch){if (_size == _capacity){//2倍扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';}
插入字符时,首先判断空间大小,空间不足则进行2倍扩容,要注意的是原字符串为空的情况,此时就不是2倍扩容了,而是给定一个初始大小的空间。插入一个字符不仅要对插入位置进行赋值,还要将它的下一位置赋值为'\0'。
//插入字符串void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){//至少扩容到_size+lenreserve(_size + len);}strcpy(_str + _size, str);_size += len;}
插入字符串的操作和插入字符类似。进行扩容操作之后用strcpy函数将要插入的字符串赋值到原字符串的末尾处。
我们在使用string类的时候经常会用到其重载后的+=操作,其作用是直接在str后面插入字符或字符串,很方便,其实实现起来也很简单,就是用到上述的插入函数:
string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}
中间插入
在string
类中,insert
函数用于在字符串的指定位置插入字符或字符串。
void insert(size_t pos, size_t n, char ch){assert(pos <= _size);if (_size + n < _capacity){//至少扩容到_size+nreserve(_size + n);}//挪动数据size_t end = _size;while (end >= pos && end != -1) //若pos为0呢?end!=-1{_str[end + n] = _str[end];--end;}for (size_t i = 0; i < n; i++){_str[pos + i] = ch;}_size += n;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len < _capacity){//至少扩容到_size+nreserve(_size + len);}//挪动数据size_t end = _size;while (end >= pos && end != -1) //若pos为0呢?end!=-1{_str[end + len] = _str[end];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}
同样要先判断空间大小,进行扩容操作。然后要进行数据的挪动,挪动的范围是pos到end位置,挪动的距离是n。这里要注意一个特殊情况,就是当pos为0时,也就是要将字符串整体向后移动时,标记当前挪动字符位置的变量end在对首字符挪动完之后,其值会自减为-1,但是end是一个无符号整形,因此此时的-1会被解释为该无符号整数的最大可能值,所以还有加上一个判断条件:end != -1。
5.删除字符或子字符串
在 string
类中,erase
函数用于从字符串中删除字符或子字符串。
void erase(size_t pos, size_t len = -1){assert(pos < _size);if (len == -1 || pos + len > _size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[pos++] = _str[end++];}_size -= len;}}
pos表示删除的起始位置,len表示删除的字符串的长度,len设置成缺省参数,默认为最大值,即pos位置后面的字符全删,当pos+len大于字符串长度时也是全删。全删很简单,只要将pos位置赋值为'\0'就可以了。此外就是删除内部的子串了,定义一个变量end用于标记要删除的子串的末尾,将end后面的字符依次覆盖到pos后面的字符处,即可完成删除操作。
6.查找字符或子串
string
类中的 find
函数用于在字符串中搜索子字符串或字符,并返回第一次出现的位置:
//找一个字符size_t find(char ch, size_t pos = 0){for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return -1;}//找一个字符串size_t find(const char* str, size_t pos = 0){const char* ptr = strstr(_str,str);if (ptr){return ptr - _str;}else{return -1;}}
查找操作很容易实现,只需要对字符串进行遍历,需要说明的是查找字符串操作时用到的 strstr
函数:C 标准库函数 strstr
在字符串 _str
中查找第一次出现的子字符串 str
。strstr
返回一个指向匹配子字符串的指针,如果未找到匹配项,则返回 nullptr。
7.获取子串
在 string
类中,substr
函数用于提取字符串的子串:
//取子串string substr(size_t pos = 0, size_t len = -1){assert(pos <= _size);size_t n = len;if (n == -1 || pos + n > _size){n = _size - pos;}string tmp;tmp.reserve(n);for (size_t i = pos; i < pos + n; i++){tmp += _str[i];}return tmp;}
pos表示子串的首元素位置,len表示子串长度,len同样设置成缺省参数,缺省值为最大值,即取的是pos后面的全部字符组成的子串。由于返回值类型是string类,所以我们需要声明一个tmp对象,用于存放子串的副本,用重载后的+=操作符即可实现子串的复制。
三、完整代码
#pragma once
#include<iostream>
#include<cassert>
using namespace std;
namespace Mystd
{class string{public:string(const char* str = "") //全缺省,常量字符串末尾默认'\0':_size(strlen(str)),_capacity(_size),_str(new char[_capacity + 1]){strcpy(_str, str);}string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* c_str() const //const关键字进行函数重载,表示const对象也可以调用,不加则不行{return _str;}size_t size() const{return _size;}char& operator[](size_t pos) //引用返回:返回值出了作用域任然存在,可读可写{assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const //const对象调用这个,只读{assert(pos < _size);return _str[pos];}//迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;} //实现了迭代器也就实现了范围forconst_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;} //实现了迭代器也就实现了范围for//扩容void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;//可以直接指针复制,令两者指向同一块空间_capacity = n;}}//插入字符void push_back(char ch){if (_size == _capacity){//2倍扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';}//插入字符串void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){//至少扩容到_size+lenreserve(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}void insert(size_t pos, size_t n, char ch){assert(pos <= _size);if (_size + n < _capacity){//至少扩容到_size+nreserve(_size + n);}//挪动数据size_t end = _size;while (end >= pos && end != -1) //若pos为0呢?end!=-1{_str[end + n] = _str[end];--end;}for (size_t i = 0; i < n; i++){_str[pos + i] = ch;}_size += n;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len < _capacity){//至少扩容到_size+nreserve(_size + len);}//挪动数据size_t end = _size;while (end >= pos && end != -1) //若pos为0呢?end!=-1{_str[end + len] = _str[end];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}void erase(size_t pos, size_t len = -1){assert(pos < _size);if (len == -1 || pos + len > _size){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[pos++] = _str[end++];}_size -= len;}}//找一个字符size_t find(char ch, size_t pos = 0){for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return -1;}//找一个字符串size_t find(const char* str, size_t pos = 0){const char* ptr = strstr(_str,str);if (ptr){return ptr - _str;}else{return -1;}}//取子串string substr(size_t pos = 0, size_t len = -1){assert(pos <= _size);size_t n = len;if (n == -1 || pos + n > _size){n = _size - pos;}string tmp;tmp.reserve(n);for (size_t i = pos; i < pos + n; i++){tmp += _str[i];}return tmp;}private:char* _str;size_t _size;size_t _capacity;static size_t npos;};size_t Mystd::string::npos = -1;
}
四、补充
前面说到过:在C++中,对于无符号整数类型,-1 不是一个负数,而是一个非常大的正整数。这是由于无符号整数类型不能表示负数,因此用有符号整数的-1表示无符号整数时,会被解释为该无符号整数的最大可能值。因此我在处理一些返回值情况时,例如查找操作时,没找到指定字符则返回-1这可能导致问题,因为 size_t
是一个无符号整数类型,而 -1
是有符号整数。在 C++ 中,无符号整数和有符号整数之间的比较可能导致一些不直观的行为。
所以最好用std::string::npos来表示-1(最大可能值)的情况。npos需设置成静态成员变量:
namespace Mystd
{class string{public://...private:char* _str;size_t _size;size_t _capacity;static size_t npos;};size_t Mystd::string::npos = -1;
}
写文不易,望多多支持~~
相关文章:
【C++】理解string类的核心理念(实现一个自己的string类)
目录 一、引言 二、自我实现 1.成员变量的读写 2.构造与析构 3.迭代器 4.插入字符或字符串 尾插 中间插入 5.删除字符或子字符串 6.查找字符或子串 7.获取子串 三、完整代码 四、补充 一、引言 实现自己的 string 类是学习 C 语言和面向对象编程的一个好方法。通过…...
conda 虚拟环境使用
查看已有的虚拟环境 conda env list 创建虚拟环境且带python conda create -n test123 python3.7 激活虚拟环境(To activate this environment) conda activate test123 安装需要的包 python -m pip install opencv-python 退出虚拟环境(To…...
C# 使用MSTest进行单元测试
目录 写在前面 代码实现 执行结果 写在前面 MSTest是微软官方提供的.NET平台下的单元测试框架;可使用DataRow属性来指定数据,驱动测试用例所用到的值,连续对每个数据化进行运行测试,也可以使用DynamicData 属性来指定数据&…...
基于Java (spring-boot)的宠物管理系统
一、项目介绍 1、用户端功能: 首页:展示公告列表,宠物科普,介绍流浪宠物,热门活动。 宠物领养:用户搜索想要领养宠物,申请领养,查看自己领养的宠物。 宠物救助:用户能…...
基于博弈树的开源五子棋AI教程[1 位棋盘]
0 引子 常见的五子棋棋盘大小为15x15,最直观的表示就是一个二维数据。本文为了易于拓展一开始使用的是QVector<QVector>的数据,但是在分支因子为10的情况下只能搜索到4层左右,后面深度加深,搜索时间呈指数倍数增长。这种实…...
Java Catching and Handling Exceptions(二)
一、Try with resources语句 try with resources语句是声明一个或多个资源的try语句。资源是程序使用完后必须关闭的对象。try with resources语句确保在语句末尾关闭每个资源。任何实现java.lang.AutoCloseable的对象(包括实现java.io.Closeable的所有对象&#x…...
【HarmonyOS开发】ArkTs关系型和非关系型数据库的存储封装
前面使用了首选项的存储方式,因此将其他的两种存储方式(键值型数据库和关系型数据库)也学习一下,简单记录一下,并进行封装,方便后续使用。 1、效果预览 2、使用条件 2.1 键值型数据库 键值型数据库实现数据…...
Latex编译出来的pdf文件缺少参考文献和交叉引用
参考文件通常需要在首次编译后,再次编译添加 依次执行下面的命令即可: xelatex main.tex main.tex为需要编译的主tex文件 biber mainxelatex main.tex 如果编译过程中遇到错误,请删除所有辅助文件和已打开的pdf文件后重试 辅助文件包括&#…...
sql_lab靶场搭建以及存在的一些问题
sql_lab靶场搭建问题 首先检查小皮版本 把小皮改到5.3.29版本如果没有可以直接点击更多版本进行选择安装 当版本不对时则会暴出这种错误 SETTING UP THE DATABASE SCHEMA AND POPULATING DATA IN TABLES: Fatal error: Uncaught Error: Call to undefined function mysql_co…...
Https接口调用问题
使用场景: 因为项目需要爬点接口数据, 接口是https, 在网上找的笔记整理了一下. 仅供参考 1. 调用Https的Get方法 /*** 只需要url** param url* return*/public static String doGetForHTML(String url) {return doGetForHTML(url, null);}/*** param url 请求地址* para…...
CSS自适应分辨率 amfe-flexible 和 postcss-pxtorem:大屏高宽自适应问题
前言 继上篇《CSS自适应分辨率 amfe-flexible 和 postcss-pxtorem》。 发现一个有趣的问题,文件 rem.js 中按照宽度设置自适应,适用于大多数页面,但当遇到大屏就不那么合适了。 问题 使用宽度,注意代码第2 和 4 行:…...
SQL面试题挑战01:打折日期交叉问题
目录 问题:SQL解答:第一种方式:第二种方式: 问题: 如下为某平台的商品促销数据,字段含义分别为品牌名称、打折开始日期、打折结束日期,现在要计算每个品牌的打折销售天数(注意其中的…...
三大主流前端框架介绍及选型
在前端项目中,可以借助某些框架(如React、Vue、Angular等)来实现组件化开发,使代码更容易复用。此时,一个网页不再是由一个个独立的HTML、CSS和JavaScript文件组成,而是按照组件的思想将网页划分成一个个组…...
云原生消息流系统 Apache Pulsar 在腾讯云的大规模生产实践
导语 由 InfoQ 主办的 Qcon 全球软件开发者大会北京站上周已精彩落幕,腾讯云中间件团队的冉小龙参与了《云原生机构设计与音视频技术应用》专题,带来了以《云原生消息流系统 Apache Pulsar 在腾讯云的大规模生产实践》为主题的精彩演讲,在本…...
【LeetCode刷题】--245.最短单词距离III
245.最短单词距离III class Solution {public int shortestWordDistance(String[] wordsDict, String word1, String word2) {int len wordsDict.length;int ans len;if(word1.equals(word2)){int prev -1;for(int i 0;i<len;i){String word wordsDict[i];if(word.equa…...
数字化时代的智能支持:亚马逊云科技轻量应用服务器技术领先
轻量应用服务器是一种简化运维、门槛低的弹性服务器,它的"轻"主要体现在几个方面:开箱即用、应用优质、上手简洁、投入划算、运维简便以及稳定可靠。相较于普通的云服务器,轻量应用服务器简化了云服务的操作难度、使用和管理流程&a…...
【智慧之窗】AI驱动产品探索
一.初识 ChatGPT ChatGPT 是由 OpenAI 开发的自然语言处理(NLP)模型,基于 GPT(Generative Pre-trained Transformer)架构。GPT 系列的模型旨在理解和生成自然语言文本。ChatGPT 专注于支持对话性任务,即与…...
BBS项目--登录
BBS阶段性测试总要求 django登录报错 Error: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。 原因分析:出现这种情况在Windows中很常见,就是端口被占用 解决措施:这时我们只需改一下端口便可以了 登录前端页面(HTML…...
Python---TCP服务端程序开发
1. 开发 TCP 服务端程序开发步骤回顾 创建服务端端套接字对象绑定端口号设置监听等待接受客户端的连接请求接收数据发送数据关闭套接字 2. socket 类的介绍 导入 socket 模块import socket 创建服务端 socket 对象socket.socket(AddressFamily, Type) 参数说明: AddressF…...
回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 (多指标,多图)
回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 (多指标,多图) 目录 回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 (多指标,多图&#…...
听GPT 讲Rust源代码--src/tools(15)
File: rust/src/tools/rust-analyzer/crates/mbe/src/token_map.rs 在Rust源代码中,rust/src/tools/rust-analyzer/crates/mbe/src/token_map.rs文件的作用是实现了一个能够将输入的文本映射为标记的结构。具体来说,它定义和实现了几个结构体(…...
python可以做小程序研发嘛,python能做微信小程序吗
大家好,给大家分享一下python可以做微信小程序开发吗,很多人还不知道这一点。下面详细解释一下。现在让我们来看看! 大家好,给大家分享一下用python编写一个小程序,很多人还不知道这一点。下面详细解释一下用python代码…...
创建型模式 | 单例模式
一、单例模式 单例模式(Singleton Pattern),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例被构造,并提供一个访问它的全局访问接口,该实例被程序的所有模块共享。 1、饿汉式 1.1、基础版本 在程序启动后立刻构造单例࿰…...
【无标题】欢迎使用Markdown编辑器
这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…...
Postgresql中PL/pgSQL的游标、自定义函数、存储过程的使用
场景 Postgresql中PL/pgSQL代码块的语法与使用-声明与赋值、IF语句、CASE语句、循环语句: Postgresql中PL/pgSQL代码块的语法与使用-声明与赋值、IF语句、CASE语句、循环语句-CSDN博客 上面讲了基本语法,下面记录游标、自定义函数、存储过程的使用。 …...
【IDEA】Intellij IDEA相关配置
IDEA 全称 IntelliJ IDEA,是java编程语言的集成开发环境。IntelliJ在业界被公认为最好的Java开发工具,尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超…...
GD32移植STM32工程(因为懒,所以移植)
文章目录 一、前言二、差异性三、软件移植部分1.前期准备1.1 安装GD32固件库1.2 选择所用芯片 2.修改程序2.1 启动时间(内部时钟可不改)2.2 主频2.2.1 系统时钟配置2.2.2 108MHz宏定义第一处第二处第三处第四处第五处 2.2.3 串口2.2.4 FLASH 四、总结 一…...
mt5和mt4交易软件有什么区别?
MetaTrader 4(MT4)和MetaTrader 5(MT5)是两种广泛使用的外汇和金融市场交易平台,由MetaQuotes公司开发。尽管它们都是外汇交易的常见选择,但在功能和特性上存在一些区别。以下是MT4和MT5之间的主要区别&…...
零刻EQ12 N100 双2.5G网口 All In One新手教程
零刻EQ12 N100 双2.5G网口 All In One新手教程 前言1.硬件配置2.准备工作2.1. ESXI8.0U2镜像2.2. Rufus磁盘工具下载2.3. ikuai镜像下载2.4. StarWindConverter虚拟磁盘格式转换工具下载2.5. OpenWrt镜像下载2.6. 黑群晖RR引导镜像下载(DSM7.2)2.7. 需要准备的硬件2.8. 格式化需…...
竞赛保研 基于Django与深度学习的股票预测系统
文章目录 0 前言1 课题背景2 实现效果3 Django框架4 数据整理5 模型准备和训练6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于Django与深度学习的股票预测系统 ** 该项目较为新颖,适合作为竞赛课题方向ÿ…...
金陵热线 网站备案/站长交流平台
使用新浪SAE架构搭建自己的网站。将自己在本地编写的PHP程序上传到SAE上。如果要正常使用需要链接MySQL数据库(如果你的网站使用了MySQL数据库服务)。新浪SAE提供了对PHP访问MySQL的程序支持。所以这个过程要实现起来并不困难。只需要修改用户名和密码。创建完应用后࿰…...
网站建设七点/教育培训学校
先查看是否有密钥文件 ls -al ~/.ssh/ 没有,可以配置 添加密钥(用自己的邮箱) ssh-keygen -C youemail163.com -t rsa 一路点回车键就可以了,直到出现下面画面 进入到密钥文件目录,查看公钥文件 id_rsa.pub cd ~/…...
商城网站建设/手机百度极速版app下载安装
问题描述 请把纸条竖着放在桌⼦上,然后从纸条的下边向上⽅对折,压出折痕后再展 开。此时有1条折痕,突起的⽅向指向纸条的背⾯,这条折痕叫做“下”折痕 ;突起的⽅向指向纸条正⾯的折痕叫做“上”折痕。如果每次都从下边…...
wordpress 机器学习/阿里域名购买网站
.yaml文件实际是用YAML语言编写的,YAML简述。如下 1、语法特点 大小写敏感通过缩进表示层级关系禁止使用tab缩进,只能使用空格键缩进的空格数据不重要,只要相同层级左对齐即可使用#表示注释 2、yaml支持的数据结构有三种:对象、…...
用家里的路由器做网站/太原搜索引擎优化
天线增益概念。原创不易,恐有错误,恳请读者指正。碎片三分钟逛电巢App,收获一丢丢。 天线定向性(directivity) 假设理想的无定向性天线,在远场区的3D球面空间各方向的辐射功率都相等,则定义球面等辐射功率的方向图的定…...
无锡高端网站开发/永久免费客服系统有哪些软件
关注我,和我一起学习新知识数据治理是企业数据建设必不可少的一个环节。好的数据治理体系可以盘活整条数据链路,最大化保障企业数据的采集、存储、计算和使用过程的可控和可追溯。如何构建企业数据治理体系?企业数据治理过程需要注意哪些问题…...