c++初阶篇----string的底层模拟

news2024/11/24 16:34:41

string类的模拟

目录

  • string类的模拟
    • 功能介绍
    • 各功能的实现
      • 类的构造函数,拷贝构造函数,析构函数
      • 迭代器的实现
      • string的内部容量访问成员函数
      • string的修改成员函数
      • string类的相关联函数
      • string类的输入输出友元
    • 汇总
      • string功能的实现汇总
      • 测试代码

功能介绍

namespace bit
{
    class string
    {
    private:
        char* _str;
        size_t _capacity;
        size_t _size;
    public:
        typedef char* iterator;
        typedef const char*const_iterator;
        static const int npos;
    public:
		    string(){}
		    ~string(){}
		    //各个成员函数的实现
    }
}
const int bit::string::npos = -1;

实现思路:

  • 迭代器的实现{typefef 一个指针,模拟指针,这里用的指针}
  • 先实现构造函数{注意初始化的动态内存开辟}
    这里还要注意如何实现缺省值(赋予nullptr? 赋予空)
    ,拷贝构造函数{开辟字符串长度大小的空间,strcpy内存复制}
  • c_str(){返回数组内容}
  • 运算符重载 拷贝 {设计现代写法,利用临时变量在此函数调用其他已经实现的构造函数,与临时变量交换,实现拷贝。第二种普遍想法,开同等大小的空间(注意实际多出1来存‘/0’),内存复制函数}
  • 析构函数{释放空间,成员变量归零}
  • 扩容函数reserve{若空间不足,new,思想和栈,链表开空间一样,临时变量来做缓冲}
  • 调整字符串大小函数resize{若参数的长度小于当前string的长度,便将[n]位置的数据赋予‘/0’

修改:

  • 尾插push_pack{判断扩容,尾部插入字符}
  • append{扩容,复制拷贝字符串}
  • 插入函数insert(字符串,字符){扩容,对pos位置的字符往后排,在pos位置插入字符,或者插入字符串(strncpy,不会复制空字符)}
  • 擦除erase{在pos位置删除之后的字符串}
  • 交换swap{交换函数模板,各成员变量都交换}
  • 查找find(字符,字符串)
    判断pos位置的合理性,循环比较相等
    字符串需要用到库函数strstr
  • 获取从某个位置开始的字符串substr{临时变量string来储存pos之后的字符串,注意的是,谨慎判断pos与_size和npos之间的关系大小
  • 清除clear{_str[0]置空字符,大小变为零}
  • [ ]

各功能的实现

类的构造函数,拷贝构造函数,析构函数

其中涉及到库函数,内存拷贝的4个库函数

  1. void * memcpy ( void * destination, const void * source, size_t num ); 返回值是destination,此函数是复制内存块,将字节数的值从源指向的位置直接复制到目标指向的内存块,不检查是否source是否有终止符号

  2. void * memmove ( void * destination, const void * source, size_t num ); 返回值是destination,此函数是移动内存块。将 num 字节的值从指向的位置复制到目标指向的内存块。复制就像使用中间缓冲区一样进行,从而允许目标重叠

  3. char * strcpy ( char * destination, const char * source ); 返回值是destination,此函数的复制包括结尾的‘/0’

  4. char * strncpy ( char * destination, const char * source, size_t num ); 返回值是 destination,此函数是复制字符串,复制n个字符至des

  5. 构造,拷贝构造

//不建议的写法
string():_str(new char[1]),_capacity(0),_size(0)
{
    _str[0] = '/0';
}
string(const char* s):_capacity(strlen(s))
{
    _str = new char[_capacity + 1];
    _size = _capacity;
    strcpy(_str, s);
}
string(const char* str = ""):_capacity(strlen(str))//缺省值不给字符,也就是空字符串
{
    _str = new char[_capacity + 1];//多开一个空间给‘/0’
    _size = _capacity;
    strcpy(_str, str);
}

string(const string& s)
{
    _str = new char[s._capacity + 1];
    _capacity = s._capacity;
    _size = s._size;
    strcpy(_str, s._str);
}

string& operator=(const string& s)
{
    _str = new char[s._capacity + 1];
    _capacity = s._capacity;
    _size = s._size;
    strcpy(_str, s._str);
    return *this;
}
  1. 现代写法:在实现了一个构造函数,在此基础上调用构造函数来实现另一个构造函数
string& operator=(const string& s)
{
    //_str = new char[s._capacity + 1];
    //_capacity = s._capacity;
    //_size = s._size;
    //strcpy(_str, s._str);
    //return *this;
    string tem(s);
    swap(tem);//这里交换要注意一开始给成员变量初始值
    return *this;
}

注意:交换后临时开辟的变量若对成员变量不初始化,临时变量就会变成野指针,在析构可能出现异常

在这里插入图片描述

  1. 析构函数
~string()
{
    delete[] _str;
    _str = nullptr;            
    _size = _capacity = 0;
}

迭代器的实现

string的迭代器这里用的是指针实现,迭代器用指针是比较容易实现的,只需返回指针即可

// iterator
typedef char* iterator;
typedef const char*const_iterator;
const_iterator begin()const
{
    return _str;
}
const_iterator end()const
{
    return _str + _size;
}
iterator begin()
{
    return _str;
}
iterator end()
{
    return _str + _size;
}

实现了迭代器,那么for循环也可以使用,其实for循环的本质也是用的迭代器的原理,表面是任意变量的拷贝,底层是迭代器的转换

	void test()
	{
			bit::string s2("abcdefg");
			bit::string::iterator begin = s2.begin();
			while (begin != s2.end())
			{
			    (*begin)++;
			    cout << *begin;
			    begin++;
			}
			cout << endl;
			for (auto ch : s2)
			{
			    cout << ch;
			}
  }

在这里插入图片描述

string的内部容量访问成员函数

  1. string大小容量的实现
// capacity
size_t size()const
{
    return _size;
}

size_t capacity()const
{
    return _capacity;
}

bool empty()const
{
    return _size == 0;
}
  1. 在实现resize和reserve成员函数,应该充分了解他们的底层逻辑,resize只增容不缩容,若参数大于当前容量,扩容并且以参数char c来填充扩容后的内容。
    reserve是用来为其他成员函数扩容的,不缩容,所有扩容函数构造函数都会多开一个空间来留个‘\0’这个空字符
void resize(size_t n, char c = '\0')
{
    if (n <= _capacity)
    {
        _str[n] = '\0';
        _size = n;
    }
    else {
        reserve(n);
        for (size_t i = _size;i < n; i++)   
        {
            _str[i] = c;
        }
        _str[n] = '\0';
        _size = n;
    }
}

void reserve(size_t n)
{
    if (n > _capacity)
    {
        char* tem = new char[n + 1];//多开一个空间
        strcpy(tem, _str);
        delete[] _str;
        _str = tem;
        _capacity = n;
    }
}

string的修改成员函数

string的修改成员函数

   modify

  //void push_back(char c);

  //string& operator+=(char c);

  //void append(const char* str);

  //string& operator+=(const char* str);

  //void clear();

  //void swap(string& s);
  
 //const char* c_str()const

  1. 实现插入,增加的原理是一样的:
    先判断是否扩容,然后插入字符,或者strcpy插入字符串
 void push_back(char c)
 {
     if (_size == _capacity)
     {
         reserve(_capacity == 0 ? 4 : 2 * _capacity);
     }
     _str[_size++] = c;
     _str[_size] = '\0';
 }

 string& operator+=(char c)
 {
     push_back(c);
     return *this;
 }

 void append(const char* str)
 {
     int len = strlen(str);
     if(_size+len>_capacity||_size >_capacity - len)//最大值溢出问题
     {
         reserve(_size + len);
     }
     strcpy(_str + _size, str);
     _size = _size + len;
 }

 string& operator+=(const char* str)
 {
     append(str);
     return *this;
 }

 string& operator+=(const string s)
 {
     reserve(_size + s._size);
     strcpy(_str + _size, s._str);
     _size = _size + s._size;
     return *this;
 }

  1. 清除函数和交换函数也是很容易实现的
    清除成员函数不需要考虑释放空间,只需要将第一个有效字符设置为’\0’即可
    而交换函数可以利用库函数的模板来实现,将各个成员变量进行交换
 void clear()
 {
     _str[0] = '\0';
     _size = 0;
 }

 void swap(string& s)
 {
     std::swap(_str, s._str);
     std::swap(_capacity, s._capacity);
     std::swap(_size, s._size);
 }

在swap中应用中还是不太普遍,需要s1.swap(s2) ,看起来还是不够使用,也不像库函数那样,所以,可以再重载一个全局函数,这里注意是在类域外,全局处重载函数

void swap(string& s1, string& s2)
{
    s1.swap(s2);
}
  1. 返回字符串函数,返回成员变量_str(开辟空间的地址)即可
const char* c_str()const
 {
     return _str;
 }

string类的相关联函数

  1. find成员函数的实现
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
    //pos合理
    assert(pos < _size);
    for (size_t i = pos;i < _size;i++)
    {
        if (_str[i] == c)
            return i;
    }
    return npos;
}

find的字符串的实现

这里用到了库函数strstr
const char * strstr ( const char * str1, const char * str2 ); 此函数查找子字符串,若匹配了,返回指针,不匹配返回空指针

// 返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const
{
    assert(pos < _size);
    char* ch = strstr(_str, s);
    if (ch)
    {
        //返回俩个指针的差值,就是当前的位置
        return ch - _str;
    }
    else
    {
        return npos;
    }
}

insert插入函数的实现

 在pos位置上插入字符c/字符串str,并返回该字符的位置
string& insert(size_t pos, char c)
{
    assert(pos <= _size);
    if (_size == _capacity)
    {
        reserve(_capacity == 0 ? 4 : 2 * _capacity);
    }
    for (size_t i = _size+1;i > pos;i--)
    {
        _str[i] = _str[i-1];
    }
    _str[pos] = c;
    _size++;
    return* this;
}

string& insert(size_t pos, const char* str)
{
    assert(pos <= _size);
    //和append实现思路一样
    size_t len = strlen(str);
    if (_size > _capacity - len || _size+len >_capacity )//最大值溢出的问题
    {
        reserve(_size + len);
    }
    for (size_t i = _size  + len;i > pos + len -1 ;i--)
    {
         _str[i] = _str[i - len]; 
    }
    strncpy(_str + pos, str,len);
    _size = _size + len;
    return *this;
}

erase擦除函数,将pos位置及后面的总计len个字符擦除

// 删除pos位置上的元素,并返回该元素的下一个位置
string& erase(size_t pos, size_t len=npos)
{
    assert(pos < _size);//不用取等,最后一个_size位置是不能擦除的,'\0'
    if (len == npos || len > _size - pos-1)
    {
        _str[pos] = '\0';
        _size = pos;
    }
    else
    {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
    }
    return *this;
}

string比较函数的实现可以借助库函数的strcmp
int strcmp ( const char * str1, const char * str2 ); 此函数将俩个字符串进行比较,相等返回0 ,str1小于str2返回一个负数(反之)

string类的输入输出友元

注意:此类函数的实现都是基于类域的外面,也就是全局

输出流cout

输入流cin

输入流的实现思路有很多种优化。
很普遍的实现是将输入的字符一个一个塞进string的实例中,一边塞一边扩容 ,获取输入字符可以借助库函数get()

    //istream& operator>>(istream& _cin, bit::string& s)
    //{
    //    //清空当前的内容
    //    s.clear();
    //    char ch;
    //    ch = _cin.get();
    //    s.reserve(64);
    //    while (ch != ' ' && ch != '\n')//当遇到enter和空格就停止获取
    //    {
    //        s.push_back(ch);
    //        ch = _cin.get();
    //    }
    //    return _cin;
    //}

优化:用一个大小固定的临时数组来存储当前输入字符,当输入结束或者数组已满,就赋值给string,将数组的有效字符重置,继续下一轮(如果还有输入字符)

istream& operator>>(istream& _cin, bit::string& s)
{
    s.clear();
    char ch;
    ch = _cin.get();
    char c[128];
    size_t i = 0;
    while (ch != ' ' && ch != '\n')
    {
        c[i++] = ch;
        //当数组满时
        if (i == 127)
        {
            c[127] = '\0';//注意在这个位置赋予结束字符,否则会出现随机字符
            s += c;
            i = 0;
        }
        ch = _cin.get();
    }
    if (i > 0)
    {
        c[i] = '\0';//注意先给结束字符,否则会将上一次循环的已无效字符或随机字符,+=进入string
        s += c;
    }
    return _cin;
}

汇总

string功能的实现汇总

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;

namespace bit
{
    class string
    {
    private:
        char* _str = nullptr;
        size_t _capacity = 0;
        size_t _size = 0;
        friend ostream& operator<<(ostream& _cout, const bit::string& s);
        friend istream& operator>>(istream& _cin, bit::string& s);
    public:
        typedef char* iterator;
        typedef const char*const_iterator;
        static const int npos;
    public:
        //string() :_str(new char[1]), _capacity(0), _size(0)
        //{
        //    _str[0] = '/0';
        //}
        //string(const char* s) :_capacity(strlen(s))
        //{
        //    _str = new char[_capacity + 1];
        //    _size = _capacity;
        //    strcpy(_str, s);
        //}

        string(const char* str = ""):_capacity(strlen(str))//缺省值不给字符,也就是空字符串
        {
            _str = new char[_capacity + 1];//多开一个空间给‘/0’
            _size = _capacity;
            strcpy(_str, str);
        }
        string(const string& s)
        {
            _str = new char[s._capacity + 1];
            _capacity = s._capacity;
            _size = s._size;
            strcpy(_str, s._str);
        }
        string& operator=(const string& s)
        {
            //_str = new char[s._capacity + 1];
            //_capacity = s._capacity;
            //_size = s._size;
            //strcpy(_str, s._str);
            //return *this;
            string tem(s);
            swap(tem);//这里交换要注意一开始给成员变量初始值
            return *this;
        }
        //俩种现代写法,在完成其他成员函数的基础上

        ~string()
        {
            delete[] _str;
            _str = nullptr;            
            _size = _capacity = 0;
        }

        // iterator
        const_iterator begin()const
        {
            return _str;
        }
        const_iterator end()const
        {
            return _str + _size;
        }
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }

        // modify
        void push_back(char c)
        {
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : 2 * _capacity);
            }
            _str[_size++] = c;
            _str[_size] = '\0';
        }

        string& operator+=(char c)
        {
            push_back(c);
            return *this;
        }

        void append(const char* str)
        {
            size_t len = strlen(str);
            if (_size >_capacity - len||_size+len>_capacity)//最大值溢出问题
            {
                reserve(_size + len);
            }
            strcpy(_str + _size, str);
            _size = _size + len;
        }

        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

        string& operator+=(const string s)
        {
            reserve(_size + s._size);
            strcpy(_str + _size, s._str);
            _size = _size + s._size;
            return *this;
        }

        void clear()
        {
            _str[0] = '\0';
            _size = 0;
        }

        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_capacity, s._capacity);
            std::swap(_size, s._size);
        }

        const char* c_str()const
        {
            return _str;
        }

        // capacity
        size_t size()const
        {
            return _size;
        }

        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            return _size == 0;
        }

        void resize(size_t n, char c = '\0')
        {
            if (n <= _capacity)
            {
                _str[n] = '\0';
                _size = n;
            }
            else {
                reserve(n);
                for (size_t i = _size;i < n; i++)   
                {
                    _str[i] = c;
                }
                _str[n] = '\0';
                _size = n;
            }
        }

        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                char* tem = new char[n + 1];
                strcpy(tem, _str);
                delete[] _str;
                _str = tem;
                _capacity = n;
            }
        }

         access
        char& operator[](size_t index)
        {
            return *(_str + index);
        }

        const char& operator[](size_t index)const
        {
            return *(_str + index);
        }

        //relational operators
        bool operator<(const string& s)
        {
            if (strcmp(c_str(), s.c_str()) < 0)
            {
                return true;
            }
            return false;
                
        }

        bool operator<=(const string& s)
        {
            return *this == s || *this < s;
        }

        bool operator>(const string& s)
        {
            return !(*this <= s);
        }

        bool operator>=(const string& s)
        {
            return !(*this < s);
        }

        bool operator==(const string& s)
        {
            if (strcmp(c_str(), s.c_str()) == 0)
                return true;
            return false;
        }

        bool operator!=(const string& s)
        {
            return !(*this == s);
        }

        // 返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const
        {
            //pos合理
            assert(pos < _size);
            for (size_t i = pos;i < _size;i++)
            {
                if (_str[i] == c)
                    return i;
            }
            return npos;
        }

        // 返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const
        {
            assert(pos < _size);
            char* ch = strstr(_str, s);
            if (ch)
            {
                //返回俩个指针的差值,就是当前的位置
                return ch - _str;
            }
            else
            {
                return npos;
            }
        }

         在pos位置上插入字符c/字符串str,并返回该字符的位置
        string& insert(size_t pos, char c)
        {
            assert(pos <= _size);
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : 2 * _capacity);
            }
            for (size_t i = _size+1;i > pos;i--)
            {
                _str[i] = _str[i-1];
            }
            _str[pos] = c;
            _size++;
            return* this;
        }

        string& insert(size_t pos, const char* str)
        {
            assert(pos <= _size);
            //和append实现思路一样
            size_t len = strlen(str);
            if (_size > _capacity - len || _size+len >_capacity )//最大值溢出的问题
            {
                reserve(_size + len);
            }
            for (size_t i = _size  + len;i > pos + len -1 ;i--)
            {
                 _str[i] = _str[i - len]; 
            }
            strncpy(_str + pos, str,len);
            _size = _size + len;
            return *this;
        }

        // 删除pos位置上的元素,并返回该元素的下一个位置
        string& erase(size_t pos, size_t len=npos)
        {
            assert(pos < _size);//不用最后一个pos是不能擦除的,‘\0'
            if (len == npos || len > _size - pos-1)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                strcpy(_str + pos, _str + pos + len);
                _size -= len;
            }
            return *this;
        }
    };
    const int bit::string::npos = -1;

    void swap(string& s1, string& s2)
    {
        s1.swap(s2);
    }

    ostream& operator<<(ostream& _cout, const bit::string& s)
    {
        for (auto ch : s)
        {
            _cout << ch;
        }
        return _cout;
    }

    //istream& operator>>(istream& _cin, bit::string& s)
    //{
    //    //清空当前的内容
    //    s.clear();
    //    char ch;
    //    ch = _cin.get();
    //    s.reserve(64);
    //    while (ch != ' ' && ch != '\n')//当遇到enter和空格就停止获取
    //    {
    //        s.push_back(ch);
    //        ch = _cin.get();
    //    }
    //    return _cin;
    //}
        istream& operator>>(istream& _cin, bit::string& s)
        {
            s.clear();
            char ch;
            ch = _cin.get();
            char c[128];
            size_t i = 0;
            while (ch != ' ' && ch != '\n')
            {
                c[i++] = ch;
                //当数组满时
                if (i == 127)
                {
                    c[127] = '\0';//注意在这个位置赋予结束字符,否则会出现随机字符
                    s += c;
                    i = 0;
                }
                ch = _cin.get();
            }
            if (i > 0)
            {
                c[i] = '\0';//注意先给结束字符,否则会将上一次循环的已无效字符或随机字符,+=进入string
                s += c;
            }
            return _cin;
        }
}

测试代码

#include"imitate_string.h"

void test1()
{
    //bit::string s1;
	bit::string s2("abcdefg");
    bit::string::iterator begin = s2.begin();
    while (begin != s2.end())
    {
        (*begin)++;
        cout << *begin;
        begin++;
    }
    cout << endl;
    for (auto ch : s2)
    {
        cout << ch;
    }

	//cout << s2[2] << endl;
}

void test2()
{
    bit::string s1("abcdefg");
    //s1.resize(4);
    //s1.resize(5, 'i');
    //cout << s1.c_str() << endl;
    //bit::string s2;
    //s2.resize(10, '1');
    //s1.push_back('2');
    s1.append("you donot know .... ,just nothing");
    cout << s1.c_str() << endl;
}

void test3()
{
    bit::string s1;
    bit::string s2("ijustlovebutitwillbenothing");
    bit::string s3 = s2;
    s3 += s2;
    s2 += "itjustnothing OK";
    cout << s3.c_str() << endl;
    cout << s2.c_str() << endl;
    s1.swap(s2);
    cout << s1.c_str() << endl;
    s1.clear();
    cout << s1.c_str() << endl;
}

void test4()
{
    bit::string s1("abadfadf");
    //bit::string s2("it just be ok,i think i only gave up");
    //swap(s1, s2);
    //bit::string s3 = s2;
    //cout << s1.c_str() << endl << s2.c_str() <<s3.c_str()<< endl;
}

void test5()
{
    bit::string s1("abadfadf");
    bit::string s2("ac");
    size_t i = s1.find('b');
    //s1.insert(i, '5');
    //s2.insert(0,"12345");
    s1.erase(i, 2);
    s2.erase(0);
    s2 = s1;
    s2.erase(3);
    cout << s1.c_str() << endl;
    cout << s2.c_str();
}

void test6()
{
    bit::string s1("qwert");
    bit::string s2("qwert");
    bit::string s3("qert");
    //cout << (s1 < s2) << endl;//0
    //cout << (s1 >= s2) << endl;//1
    //cout << (s3 <= s2) << endl;//1

    cout << s1 << endl;
   cin >> s2;
   cout << s2;
   bit::swap(s2, s1);
   cout << s1;
    
}

int main()
{
    //using namespace bit;
    //bit::string s1();
    //bit::string s2("abcdefg");
    //test5();
    //test6();
    bit::string s1("abka");
    cin >> s1;
    //s1.append("ab");
    cout << s1;
    return 0;
}

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

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

相关文章

鸿蒙实战开发-使用属性动画实现自定义刷新组件

介绍 本篇Codelab主要介绍组件动画animation属性设置。当组件的某些通用属性变化时&#xff0c;可以通过属性动画实现渐变效果&#xff0c;提升用户体验。效果如图所示&#xff1a; 说明&#xff1a; 本Codelab使用的display接口处于mock阶段&#xff0c;在预览器上使用会显示…

element-ui switch 组件源码分享

今日简单分享 switch 组件源码&#xff0c;主要从以下四个方面来分享&#xff1a; 1、switch 组件的页面结构 2、switch 组件的属性 3、switch 组件的事件 4、switch 组件的方法 一、switch 组件的页面结构 二、switch 组件的属性 2.1 value / v-model 属性&#xff0c;绑…

基于Hive大数据分析springboot为后端以及vue为前端的的民宿系

标题基于Hive大数据分析springboot为后端以及vue为前端的的民宿系 本文介绍了如何利用Hive进行大数据分析,并结合Spring Boot和Vue构建了一个民宿管理系统。该民民宿管理系统包含用户和管理员登陆注册的功能,发布下架酒店信息,模糊搜索,酒店详情信息展示,收藏以及对收藏的…

SpringMVC源码分析(七)--数据绑定工厂

1.数据绑定工厂的使用 数据绑定工厂能够创建数据绑定器,将数据绑定到对象中,比如说当接收到请求时,经过http协议解析后数据刚开始都是字符串,此时我们希望将这些属性进行类型转换,并为对象赋值,示例如下: 1)先创建两个实体类Student和Teacher @Getter @Setter @ToSt…

封装性练习

练习 1 &#xff1a; 创建程序&#xff1a;在其中定义两个类&#xff1a; Person 和 PersonTest 类。定义如下&#xff1a; 用 setAge() 设置人的合法年龄 (0~130) &#xff0c;用 getAge() 返回人的年龄。在 PersonTest 类中实例化 Person 类的对象 b &#xff0c;调用 set…

Java八股文(算法)

Java八股文の算法 算法 算法 逆序输出字符串 题目描述&#xff1a;输入一个字符串&#xff0c;要求逆序输出。 public static String reverseString(String s) {StringBuilder sb new StringBuilder();for (int i s.length() - 1;i > 0;i--) {sb.append(s.charAt(i));}r…

基于多模态信息的语音处理(misp) 2023挑战:视听目标说话人提取

THE MULTIMODAL INFORMATION BASED SPEECH PROCESSING (MISP) 2023 CHALLENGE: AUDIO-VISUAL TARGET SPEAKER EXTRACTION 第二章 目标说话人提取之《基于多模态信息的语音处理(misp) 2023挑战:视听目标说话人提取》 文章目录 THE MULTIMODAL INFORMATION BASED SPEECH PROCESS…

MCU或者SOC常见驱动3:USART通信

MCU或者SOC常见驱动3&#xff1a;USART通信 本文目的前置知识点UART简介主要特性通信流程数据帧格式所有数据帧满足的格式特殊的帧和用处&#xff08;不是很清楚对不对&#xff09; 参考文献 本文目的 简单的介绍USART通信一下是什么&#xff0c;有什么用&#xff0c;以及相关…

鸿蒙OS开发实例:【窥探网络请求】

HarmonyOS 平台中使用网络请求&#xff0c;需要引入 "ohos.net.http", 并且需要在 module.json5 文件中申请网络权限, 即 “ohos.permission.INTERNET” 本篇文章将尝试使用 ohos.net.http 来实现网络请求 场景设定 WeiBo UniDemo HuaWei : 请求顺序WeiBo1 UniDem…

同元软控专业模型库系列——液压气动篇

01 引言 近年来&#xff0c;数字液压技术在工业领域的应用逐渐推广&#xff0c;为提升生产效率、降低能源消耗、实现智能化制造提供了新的可能性。数字液压技术的应用已经覆盖了工程机械、航空航天、能源设备等众多领域&#xff0c;具有巨大的发展潜力。 行业技术的发展融合在…

机器人码垛机:智能仓储系统的重要组成部分

随着科技的飞速进步&#xff0c;机器人技术已经渗透到了许多行业领域&#xff0c;其中&#xff0c;仓储业尤为显著。机器人码垛机作为智能仓储系统的重要组成部分&#xff0c;不仅提高了码垛效率&#xff0c;还降低了人工成本和安全风险。然而&#xff0c;在其广泛应用的同时&a…

C# OpenCvSharp-HoughCircles(霍夫圆检测) 简单计数

目录 效果 项目 代码 下载 效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp; using O…

pycharm复习

1.字面量 2.注释&#xff1a; 单行注释# 多行注释" " " " " " 3.变量&#xff1a; 变量名 变量值 print&#xff1a;输出多个结果&#xff0c;用逗号隔开 4.数据类型&#xff1a; string字符串int整数float浮点数 t…

WebSocket 详解-小案例展示

简介&#xff1a;Websocket是一种用于H5浏览器的实时通讯协议&#xff0c;可以做到数据的实时推送&#xff0c;可适用于广泛的工作环境&#xff0c;例如客服系统、物联网数据传输系统&#xff0c;该测试工具可用于websocket开发初期的测试工作。 文章末尾有此案例的完整源代码。…

Arcgis中使用NDVI阈值法提取农田shape

首先有一幅NDVI影像TIFF&#xff0c;对其查看农田上的NDVI范围&#xff0c;大概是0.1以上&#xff0c;因为是12月份&#xff0c;小麦播种完1-2个月&#xff0c;此时NDVI并不是很高&#xff0c;但是树林基本叶子掉落了&#xff0c;所以比较好提取农田。 打开地图代数-栅格计算器…

【漏洞分析】浅析android手游lua脚本的加密与解密(一)

主要用到的工具和环境&#xff1a; 1 win7系统一枚 2 quick-cocos2d-x的开发环境&#xff08;弄一个开发环境方便学习&#xff0c;而且大部分lua手游都是用的cocos2d-x框架&#xff0c;还有一个好处&#xff0c;可以查看源码关键函数中的特征字符串&#xff0c;然后在IDA定位到…

选择华为HCIE培训机构有哪些注意事项

选择软件培训机构注意四点事项1、口碑&#xff1a;学员和社会人士对该机构的评价怎样&#xff1f; 口碑对于一个机构是十分重要的&#xff0c;这也是考量一个机构好不好的重要标准&#xff0c;包括社会评价和学员的评价和感言。誉天作为华为首批授权培训中心&#xff0c;一直致…

【计算机考研】数学难,到底难在哪里?看这一篇深度分析

数一和数二的难度系数都不在一个重量级&#xff01; 数一这货&#xff0c;容量真不是数二能比的&#xff01;除了高数、线代这些常规操作&#xff0c;还要啃概率论与数理统计这本大厚书&#xff0c;简直是让人头大&#xff01; 考研数学嘛&#xff0c;大家都知道&#xff0c;…

【详细讲解Android Debug Bridge各种命令及用法的文章】

&#x1f525;博主&#xff1a;程序员不想YY啊&#x1f525; &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f4ab; &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 &#x1f308;希望本文对您有所裨益&#xff0c;如有…

微服务demo(四)nacosfeigngateway

一、gateway使用&#xff1a; 1、集成方法 1.1、pom依赖&#xff1a; 建议&#xff1a;gateway模块的pom不要去继承父工程的pom&#xff0c;父工程的pom依赖太多&#xff0c;极大可能会导致运行报错&#xff0c;新建gateway子工程后&#xff0c;pom父类就采用默认的spring-b…