저는 오피스 문자열에 대한 총결산을 원합니다.

38930 단어 문자열

1. str* 시리즈 손글씨 코드


a. 끝부분'\0'처리에 유의하십시오.
b. 반드시 입력에 대해 유효성 판단을 해야 한다. 단언을 많이 하면 된다.
int Strlen(const char* str) {
    assert(str != NULL);
    const char* tmp = str;
    while (*tmp != '\0') {
        ++tmp;
    }
    return tmp - str;
}

char* Strcpy(char* dst, const char* src) {
    assert(dst != NULL && src != NULL);
    char* tmp = dst;
    while (*src != '\0') {
        *tmp++ = *src++;
    }
    *tmp = '\0';
    return dst;
}

char* Strncpy(char* dst, const char* src, int len) {
    assert(dst != NULL && src != NULL && len >= 0);
    char* tmp = dst;
    for (; len > 0 && *src != '\0'; --len) {
        *tmp++ = *src++;
    }
    for (; len > 0; --len) {
        *tmp ++ = '\0';
    }
    return dst;
}

char* Strcat(char* dst, const char* src) {
    assert(dst != NULL && src != NULL);
    char* tmp = dst;
    while (*tmp != '\0') {
        ++tmp;
    }
    while (*src != '\0') {
        *tmp++ = *src++;
    }
    *tmp = '\0';
    return dst;
}

char* Strncat(char* dst, const char* src, int len) {
    assert(dst != NULL && src != NULL && n >= 0);
    char* tmp = dst;
    while (*tmp != '\0') {
        ++tmp;
    }
    for (; len > 0 && *src != '\0'; --len) {
        *tmp++ = *src++;
    }
    *tmp = '\0';
    return dst;
}

int Strcmp(const char* str1, const char* str2) {
    assert(str1 != NULL && str2 != NULL);
    for (; *str1 == *str2; ++str1, ++str2) {
        if (*str1 == '\0') {
            return 0;
        }
    }
    if (*(unsigned char*)str1 < *(unsigned char*)str2) {
        return -1;
    } else {
        return 1;
    }
}

int Strncmp(const char* str1, const char* str2, int len) {
    assert(str1 != NULL && str2 != NULL && len >= 0);
    for (; len > 0; ++str1, ++str2) {
        if (*str1 != *str2) {
            return ((*(unsigned char*)str1) < (*(unsigned char*)str2) ? -1 : 1);
        } else if (*str1 == '\0') {
            return 0;
        }
    }
    return 0;
}

char* Strchr(const char* str, int c) {
    assert(str != NULL);
    const char* tmp = str;
    const char ch = (const char)c;
    for (; *tmp != ch; ++tmp) {
        if (*tmp == '\0') {
            return NULL;
        }
    }
    return (char*)tmp;
}

char* Strstr(const char* str1, const char* str2) {
    assert(str1 != NULL && str2 != NULL);
    if (*str2 == '\0') return str1;
    const char* tmp1 = str1;
    const char* tmp2 = str2;
    int len1 = Strlen(str1);
    int len2 = Strlen(str2);
    int i = 0;
    for (tmp1 = str1; i <= len1 - len2 && *tmp1 != '\0'; ++tmp1, ++i) {
        if (*tmp1 != *tmp2)
            continue;
        const char* cur1 = tmp1;
        const char* cur2 = tmp2;
        
        while (*cur1 == *cur2) {
            ++cur1;
            ++cur2;
            if (*cur2 == '\0') {
                return (char*)tmp1;
            }
        }
    }
    return NULL;
}

 

2. mem* 시리즈 손글씨 코드


반드시 입력에 대해 유효성 판단을 해야 하며, 단언을 많이 쓰면 된다
void* Memchr(const void* src, int c, int len) {
    assert(src != NULL && len >= 0);
    const unsigned char ch = c;
    const unsigned char* tmp = (const unsigned char*)src;
    for (; len > 0; --len, ++tmp) {
        if (*tmp == ch) {
            return (void*)tmp;
        }
    }
    return NULL;
}

int Memcmp(const void* s1, const void* s2, int len) {
    assert(s1 != NULL && s2 != NULL);
    const unsigned char* tmp1 = (const unsigned char*)s1;
    const unsigned char* tmp2 = (const unsigned char*)s2;
    for (; len > 0; --len, tmp1++, tmp2++) {
        if (*tmp1 != *tmp2) {
            return ((*tmp1 < *tmp2) ? -1 : 1);
        }
    }
    return 0;
}

void* Memcpy(void* dst, const void* src, int len) {
    assert(dst != NULL && src != NULL && len >= 0);
    char* dstTmp = (char*)dst;
    const char* srcTmp = (const char*)src;
    for (; len > 0; --len, ++dstTmp, ++srcTmp) {
        *dstTmp = *srcTmp;
    }
    return dst;
}

void* Memmove(void* dst, const void* src, int len) {
    assert(dst != NULL && src != NULL && len >= 0);
    char* dstTmp = (char*)dst;
    const char* srcTmp = (const char*)src;
    if (dstTmp > srcTmp && dstTmp < srcTmp + len) {
        for (srcTmp += n, dstTmp += n; len > 0 ; --len, --srcTmp, --dstTmp) {
            *dstTmp = *srcTmp;
        }
    } else {
        for (; len > 0; --len, ++srcTmp, ++dstTmp) {
            *dstTmp = *srcTmp;
        }
    }
    return dst;
}

 

3. atoi 함수


atoi 함수의 실현
class Solution {
public:
    int atoi(const char *str) {
        assert(str != NULL);
        const char* curr = str;
        const int maxRange = 10; int tmp = 0;
        int num = 0;
        while(isspace(*curr)) {
            ++curr;
        }
        const char* start = nullptr;
        char sign;
        if (*curr == '-' || *curr == '+') {
            sign = *curr;
            ++curr;
            start = curr;
        }  else {
            start = curr;
        }
        
        while (isdigit(*curr)) {
            tmp = num;
            num = num * 10 + (*curr - '0');
            ++curr;
        }
        int len = 0;
        if (!isdigit(*curr)) {
            len = curr - start;
        }
        --curr;
        if (len > maxRange || num < num - *curr) {
            if (sign == '-') {
                return INT_MIN;
            } else {
                return INT_MAX;
            }
        }
        if (sign == '-')  num = -num;
        return num;
    }
};

 

4.std::string 구현


c++ std::string의 간편한 실현
class Mystring {
    public:
        Mystring() : data_(new char[1]) {
            *data = '\0';
        }

        explicit Mystring(const char* str) : data_(new char[strlen(str) + 1]) {
            strcpy(data_, str);
        }

        explicit Mystring(const Mystring& str) : data_(new char[str.size() + 1]) {
            strcpy(data_, str.c_str());
        }

        ~Mystring() {
            delete[] data_;
        }
        
        //     ,  copy and swap  ,    
        Mystring& operator=(const Mystring& str) {
            Mystring tmp(str);
            swap(tmp);
            return *this;
        }

        //     ,  copy and swap  ,    
        Mystring& operator=(Mystring& str) {
            swap(str);
            return *this;
        }

        int size() const {
            return (int)strlen(data_);
        }
        const char* c_str() const {
            return data_;
        }

        void swap(Mystring& str) {
            std::swap(data_, str.data_);
        }
    private:
        char* data_;
};

a. Mystring 클래스는 내장형 int와 같이 변수를 정의할 수 있고 복사할 수 있으며 값을 부여할 수 있습니다
b. Mystring은 함수 매개 변수와 반환 값 유형으로 사용할 수 있습니다.
c. Mystring은 표준 라이브러리 컨테이너의 요소 유형, 즉vector/list/deque의valuetype
d. RAII를 이용하여 자원을 정확하게 관리하고 구조 함수에서만 new char[]를 호출하며 분석 함수에서만 delete[]를 호출한다.
e. 재부팅 연산자 사용 copy and swap 수법
 

5. 스트로 대수 계산


남-수

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1.size() == 0 || num2.size() == 0) return "";
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        
        vector<int> result(num1.size() + num2.size(), 0);
        int count = 0;
        for (int i = 0; i < num1.size(); ++i) {
            for (int j = 0; j < num2.size(); ++j) {
                result.at(i+j) += (num1.at(i) - '0') * (num2.at(j) - '0');
            }
        }
        for (int i = 0; i < result.size(); ++i) {
            int tmp = result.at(i) + count;
            result.at(i) = tmp % 10;
            count = tmp / 10;
        }
        
        int zeroPos = 0;
        for (zeroPos = result.size() - 1; zeroPos >= 0; --zeroPos) {
            if (result.at(zeroPos) != 0) break;
        }
        result.erase(result.begin() + zeroPos + 1, result.end());
        reverse(result.begin(), result.end());
        
        string res(result.size(), '0');
        for (int i = 0; i < result.size(); ++i) {
            res.at(i) += result.at(i);
        }
        
        
        if (res == "") {
            return "0";
        } else {
            return res;
        }
    }
};

 

6. 왜 char*p = "hello"라는 표현을 금지합니까?


C언어를 공부하는 학우들은 반드시char*p="hello"와 같은 문법을 본 적이 있다. 지금 내가 하고 싶은 말은 절대로 이렇게 쓰지 말라는 것이다.
int main() {
    char* p1 = "hello";
    char* p2 = "hello";
    char p3[] = "hello";
    char p4[] = "hello";
    fprintf(stdout, "%p:%p
", p1, p2); fprintf(stdout, "%p:%p
", p3, p4); return 0; }

프로그램 결과: p1은 p2이고 p3은 p4가 아닙니다
p1은 p2와 같다. "Hello"는 문자열 상수로 전역 const 구역에 위치하고 있다. 첫째, 상수 const이다. 둘째, 수정될 수 없다. 전역적이다. 즉, 모든 "Hello"를 가리키는 바늘의 주소 값은 똑같다.
p3은 p4:p3과 p4가 아닌 문자 그룹으로 창고에 위치하고 문자 그룹의 문자는 수정할 수 있습니다
 
요약:
    char* p1 = "hello";    
    char p3[] = "hello";

p1: 가리키는 내용은 수정할 수 없음 (전역const), p1 바늘은 수정할 수 있음 (지향을 변경할 수 있음)
p3: 가리키는 요소는 수정할 수 있음(일반 수조), p3는 수정할 수 없음(수조 이름이 지침일 때 수조의 첫 번째 주소를 표시하므로 수정할 수 없음)
 
char*p = "hello"로 돌아가기
앞에서 우리가 설명한 바와 같이 p가 가리키는 내용은 수정할 수 없다. 즉, p는 const를 가리키는 지침이다.
const char* p1 = "hello";

왜 const를 넣었을까요?
왜냐하면char*p="hello"는 실제constchar*은밀히char*로 변환하기 때문에 모든 악의 변환입니다. 코드를 보십시오.
    char* p1 = "this is wrong";
    char* p2 = "hello world";
    strcpy(p1, p2);

컴파일링이 통과되었는데, 실행하시겠습니까?하하
앞에서 말했듯이 p1은 실제로constchar*입니다. 지금 p1을 통해const를 수정하려면 반드시 코어 dump가 필요합니다.
그런데 우리가 이렇게 쓰면?
    const char* p1 = "this is wrong";
    const char* p2 = "hello world";
    strcpy(p1, p2);

컴파일 오류!!!(주: g++ - Wall 컴파일을 사용합니다)
 
요약:
char* p1 = "this is wrong"; //        const       ,  p1               
const char* p1 = "this is right"; //  const        const  ,  p1               

 
위에서 strcpy 함수를 예로 사용한 이상strcpy 문제를 다시 말하다
만약 상술한 문제를 모두 이해했다면 다음과 같은 코드이다.
int main() {
    char dst[] = "this is right";
    const char* src = "hello world";
    strcpy(dst, src);
    fprintf(stdout, "%s", dst);
    return 0;
}

 
운행은 모두 좋지만, 내가 말하고 싶은 것은strcpy와 같은 함수를 사용하지 말라는 것이다.
우리는 C 언어 표준 라이브러리에 strcpy,strcat,strcmp가 있다는 것을 안다
C 표준 라이브러리에도 다음과 같은 함수가 있다:strncpy,strncat,strncmp
strcpy strncpy를 예로 들다
strcpy는 src의'\0'을 만나야만 복사를 끝냅니다. dst의 공간이 src를 수용할 수 있든 없든 간에 버퍼가 넘치기 쉽습니다.××공격이 쇄도하다
그래서 strcpy에 대응하는'안전'버전이 생겼습니다. strncpy, strncpy는 원래 strcpy의 불안정성을 해결하려고 했지만 그 의미는 정말 사람을 아프게 합니다.
strncpy는 src의 전 n 바이트만 복제합니다. 만약 src의 전 n 바이트에 종료자 '\0' 이 포함되지 않는다면 문제가 발생합니다. src의 종료자를 복제하지 않습니다.어이가 없네.
 
일반적으로 strncpy를 사용하는 방법은 다음과 같습니다.
strncpy(dst, src, strlen(dst));

좋은 웹페이지 즐겨찾기