头像

小小蒟蒻




离线:1天前


最近来访(213)
用户头像
Song_S
用户头像
QWQ686
用户头像
牛牛蒟蒻
用户头像
流影剑客
用户头像
println好好学习
用户头像
hanwenwang
用户头像
supreme菜鸡
用户头像
Tobt
用户头像
yingking0608
用户头像
.CHY
用户头像
芒叉味阿米
用户头像
不要不听话
用户头像
思念变成海.
用户头像
可达
用户头像
鳕鱼饭
用户头像
偶尔也会翻身的咸鱼
用户头像
派大星
用户头像
钉宫无路赛
用户头像
itdef
用户头像
清闲


小小蒟蒻
1个月前
// 不用数组缓存数位值的实现方式
#include <stdio.h>

#define SINGAL(data) (data & (1 << (8 * sizeof(data) - 1)))
//#define SINGAL(data) ((data >> (8 * sizeof(data) - 1)) & 1)

/*
* 显示数据
* 1) 查找数据的前导0, 一旦遇到非零表示遇到了实际表达数值的数字
     每一个前导零都用字符F替换
* 2) 在输出数字时屏蔽前导零
* 
* 3) 将数分为3类,
*    0直接输出
*    负数前面的前导F, 例如FF FF FF F4, 前缀FF FF FF, 后缀F4
*    在确定前面的FF时, 掩码为FF000000
*    在确定一位十六进制数位的值时, 掩码为F0000000
*    正数没有F前缀, 把整体看成后缀
*/
void showPrefix(unsigned int x) {
    int n = (8 * sizeof(x)) >> 2;
    // 定义掩码
    int mask = 0xF0000000;
    // 从最高bit位开始, 步进为4bit(因为16进制的f占4个bit位)
    for (int i = 0; i < n; i++, x <<= 4) {
        if (!(x & mask))    // 0 & f == 0
            printf("F");    // 用字符F替换零输出

        else                // 1 & f == 1
            break;          // 前导0是连续的,一旦不是零就是实际数字
    }
}

void showSuffix(unsigned int x) {
    int n = (8 * sizeof(x)) >> 2;
    int mask = 0xF0000000;
    int last = 0;           // 表示上次的数值是0  
    for(int i = 0; i < n; i++, x <<= 4) {
        // 截取x的最高4个比特位, 并将这4比特位移动到最低的4比特位
        int t = (x & mask) >> 28;  

        // 屏蔽前导0
        if (last == 0) {  // 前一次的值为0
            if (t == 0)   // 当前的值为0
                continue;
            else last = 1; // 当前的值已非0
        }

        switch (t) {
            case 10: printf("A"); break;
            case 11: printf("B"); break;
            case 12: printf("C"); break;
            case 13: printf("D"); break;
            case 14: printf("E"); break;
            case 15: printf("F"); break;
            default: printf("%d", t); break;
        }
    }
}

void showData(int x, int singal) {
    if (singal == 1) {  // 负数
        showPrefix(x);  // 显示前缀F
        showSuffix(x);  // 显示后缀的值
    }
    else { 
        showSuffix(x); // 正数只有后缀
    }
}

void convertHex(int x) {
    if (x == 0) {      // 0直接输出
        printf("0");
        return;
    }

    unsigned int tmp = x;        // 将有符号数当成无符号数看待
    if (SINGAL(x) == 1) {        // 负数要拆分出后缀
        int mask = 0xFF000000;
        int moveBtyes = 0;       // 去掉前缀, 负数应该左移的字节数
        for (int i = 0; i < sizeof(x); i++) {
            if ((tmp & mask) == mask)  // 在负数的高位截取的字节中的内容是FF
                moveBtyes++;           // 应该左移一个字节 
            else                       // 否则表明已经处理完前缀
                break;                 

            tmp = (tmp << 8);          // 对数值进行实际的左移
        }

        tmp >>= (8 * moveBtyes);       // 为了方便后续的解读, 将后缀值放到内存的低地址处
    }

    showData(tmp, SINGAL(x));          // 按照符号来显示数据
}

int main() {
    int a[] = { -100, 100, -127, 127, -128, 128, -4832, 4832, -978670, 978670 };
    int n = sizeof(a) / sizeof(a[0]);

    puts("十进制数\t十六进制数");
    for (int i = 0; i < n; i++) {
        printf("%d\t\t", a[i]);
        convertHex(a[i]);
        puts("");
    }

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char* convertHex(unsigned char* dec, int len) {
    // 目标字符数串数组的长度为源数组的长度的两倍加一
    int n = 2 * len * sizeof(unsigned char) + 1;
    unsigned char* hex = (unsigned char*)malloc(n);  // 申请内存
    if (hex == NULL)  // 申请内存失败
        return NULL;

    memset(hex, '\0', n);   // 初始化目标数组的内容
    unsigned char* q = hex + n - 2;  // 初始化目标数组的指针
    // 按照元素组的长度遍历获取到十六进制数位上的值
    for (unsigned char* p = dec; p < dec + len; p++, q -= 2) {
        *(q - 0) = *p & 0x000F;        // 获取字节上低4位的值
        *(q - 1) = (*p >> 4) & 0x000F; // 获取字节上高4位的值
    }
    return hex;
}

void showData(unsigned char* hex, int n) {
    // 记录上一次前导字符是否为0
    // 0: 前一个值是0, 1: 前一个值不是0  
    int last = 0;   
    for (unsigned char* p = hex; p < hex + (n - 1); p++) {
        // 屏蔽前导0
        if (last == 0) {  // 前一次的值为0
            if (*p == 0)   // 当前的值为0
                continue;
            else last = 1; // 当前的值已非0
        }

        switch (*p) {
            case 10: printf("A"); break;
            case 11: printf("B"); break;
            case 12: printf("C"); break;
            case 13: printf("D"); break;
            case 14: printf("E"); break;
            case 15: printf("F"); break;
            default: printf("%d", *p); break;
        }
    }
}

int main() {
    puts("十进制数\t十六进制数");
    int dec[] = { -100, 100, -127, 127, -128, 128, -4832, 4832, -978670, 978670 };
    int n = sizeof(dec) / sizeof(dec[0]);  

    for (int i = 0; i < n; i++) {
        unsigned char* hex = convertHex((unsigned char*)&dec[i], sizeof(int));
        if (hex == NULL)
            return 1;

        // hex字符数组的长度
        // 目标字符数串数组的长度为源数组的长度的两倍加一
        int m = 2 * sizeof(int) * sizeof(unsigned char) + 1;
        printf("%d\t\t", dec[i]);
        showData(hex, m);
        puts("");

        free((void*)hex);
        hex = NULL;
    }
    return 0;
}



小小蒟蒻
1个月前

11.png

#ifndef __VECTOR_H__
#define __VECTOR_H__

#define FALSE       0
#define TRUE        1
#define CAPACITY   10
#define FAILURE     0           // 操作失败 
#define SUCCESS     1           // 操作成功
#define INFINITE   -1           // 最大索引

typedef int Boolean;
typedef int Status;             // 操作状态
typedef int ElemType;
typedef unsigned int size_t;

typedef struct _tagVec {
    ElemType* base;
    size_t size;
    size_t capacity;
} vector;

extern int Equal(ElemType e1, ElemType e2);
extern int Compare(ElemType e1, ElemType e2);
extern void InitVector(vector* v);
extern Status DestroyVector(vector* v);
extern Boolean IsEmptyVector(vector* v);
extern void ClearVector(vector* v);
extern size_t VectorSize(vector* v);
extern size_t VectorCapacity(vector* v);
extern Status PushBack(vector* v, ElemType e);
extern Status PopBack(vector* v);
extern Status AddElem(vector* v, size_t i, ElemType e);
extern Status InsertElemsBefore(vector* v, size_t i, ElemType e[], size_t n);
extern Status InsertElemsAfter(vector* v, size_t i, ElemType e[], size_t n);
extern Status DelElemByValue(vector* v, ElemType e);         // 删除元素
extern Status DelByIndex(vector* v, size_t beg, size_t end); // 删除区间是[beg, end)
extern Status UpdateByIndex(vector* v, size_t beg, ElemType* e, size_t n); // 区间上的数据更新
extern int DistinctElem(vector* v, size_t l, size_t r, size_t k, int flag); // k是要保持的重复元素的个数
extern void qSort(vector* v, size_t l, size_t r, int flag);  // flag = -1 表示升序, flag = 1 表示降序
extern Status findByIndex(vector* v, size_t i, ElemType* pElem);
extern Status SearchByValue(vector* v, ElemType e, size_t* res);

#endif // !__VECTOR_H__
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "vector.h"

int Equal(ElemType e1, ElemType e2) {
    if (e1 == e2)
        return 0;

    return 1;
}

int Compare(ElemType e1, ElemType e2) {
    if (0 == Equal(e1, e2))
        return 0;

    return (e1 - e2) / abs(e1 - e2);
}

void InitVector(vector* v) {
    v->base = NULL;
    v->size = 0;
    v->capacity = 0;
}

Status DestroyVector(vector* v) {
    if (v == NULL)
        return FAILURE;

    if (v->base != NULL) {
        free((void*)v->base);
        v->base = NULL;
    }

    v->size = 0;
    v->capacity = 0;
    return SUCCESS;
}

Boolean IsEmptyVector(vector* v) {
    assert(v != NULL);
    return (v->size == 0);
}

void ClearVector(vector* v) {
    assert(v != NULL);
    v->size = 0;
}

size_t VectorSize(vector* v) {
    assert(v != NULL);
    if (v->size < 0)
        v->size = 0;

    return v->size;
}

size_t VectorCapacity(vector* v) {
    assert(v != NULL);
    if (v->capacity < 0)
        v->capacity = 0;

    return v->capacity;
}

Status PushBack(vector* v, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL) {
        v->base = (ElemType*)malloc(CAPACITY * sizeof(ElemType));
        if (v->base == NULL)
            return FAILURE;

        v->size = 0;
        v->capacity = CAPACITY;
    }

    if (v->size + 1 > v->capacity) // 当前存储空间已满,增加新内存
    {
        ElemType* newbase = NULL;
        newbase = (ElemType*)realloc(v->base, (2 * v->capacity) * sizeof(ElemType));
        if (newbase == NULL) {
            free((void*)v->base);
            v->capacity = 0;
            v->size = 0;
            return FAILURE;
        }

        v->base = newbase;
        v->capacity *= 2;
    }

    v->base[v->size] = e;
    v->size++;

    return SUCCESS;
}

Status PopBack(vector* v) {
    if (v == NULL || v->size == 0)
        return FAILURE;

    v->size--;
    return SUCCESS;
}

/*
* 在指定索引处添加数据
*/
Status AddElem(vector* v, size_t i, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL) {
        v->base = (ElemType*)malloc((i + 1 + CAPACITY) * sizeof(ElemType));
        if (v->base == NULL)
            return FAILURE;
    }
    else if(i + 1 > v->capacity) {
        ElemType* newbase = NULL;
        newbase = (ElemType*)realloc(v->base, (i + 1 + CAPACITY) * sizeof(ElemType));
        if (newbase == NULL) {
            free((void*)v->base);
            v->capacity = 0;
            v->size = 0;
            return FAILURE;
        }
        v->base = newbase;
    }

    if (i + 1 > v->capacity)
        v->capacity = (i + 1) + CAPACITY;

    if(i + 1 > v->size)
        v->size = (i + 1);

    *(v->base + i) = e;

    return SUCCESS;
}

Status InsertElemsBefore(vector* v, size_t i, ElemType e[], size_t n) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (i >= v->size)
        return FAILURE;

    if (v->size + n <= v->capacity) {
        memcpy(v->base + i + n, v->base + i, ((v->size - 1) - i + 1) * sizeof(ElemType));
        memcpy(v->base + i, e, n * sizeof(ElemType));
        v->size += n;
        return SUCCESS;
    }

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (2 * v->capacity + n) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    memcpy(newbase + i + n, newbase + i, ((v->size - 1) - i + 1) * sizeof(ElemType));
    memcpy(newbase + i, e, n * sizeof(ElemType));

    v->capacity = 2 * v->capacity + n;
    v->size += n;
    v->base = newbase;
    return SUCCESS;
}

Status InsertElemsAfter(vector* v, size_t i, ElemType e[], size_t n) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->size < 1 || v->size > v->capacity)
        return FAILURE;

    if (i >= v->size)
        return FAILURE;

    if (v->size + n <= v->capacity) {
        memcpy(v->base + (i + 1) + n, v->base + (i + 1), ((v->size - 1) - (i + 1) + 1) * sizeof(ElemType));
        memcpy(v->base + (i + 1), e, n * sizeof(ElemType));
        v->size += n;
        return SUCCESS;
    }

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (2 * v->capacity + n) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    memcpy(newbase + (i + 1) + n, newbase + (i + 1), ((v->size - 1) - (i + 1) + 1) * sizeof(ElemType));
    memcpy(newbase + (i + 1), e, n * sizeof(ElemType));

    v->capacity = 2 * v->capacity + n;
    v->size += n;
    v->base = newbase;
    return SUCCESS;
}

Status DelElemByValue(vector* v, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity == 0 || v->size == 0)
        return FAILURE;

    // 所谓的双指针算法
    // 来自leecode的小算法, 一次性去除所有重复元素
    // https://leetcode.cn/leetbook/read/array-and-string/cwuyj/
    /*size_t j = 0;
    for (size_t i = 0; i < v->size; i++) {
        if (v->base[i] != e) {   // 没有把子集从集合中拿出来, 遍历所有元素来删除子集的元素
            v->base[j] = v->base[i];
            j++;
        }
    }*/

    // 可以介绍一下下面的代码为什么与上面的代码具有同等的功效
    // 为什么if可以替换成for, 再介绍一下在哪些情况下if不可以被for替换
    size_t j = 0;
    for (size_t i = 0; i < v->size; i++) {
        // 我认为满足条件(v->size && v->base[i] != e)的元素是上面集合的一个子集
        // 遍历删除子集元素使用for循环, 看似是二重循环,其实是把一个大集合分成了两类
        // 满足条件的子集与不满足条件的子集, 将满足条件的子集给覆盖掉
        for(; i < v->size && v->base[i] != e; i++) {
            v->base[j] = v->base[i];
            j++;
        }
    }

    if (j >= v->size)
        return FAILURE;

    v->size = j;

    // 空闲容量过多, 重新调整容量的大小
    if (2 * v->size >= v->capacity)
        return SUCCESS;

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (v->capacity / 2 + 1) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    v->capacity = v->capacity / 2 + 1;
    v->base = newbase;
    return SUCCESS;
}

Status DelByIndex(vector* v, size_t beg, size_t end) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity == 0 || v->size == 0)
        return FAILURE;

    if (beg > end) {
        size_t t = beg;
        beg = end;
        end = t;
    }

    // 要删除的区间是[beg, end)且r >= size 
    // 只要保留区间[0, l)
    if (end >= v->size) {  
        v->size = beg;
        return SUCCESS;
    }

    // 要删除的区间是[0, ... , [beg, ... , end), ... , size - 1]  
    // 要删除的个数: (size - 1) - end + 1
    // 基本常识, 个数 = 尾数索引 - 首数索引 + 1
    // memcpy(v->base + beg, v->base + end + 1, ((v->size - 1) - end + 1) * sizeof(ElemType));
    // v->size -= end - beg + 1;

    // 要删除的区间是[0, ... , [beg, ... , end - 1], end... , size - 1]
    // 要删除的个数: end - 1 - beg + 1 (基本常识, 个数 = 尾数索引 - 首数索引 + 1)
    // 要移动的元素个数: size - 1 + end + 1
    memcpy(v->base + beg, v->base + end, ((v->size - 1) - end + 1) * sizeof(ElemType));
    v->size -= end - beg;
    return SUCCESS;
}

void qSort(vector* v, size_t l, size_t r, int flag) {
    if ((r >= v->size && r - l < 2) || (r < v->size && r - l < 1))
        return;

    int m = v->base[(l + r) >> 1];
    int i = l - 1, j = 0;
    if (r < v->size)
        j = r + 1;
    else
        j = r;

    while (i < j) {
        while (Compare(v->base[++i], m) == flag);
        while (Compare(m, v->base[--j]) == flag);

        if (i < j) {
            int t = v->base[i];
            v->base[i] = v->base[j];
            v->base[j] = t;
        }
    }

    qSort(v, l, j, flag);

    if (r < v->size)
        qSort(v, j + 1, r, flag);
    else
        qSort(v, j, r - 1, flag);
}

int DistinctElem(vector* v, size_t l, size_t r, size_t k, int flag) {
    if (k <= 0)
        return v->size;

    qSort(v, l, r, flag);

    // https://leetcode.cn/leetbook/read/all-about-array/x9nivs/
    size_t j = 0;
    for (size_t i = 0; i < v->size; i++) {
        // j小于k时, a[i]直接覆盖a[j], 此时i == j(元素自己覆盖自己)
        // j大于等于k且a[j - k] != a[i]时, a[i]覆盖a[j]
        // [0, k)上的元素值被保留
        if (j < k || v->base[j - k] != v->base[i]) {
            v->base[j] = v->base[i];
            j++;
        }
    }
    v->size = j;
    return j;
}

Status UpdateByIndex(vector* v, size_t beg, ElemType* e, size_t n) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity == 0 || v->size == 0)
        return FAILURE;

    if (beg + n >= v->size) {
        if (beg + n >= v->capacity) {
            ElemType* newBase = (ElemType*)realloc(v->base, (v->capacity + n + CAPACITY) * sizeof(ElemType));
            if (newBase == NULL)
                return FAILURE;

            v->base = newBase;
            v->capacity = n + CAPACITY;
        }
        memcpy(v->base + beg, e, n * sizeof(ElemType));
        v->size = beg + n;
        return SUCCESS;
    }

    memcpy(v->base + beg, e, n * sizeof(ElemType));
    return SUCCESS;
}

// 要初始化e = NULL, 返回失败e必定为null
Status findByIndex(vector* v, size_t i, ElemType* e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if(i >= v->size)
        return FAILURE;

    *e = v->base[i];
    return SUCCESS;
}

Status SearchByValue(vector* v, ElemType e, size_t* res) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    for (size_t i = 0; i < v->size; i++) {
        if (v->base[i] == e) {
            *res = i;
            return SUCCESS;
        }
    }

    *res = (size_t)INFINITE;
    return FAILURE;
}
#include <stdio.h>
#include "vector.h"

void TestPushBack() {
    printf("TestPushBack\n");
    ElemType e[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    size_t n = sizeof(e) / sizeof(ElemType);

    vector v;
    InitVector(&v);

    printf("在执行从后面插入前动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[]");

    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);
    printf("\n");

    printf("在执行从后面插入后动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[");
    for (size_t i = 0; i < n; i++) {
        if (i < n - 1)
            printf("%d ", v.base[i]);
        else 
            printf("%d", v.base[i]);
    }
    printf("]\n");

    DestroyVector(&v);
    printf("\n");
}

void TestPopBack() {
    printf("TestPopBack\n");
    ElemType e[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    size_t n = sizeof(e) / sizeof(ElemType);

    vector v;
    InitVector(&v);

    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    printf("从后面弹出执行后动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[");
    for (size_t i = 0; i < n; i++) {
        if (i < n - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    while (v.size != 0) {
        PopBack(&v);
        printf("大小%d, 容量%d ", v.size, v.capacity);

        printf("元素[");
        for (size_t i = 0; i < v.size; i++) {
            if (i < v.size - 1)
                printf("%d ", v.base[i]);
            else
                printf("%d", v.base[i]);
        }
        printf("]\n");
    }

    DestroyVector(&v);
    printf("\n");
}

void TestAddOneElem() {
    printf("TestAddOneElem\n");
    vector v;
    InitVector(&v);

    printf("在插入一个元素前动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[]\n");

    AddElem(&v, 1, 9);
    printf("在插入一个元素后动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[");

    for (size_t i = 0; i < v.size; i++) {
        if (v.base[i] == 0xcdcdcdcd)  
            continue;

        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    DestroyVector(&v);
    printf("\n");
}

void TestRadomAddElems() {
    printf("TestRadomAddElems\n");
    vector v;
    InitVector(&v);
    printf("乱插元素之前动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[]\n");

    ElemType e[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // 指定元素值 
    size_t idx[] = { 3, 6, 1, 2, 9, 5, 7, 8, 0, 4 };  // 指定乱序索引

    size_t n = sizeof(e) / sizeof(ElemType);

    for (size_t i = 0; i < n; i++) {
        AddElem(&v, idx[i], e[i]);
        printf("[");
        for (size_t i = 0; i < v.size; i++) {
            if (v.base[i] == 0xcdcdcdcd)
                continue;

            if (i < v.size - 1)
                printf("%d ", v.base[i]);
            else
                printf("%d", v.base[i]);
        }
        printf("] 大小%d, 容量%d\n", v.size, v.capacity);
    }

    DestroyVector(&v);
    printf("\n");
}

void TestInsertBefore() {
    printf("TestInsertBefore\n");
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 6, 4, 2, 8, 10, 11 };
    size_t n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    for (size_t i = 0; i < v.size; ++i)
            printf("%d ", v.base[i]);
        printf("\n");


    puts("动态数组中每个元素的前面插入10, 11, 12");
    ElemType a[] = { 10, 11, 12 };
    n = sizeof(a) / sizeof(a[0]);
    for (size_t i = 0; i < v.size; i += 4)
        InsertElemsBefore(&v, i, a, n);

    size_t j = 0;
    for (size_t i = 0; i < v.size; ++i, ++j) {
        if (i != 0 && i % 32 == 0)  // 32个数据为一行
            printf("\n");

        if (j != 0 && j % 3 == 0)   // 原来数组中的元素用[]括起来
            printf("[%d] ", v.base[i]);
        else
            printf("%d ", v.base[i]);
        if (j > 3) j = 0;
    }
    printf("\n");

    DestroyVector(&v);
    printf("\n");
}

void TestInsertAfter() {
    printf("TestInsertAfter\n");
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 6, 4, 2, 8, 10, 11 };
    size_t n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    for (size_t i = 0; i < v.size; ++i)
        printf("%d ", v.base[i]);
    printf("\n");

    puts("动态数组中每个元素的后面插入10, 11, 12");
    ElemType a[] = { 10, 11, 12 };
    n = sizeof(a) / sizeof(a[0]);
    for (size_t i = 0; i < v.size; i += 4)
        InsertElemsAfter(&v, i, a, n);

    size_t j = 0;
    for (size_t i = 0; i < v.size; ++i, ++j) {
        if (i != 0 && i % 32 == 0)
            printf("\n");

        if (j == 0 || j % 4 == 0)
            printf("[%d] ", v.base[i]);
        else
            printf("%d ", v.base[i]);
        if (j > 3) j = 0;
    }
    printf("\n");

    DestroyVector(&v);
    printf("\n");
}

void TestDelElem() {
    printf("TestDelElem\n");
    ElemType e[] = { 3, 0, 1, 2, 3, 4, 5, 3, 6, 7, 8, 9, 3 };
    size_t n = sizeof(e) / sizeof(ElemType);

    vector v;
    InitVector(&v);

    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    printf("执行后插后动态数组的大小%d, 容量%d ", v.size, v.capacity);
    printf("元素[");
    for (size_t i = 0; i < n; i++) {
        if (i < n - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    DelElemByValue(&v, 3);
    printf("元素[");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");
    printf("\n");
}

void TestDistinctElem() {
    printf("TestDistinctElem\n");
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 2, 2, 2, 6, 4, 2, 8, 10, 11, 2 };
    size_t n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    printf("插入数据后数组的大小是%d, 容量是%d ", v.size, v.capacity);
    printf("元素是[");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    puts("元素去重,重复元素保留2个");
    DistinctElem(&v, 0, v.size, 2, 1);
    printf("元素[");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");
    printf("\n");
}

void TestDelByIndex() {
    printf("TestDelByIndex\n");
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 2, 2, 2, 6, 4, 2, 8, 10, 11, 2 };
    size_t n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    for (size_t i = 0; i < n; i++)
        PushBack(&v, e[i]);

    printf("插入数据后数组的大小是%d, 容量是%d ", v.size, v.capacity);
    printf("元素是[");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    size_t beg = 3, end = 7;
    DelByIndex(&v, 3, 7);
    printf("数据元素是 [");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");
    DestroyVector(&v);
    printf("\n");
}

void TestUpdateByIndex() {
    printf("TestUpdateByIndex\n");
    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 2, 2, 2, 6, 4, 2, 8, 10, 11, 2 }; // { 11, 11, 11 }; 
    size_t n = sizeof(e) / sizeof(ElemType);

    printf("源数据是 [");
    for (size_t i = 0; i < n; i++) {
        if (i < n - 1)
            printf("%d ", e[i]);
        else
            printf("%d", e[i]);
    }
    printf("]\n");

    vector v;
    InitVector(&v);

    for (size_t i = 0; i < 10; i++)
        PushBack(&v, i);

    printf("目标数据是 [");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    int beg = 3;
    UpdateByIndex(&v, beg, e, n);

    printf("更新后数据是 [");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");
    DestroyVector(&v);
    printf("\n");
}

void TestSearchByValue() {
    printf("TestSearchByValue\n");
    vector v;
    InitVector(&v);
    for (size_t i = 0; i < 10; i++)
        PushBack(&v, i);

    printf("数据是 [");
    for (size_t i = 0; i < v.size; i++) {
        if (i < v.size - 1)
            printf("%d ", v.base[i]);
        else
            printf("%d", v.base[i]);
    }
    printf("]\n");

    size_t res = INFINITE;
    if (SUCCESS == SearchByValue(&v, 3, &res) && res != INFINITE)
        printf("查找到数据");
    else 
        printf("查找不到数据");

    DestroyVector(&v);
    printf("\n");
}

int main() {
    TestPushBack();
    TestPopBack();
    TestAddOneElem();
    TestRadomAddElems();
    TestInsertBefore();
    TestInsertAfter();
    TestDelElem();
    TestDistinctElem();
    TestDelByIndex();
    TestUpdateByIndex();
    TestSearchByValue();

    return 0;
}
#ifndef __VECTOR_H__
#define __VECTOR_H__

#include <stdio.h>

#define FALSE       0
#define TRUE        1
#define CAPACITY   10
#define FAILURE     0           // 操作失败 
#define SUCCESS     1           // 操作成功
#define INFINITE   -1           // 最大索引

typedef int Boolean;
typedef int Status;             // 操作状态
typedef int ElemType;
typedef int size;

typedef struct _tagVector
{
    ElemType* base;
    size size;
    size capacity;
} vector;

extern int Equal(ElemType e1, ElemType e2);
extern int Compare(ElemType e1, ElemType e2);
extern void InitVector(vector* v);
extern Status DestroyVector(vector* v);
extern Boolean IsEmptyVector(vector* v);
extern void ClearVector(vector* v);
extern size VectorSize(vector* v);
extern size VectorCapacity(vector* v);
extern size LocateElem(vector* v, int i, ElemType cur, int(*comp)(ElemType, ElemType));
extern Status AddElemInSize(vector* v, int i, ElemType e);
extern Status DelElemInSize(vector* v, int i);
extern Status AddElem(vector* v, ElemType e);
extern Status DelElem(vector* v, ElemType e);
extern Status InsertElemsBefore(vector* v, int i, ElemType e[], int n);
extern Status InsertElemsAfter(vector* v, int i, ElemType e[], int n);
extern Status GetElem(vector* v, int i, ElemType* e);
extern int DistinctElem(vector* v, int l, int r, int k, int flag); // k是要保持的重复元素的个数
extern void qSort(vector* v, int l, int r, int flag);  // flag = -1 表示升序, flag = 1 表示降序
extern void Travel(vector* v);

#endif // !__VECTOR_H__
#include "vector.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int Equal(ElemType e1, ElemType e2) {
    if (e1 == e2)
        return 0;

    return 1;
}

int Compare(ElemType e1, ElemType e2) {
    if (0 == Equal(e1, e2))
        return 0;

    return (e1 - e2) / abs(e1 - e2);
}

Status DestroyVector(vector* v) {
    if (v == NULL)
        return FAILURE;

    if (v->base != NULL) {
        free((void*)v->base);
        v->base = NULL;
    }

    v->size = 0;
    v->capacity = 0;
    return SUCCESS;
}

void InitVector(vector* v) {
    v->base = NULL;
    v->size = 0;
    v->capacity = 0;
}

Boolean IsEmptyVector(vector* v) {
    assert(v != NULL);
    return (v->size == 0);
}

void ClearVector(vector* v) {
    assert(v != NULL);
    v->size = 0;
}

size VectorSize(vector* v) {
    assert(v != NULL);
    if (v->size < 0) 
        v->size = 0;

    return v->size;
}

size VectorCapacity(vector* v) {
    assert(v != NULL);
    if (v->capacity < 0)
        v->capacity = 0;

    return v->capacity;
}

Status AddElemInSize(vector* v, int i, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (i < 0 || (i > 0 && i > v->size))
        return FAILURE;

    if (v->size > v->capacity)
        return FAILURE;

    v->base[i] = e;
    v->size++;

    return SUCCESS;
}

Status AddElem(vector* v, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL) {
        v->base = (ElemType*)malloc(CAPACITY * sizeof(ElemType));
        if (v->base == NULL) 
            return FAILURE;

        v->size = 0;
        v->capacity = CAPACITY;
    }

    if (v->size + 1 > v->capacity) // 当前存储空间已满,增加分配
    {
        ElemType* newbase = NULL;
        newbase = (ElemType*)realloc(v->base, (2 * v->capacity) * sizeof(ElemType));
        if (newbase == NULL) {
            free((void*)v->base);
            v->capacity = 0;
            v->size = 0;
            return FAILURE;
        }

        v->base = newbase;
        v->capacity *= 2;
    }

    v->base[v->size] = e;
    v->size++;

    return SUCCESS;
}

Status DelElemInSize(vector* v, int i) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity < 1 || v->size < 1)
        return FAILURE;

    if (i < 0 || i >= v->size)
        return FAILURE;

    for (int j = i; j < v->size - 1; ++j) 
        v->base[j] = v->base[j + 1];

    v->size--;
    return SUCCESS;
}

Status DelElem(vector* v, ElemType e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity < 1 || v->size < 1)
        return FAILURE;

    int j = 0;
    for (int i = 0; i < v->size; ++i) {
        if (v->base[i] != e) {
            v->base[j] = v->base[i];
            ++j;
        }
    }

    if (j >= v->size)
        return FAILURE;

    v->size = j;

    // 空闲容量过多, 重新调整容量的大小
    if (2 * v->size >= v->capacity)
        return SUCCESS;

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (v->capacity / 2 + 1) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    v->capacity = v->capacity / 2 + 1;
    v->base = newbase;
    return SUCCESS;
}

Status InsertElemsBefore(vector* v, int i, ElemType e[], int n) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (i < 0 || i >= v->size)
        return FAILURE;

    if (v->size + n <= v->capacity) {
        memcpy(v->base + i + n, v->base + i, ((v->size - 1) - i + 1) * sizeof(ElemType));
        memcpy(v->base + i, e, n * sizeof(ElemType));
        v->size += n;
        return SUCCESS;
    }

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (2 * v->capacity + n) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    memcpy(newbase + i + n, newbase + i, ((v->size - 1) - i + 1) * sizeof(ElemType));
    memcpy(newbase + i, e, n * sizeof(ElemType));

    v->capacity = 2 * v->capacity + n;
    v->size += n;
    v->base = newbase;
    return SUCCESS;
}

Status InsertElemsAfter(vector* v, int i, ElemType e[], int n) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->size < 1 || v->size > v->capacity)
        return FAILURE;

    if (i < 0 || i >= v->size)
        return FAILURE;

    if (v->size + n <= v->capacity) {
        memcpy(v->base + (i + 1) + n, v->base + (i + 1), ((v->size - 1) - (i + 1) + 1) * sizeof(ElemType));
        memcpy(v->base + (i + 1), e, n * sizeof(ElemType));
        v->size += n;
        return SUCCESS;
    }

    ElemType* newbase = NULL;
    newbase = (ElemType*)realloc(v->base, (2 * v->capacity + n) * sizeof(ElemType));
    if (newbase == NULL) {
        free((void*)v->base);
        v->capacity = 0;
        v->size = 0;
        return FAILURE;
    }

    memcpy(newbase + (i + 1) + n, newbase + (i + 1), ((v->size - 1) - (i + 1) + 1) * sizeof(ElemType));
    memcpy(newbase + (i + 1), e, n * sizeof(ElemType));

    v->capacity = 2 * v->capacity + n;
    v->size += n;
    v->base = newbase;
    return SUCCESS;
}

Status GetElem(vector* v, int i, ElemType* e) {
    if (v == NULL)
        return FAILURE;

    if (v->base == NULL)
        return FAILURE;

    if (v->capacity <= 0)
        return FAILURE;

    if (v->size < 0 || v->size > v->capacity)
        return FAILURE;

    if (i < 0 || i + 1 > v->size)
        return FAILURE;

    *e = *(v->base + i);
    return SUCCESS;
}

size LocateElem(vector* v, int i, ElemType cur, int(*comp)(ElemType, ElemType)) {
    if (v == NULL)
        return INFINITE;

    if (v->base == NULL)
        return INFINITE;

    if (v->capacity <= 0)
        return INFINITE;

    if (v->size < 0 || v->size > v->capacity)
        return INFINITE;

    if(i < 0 || i > v->size)
        return INFINITE;

    ElemType* p = v->base;
    // 元素索引不越界且元素值不是要查找的元素值持续循环
    for (; i < v->size && 0 != comp(*p, cur); ++i, ++p);

    if (i >= v->size)     // 定位失败
        return INFINITE;

    return i;
}

void qSort(vector* v, int l, int r, int flag) {
    if ((r >= v->size && r - l < 2) || (r < v->size && r - l < 1))
        return;

    int m = v->base[(l + r) >> 1];
    int i = l - 1, j = 0;
    if (r < v->size)
        j = r + 1;
    else
        j = r;

    while (i < j) {
        while (Compare(v->base[++i], m) == flag);
        while (Compare(m, v->base[--j]) == flag);

        if (i < j) {
            int t = v->base[i];
            v->base[i] = v->base[j];
            v->base[j] = t;
        }
    }

    qSort(v, l, j, flag);

    if (r < v->size)
        qSort(v, j + 1, r, flag);
    else
        qSort(v, j, r - 1, flag);
}

int DistinctElem(vector* v, int l, int r, int k, int flag) {
    if (k <= 0)
        return v->size;

    qSort(v, l, r, flag);

    int j = 0;
    for (int i = 0; i < v->size; ++i) {
        // j小于k时, a[i]直接覆盖a[j], 此时i == j
        // j大于等于k且a[j - k] != a[i]时, a[i]覆盖a[j]
        // [0, k)上的元素值被保留
        if (j < k || v->base[j - k] != v->base[i]) {
            v->base[j] = v->base[i];
            ++j;
        }
    }
    v->size = j;
    return j;
}

void Travel(vector* v) {
    for (int i = 0; i < v->size; ++i)
        printf("%d ", v->base[i]);

    printf("\n");
}
#include "vector.h"
#include <stdio.h>

void AddElement(vector* v, ElemType e[], int n) {
    for (int i = 0; i < n; ++i)
        (i < v->size) 
        ? AddElemInSize(v, i, e[i]) 
        : AddElem(v, e[i]);
}

void DelSameElement(vector* v, ElemType e) {
    if (FAILURE == DelElem(v, e));
}

void DelElement(vector* v, int idx) {
    if (FAILURE == DelElemInSize(v, idx));
}

void TestAddElem() {
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 6, 4, 2, 8, 10, 11 };
    int n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    AddElement(&v, e, n);
    Travel(&v);
    puts("动态数组中删除所有值为2的元素");
    DelSameElement(&v, 2);
    Travel(&v);
    puts("动态数组中删除索引为2的元素");
    DelElement(&v, 2);
    Travel(&v);
    DestroyVector(&v);
}

void TestInsertBefore() {
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 6, 4, 2, 8, 10, 11 };
    int n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    AddElement(&v, e, n);
    Travel(&v);

    puts("动态数组中每个元素的前面插入10, 11, 12");
    ElemType a[] = { 10, 11, 12 };
    n = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < v.size; i += 4)
        InsertElemsBefore(&v, i, a, n);

    int j = 0;
    for (int i = 0; i < v.size; ++i, ++j) {
        if (i != 0 && i % 32 == 0)
            printf("\n");

        if (j != 0 && j % 3 == 0)
            printf("[%d] ", v.base[i]);
        else
            printf("%d ", v.base[i]);
        if (j > 3) j = 0;
    }
    printf("\n");

    DestroyVector(&v);
}

void TestInsertAfter() {
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 6, 4, 2, 8, 10, 11 };
    int n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    AddElement(&v, e, n);
    Travel(&v);

    puts("动态数组中每个元素的后面插入10, 11, 12");
    ElemType a[] = { 10, 11, 12 };
    n = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < v.size; i += 4)
        InsertElemsAfter(&v, i, a, n);

    int j = 0;
    for (int i = 0; i < v.size; ++i, ++j) {
        if (i != 0 && i % 32 == 0)
            printf("\n");

        if (j == 0 || j % 4 == 0)
            printf("[%d] ", v.base[i]);
        else
            printf("%d ", v.base[i]);
        if (j > 3) j = 0;
    }
    printf("\n");

    DestroyVector(&v);
}

void TestLocateAndGetElem(int x) {
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 2, 2, 2, 6, 4, 2, 8, 10, 11, 2 };
    int n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    AddElement(&v, e, n);
    Travel(&v);

    for (int i = 0; i < v.size; ++i) {
        int val = x;
        int j = LocateElem(&v, i, val, Compare);
        if(INFINITE == j)
            continue;

        if (FAILURE == GetElem(&v, j, &val)) {
            puts("获取元素失败");
            continue;
        }
        else if (x == val) {
            if (j < v.size - 1)
                printf("a[%d] = %d, ", j, x);
            else if(j == v.size - 1)
                printf("a[%d] = %d", j, x);
        }
    }
    printf("\n");
}

void TestDistinctElem() {
    vector v;
    InitVector(&v);

    ElemType e[] = { 9, 5, 2, 7, 0, 3, 1, 2, 2, 2, 6, 4, 2, 8, 10, 11, 2 };
    int n = sizeof(e) / sizeof(e[0]);
    puts("动态数组中添加一组数据");
    AddElement(&v, e, n);
    Travel(&v);

    puts("元素去重,重复元素保留2个");
    DistinctElem(&v, 0, v.size, 2, 1);
    Travel(&v);
}

int main() {
    TestAddElem();
    TestInsertBefore();
    TestInsertAfter();
    TestLocateAndGetElem(2);
    TestDistinctElem();
    return 0;
}


新鲜事 原文

小小蒟蒻
2个月前
最近有其他事,要被迫营业几天



小小蒟蒻
2个月前

测试结果:
9.png
10.png
在输入ctrl+z回车, 如果不直接按回车而是再输入一串字符串的结果
10.png

// getLine模板
int getLine(char s[], int n) {        // n是字符串数组的大小
    int i = 0, c = 0;                 // i保存从输入缓冲区读取的字符的索引
    do {
        c = getchar();                
        if (c >= EOF && c <= '\x1F')  // 当前读取的字符不可显示, 通过循环覆盖掉它们
            continue;                 // 执行continue后会跳转到while处再次判断字符c的值             

        if (i < n)                    // 字符数组能够装下当前读取的可显示的字符           
            s[i] = c;                 // 保存当前字符

        ++i;                          // 此时i + 1是当前读取的字符个数, 亦是下一个读取的字符的索引
    } while (c != '\x1a' && c != '\n'); // 当前读取的字符不是ctrl键或回车键的ASIIC码则继续循环

    if (i >= n)     // 保存的字符总数大于等于字符数组的大小
        i = n - 1;  // 重新设置字符串的长度为字符串数组的长度减一               

    s[i] = '\0';    // 设置字符串的结束符号        
    return i;       // 返回字符串的长度      
}
// getText模板
void getText(char s[], int n) {  // n是字符串数组的大小
    int i = 0, c = 0;            // i保存字符串的长度, 字符c保存从输入缓冲区读取的字符 
    do {
        puts("请输入一行字符串, 以回车结束输入或以ctrl+z回车结束输入");
        c = getchar();
        // 字符数组还能装下当前读取的字符且字符不是ctrl也不是回车
        if (i < n && c != '\x1a' && c != '\n') {
            ungetc(c, stdin);    // 有效字符返还给输入缓冲区
            i = getLine(s, n);        
            if (i > 0)  {        // 读取的字符串非空
                // 这里可以对字符串进行适当的操作
            }
            else {                // 读取的字符串为空
            }
        }
        // 字符数组不能装下当前读取的字符且字符是ctrl或是回车
        else if (i >= n && (c == '\x1a' || c == '\n')) {
            i = 0;   // 字符串的长度清零, 准备再读取一行字符
        }
    } while (c != EOF);  // 未按下ctrl+z继续循环
    // ctrl键在组合其他键的情况下, ctrl键对应的asiic码才会进入输入缓冲区
}
/*
ctrl+z回车控制台会换行
换行后直接回车就停止程序的运行
程序将读取到空字符串

ctrl+z回车控制台会换行
换行后输入字符再回车
程序将读取到非空字符串
*/

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define N  4  // 定义字符串数组的大小(考虑字符串数组的空间能否装下输入的字符总数)

// 参数n是字符数组的大小
int getLine(char s[], int n);
void getText(char s[], int n);
// 参数n是字符串的长度
int removeExtraSpaces(char str[], int n);
void showInfo(char s[], int n);

int getLine(char s[], int n) {
    int j = 0, c = 0; // j保存从输入缓冲区读取的字符总数
    // i保存从输入缓冲区读取的字符的索引
    // 输入一行字符以回车或ctrl+z回车结束该行的输入
    for (int i = 0; c != '\x1a' && c != '\n'; ++i) {
        c = getchar();                // 从输入缓冲区读取一个字符
        if (c >= EOF && c <= '\x1F')  // 当前读取的字符不是可显示字符
            continue;                 // 通过循环跳过这些不可显示的字符(阻止它们保存到字符串数组)

        if(i < n)                     // 保存缓冲区字符的字符数组还能够容纳字符 
            s[i] = c;                 // 将读取的字符保存到字符数组中

        j = i + 1;                    // 记录读取的字符总数
    }

    if (j >= n)  // 从输入缓冲区获取的字符总数不小于字符串数组的可容纳空间
        j = n - 1;                   // 将字符长度指定为字符串数组的长度减1

    if(j > 0)
        printf("字符数组中索引为%d的字符ASIIC码值[%xH]必须被\\0覆盖才能构造一个合法的字符串\n", j, s[j]);

    s[j] = '\0';          // 循环结束,j指向字符串的尾部,要为字符串添加结束符
    return j;             // 返回字符串的字符个数(不包含'\0'在内)
}

void getText(char s[], int n) {  // n是字符串数组的大小
    int i = 0, c = 0;            // i保存字符串的长度, 字符c保存结束字符 
    do {
        puts("请输入一行字符串, 以回车结束或以ctrl+z回车结束");
        c = getchar();
        if (i < n && c != '\x1a' && c != '\n') {
            // 每次将读取的字符退回到输入缓冲区, 否则字符串将丢失字符
            // getLine将再次调用getchar获取字符,当前为了试探ctrl或回车
            // 而读取的字符要退回到输入缓冲区,让getLine函数读取到完整的字符串
            ungetc(c, stdin);
            i = getLine(s, n);       // 读取一行字符串并且获取该行字符串的长度
            if (i > 0)               // 字符串长度大于0 
                showInfo(s, i);
        }
        else if (i >= n && (c == '\x1a' || c == '\n')) {
            i = 0;  // 字符串长度清零(要接收输入缓存区中新的字符串) 
        }
    } while (c != EOF);
}

int removeExtraSpaces(char s[], int n) {
    int j = 0;
    for (int i = 0; i < n; i++) {
        // 循环第一轮 必然有 j == 0,循环其他轮数时, 必然有j != 0
        // 循环第一轮时,发现首个单词。首个单词前面不用加空格字符
        // 循环其他轮数时,发现非首单词。非首单词前面必须加空格字符
        if (j != 0 && s[i] != ' ') s[j++] = ' ';

        // 当i指向的单词不是空格字符时,把i指向的字符复制到j指向的字符处
        // 复制后, j和i再自增一
        for (; i < n && s[i] != ' ' && s[i] != '\0'; s[j++] = s[i++]);
    }
    s[j] = '\0'; // 循环结束,j指向字符串的尾部,要为字符串添加结束符
    return j;      // 返回去除多余空格后字符串的字符个数(不包含'\0'在内)
}

void showInfo(char s[], int n) {
    printf("字符串数组的容量 = %d\n", N);
    printf("字符串数组的长度 = %d ", n + 1);
    printf("字符串数组的元素 = [%s", s);
    puts("\\0]");

    puts("删除多余空格前的字符串");
    printf("字符串的长度 = %d ", n);
    printf("字符串的元素 = [%s]\n", s);
    n = removeExtraSpaces(s, n);
    puts("删除多余空格后的字符串");
    printf("字符串的长度 = %d ", n);
    printf("字符串的元素 = [%s]\n", s);
    puts("");
}

int main() {
    char s[N];
    getText(s, N);
    return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define N  4  // 定义字符串数组的大小(考虑字符串数组的空间能否装下输入的字符总数)

// 参数n是字符数组的大小
int getLine(char s[], int n);
void getText(char s[], int n);
void showInfo(char s[], int n);

int getLine(char s[], int n) {
    int j = 0, c = 0; // j保存从输入缓冲区读取的字符总个数
    // i保存输入缓冲区字符的索引
    for (int i = 0; i < n && (c = getchar()) != '\n'; ++i) {
        // 如果读取到的字符是'\x1a'或'\n'或EOF等等, 不保存到字符串数组中, (\x1a是ctrl的ASCII码) 
        // ASCII码表中0x00到0x1F对应包含了Ctrl+A到Ctrl+Z操作, '\n', '\x1a'等等
        if (c >= '\x00' && c <= '\x1F' || c == EOF) {
            if (c == '\x1a') // 遇到ctrl键的ASCII码该行字符结束录入
                break;
        }
        else {
            s[i] = c;  // 将接收到的字符保存起来
            j = i + 1; // 字符串的长度提前增长一,便于下一个字符的收集
        }
    }

    // 从输入缓冲区获取的字符总数大于字符串的可容纳空间
    if (j >= n) {
        j = n - 1;                 // 将字符长度指定为字符串数组的长度减1
        while (getchar() != '\n'); // 清理残存在输入缓冲区中的字符(s)
    }

    s[j] = '\0';          // 循环结束,j指向字符串的尾部,要为字符串添加结束符
    return j;             // 返回字符串的字符个数(不包含'\0'在内)
}

void getText(char s[], int n) {
    int i = 0, c = 0;   // i保存输入缓冲区字符的索引                       
    while (EOF != (c = getchar())) {
        if (i >= n && (c == '\n' || c == '\x1a')) {
            i = 0;   // 字符长度清零(要接收输入缓存区中新的字符串)
        }
        else if (i < n && c != '\n' && c != '\x1a') {
            // 将有效的字符c退回到stdin输入流让getline函数接收所有有效字符
            ungetc(c, stdin);
            char e = 0;
            i = getLine(s, n);          // 处理一行字符
            if (i > 0)                  // 字符串长度大于0
                showInfo(s, n);         // 显示该行字符串相关信息
        }
    }
}

void showInfo(char s[], int n) {
    printf("字符串数组大小 = %d ", strlen(s) + 1);
    printf("字符串数组元素 = [%s", s);
    puts("\\0]");
    // 输出字符串中所有字符
    printf("字符串的长度 = %d ", strlen(s));
    printf("字符串的元素 = [%s]\n", s);
}

int main() {
    char s[N];
    getText(s, N);
    return 0;
}



小小蒟蒻
2个月前

6.png
7.png
8.png

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define N  4  // 定义字符串数组的大小(考虑字符串数组的空间能否装下输入的字符总数)

// 参数n是字符数组的大小
int getLine(char s[], int n, char* e);
void showInfo(char s[], int n, char c);

int getLine(char s[], int n, char* e) {
    int j = 0, c = 0; // j保存从输入缓冲区读取的字符总个数
    // i保存输入缓冲区字符的索引
    for (int i = 0; i < n && (c = getchar()) != '\n'; ++i) {
        // 如果读取到的字符是'\x1a'或'\n'或EOF等等, 不保存到字符串数组中, (\x1a是ctrl的ASCII码) 
        // 拦截ASCII码表中0x00到0x1F对应包含了Ctrl+A到Ctrl+Z的操作, '\n', '\x1a'等等
        if (c >= '\x00' && c <= '\x1F' || c == EOF) {
            if (c == '\x1a') // 遇到ctrl键的ASCII码该行字符结束录入
                break;
        }
        else {         
            s[i] = c;  // 将接收到的字符保存起来
            j = i + 1; // 字符串的长度提前增长一,便于下一个字符的收集
        }
    }

    // 从输入缓冲区获取的字符总数大于字符串的可容纳空间
    if (j >= n) {
        j = n - 1;                 // 将字符长度指定为字符串数组的长度减1
        *e = s[n - 1];
        while (getchar() != '\n'); // 清理残存在输入缓冲区中的字符(s)
    }

    s[j] = '\0';          // 循环结束,j指向字符串的尾部,要为字符串添加结束符
    return j;             // 返回字符串的字符个数(不包含'\0'在内)
}

void showInfo(char s[], int n, char c) {
    // 输出数组中所有字符
    if (c != '\n')
        printf("当数组大小小于输入缓冲区字符的总数时, 数组的最后一个元素%c被\\0覆盖\n", c);

    printf("数组的大小 = %d ", n);
    printf("数组的元素 = [%s", s);
    puts("\\0]");
    // 输出字符串中所有字符
    printf("字符串长度 = %d ", strlen(s));
    printf("字符串元素 = [%s]\n", s);
}

int main() {
    char s[N], c = '\n';
    int len = getLine(s, N, &c);
    showInfo(s, len + 1, c);
    return 0;
}



小小蒟蒻
2个月前

// 拆分出所有单词,用拆分出来的单词与用来替换的单词作比较,相等就输出替换单词,否则直接输出

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 201

int input(char s[], int n) {  // n是字符串数组的大小
    int j = 0, c = 0;         // j保存字符串的长度, c保存输入缓冲区中提取的一个字符
    for (int i = 0; i < n; ++i) { // 字符串的最大长度n - 1, 可以任意填装的区间[0, n - 1]  
        if (c == EOF || c == '\n') {       // 从输入缓冲区获取到结束字符 
            break;
        }
        else  if (c != '\x1a') {
            c = getchar();
            s[i] = c;   // 将接收到的字符保存起来
            j = i + 1;  // 字符串的长度提前增长一,便于下一个字符的收集
        }
    }
    // 找到字符串的末尾, 添加'\0'
    if (j < n - 1) --j;   // 从输入缓冲区获取的字符总数不大于字符串的可容纳内存
    else j = n - 1;       // 从输入缓冲区获取的字符总数大于字符串的可容纳内存

    s[j] = '\0';          // 循环结束,j指向字符串的尾部,要为字符串添加结束符
    return j;             // 返回字符串的字符个数(不包含'\0'在内)
}

const char* replace(const char* s, const char* a, const char* b) {
    if (strcmp(s, a) == 0) 
        return b;

    char* res = (char*)malloc(2 * N * sizeof(char));
    if(!res) return NULL;
    int n = strlen(s);
    int m = strlen(b);
    char p[N];   // 保存单词的字符串
    // 句子的分割符为空格符或者'\0'
    // i指向单词的首字母, j指向单词的分割符或结束符
    // 即每个单词索引的区间为[i, j)
    // 考虑到句子的内存首地址则每个单词的地址区间为[s + i, s + j)
    int k = 0, flag = 0;  // k为res的索引, flag标记分隔符的类型
    for (int i = 0, j = 0; i < n; ++i) {
        j = i;
        for (; j <= n && s[j] != ' ' && s[j] != '\0'; ++j);
        if (s[j] == ' ' || j == n) {
            if (s[j] == ' ') flag = 0;
            else if (j == n) flag = 1;
           // memset(p, '\0', j);
            memcpy(p, s + i, j - i);

            // 单词的索引区间[i, j), 最后一个字符的索引 j - i 
            // 等价于[i, j - 1], 最后一个字符的索引 (j - 1) - i + 1
            // 在这里下闭上开区间具有计算优势
            // 合理选择区间的开闭可简化问题
            p[j - i] = '\0';  

            // 判断当前分割得到的单词字符串与指定的单词字符串是否相等
            int len = 0;
            if (strcmp(p, a) == 0) {   // 相等
                len = m;
                memcpy(res + k, b, len + 1);
            }
            else {                     // 不等
                len = j - i;
                memcpy(res + k, p, len + 1);
            }

            if (!flag) {
                res[k + len] = ' ';
                res[k + len + 1] = '\0';
            }
            else {
                res[k + len] = '\0';
            }
            k += len + 1;
        }
        i = j;
    }

    return res;
}

int main() {
    char s[N], a[N], b[N];
    input(s, N);
    input(a, N);
    input(b, N);

    const char* p = replace(s, a, b);
    if (!p) 
       return -1;

    printf("%s\n", p);
    if(strcmp(p, b))
       free((void*)p);

    return 0;
}
include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 210

// input函数值得注意的地方:
// 每次判断缓存区的字符,如果不是结束字符都会收集该字符到字符串中
// 同时将字符串的长度增加一个, 便于收集缓冲区中的下一个字符
// 此时还未检测缓存区下一个字符是否是结束符号, 即无脑假设缓存区的字符都不是结束符号
// 于是一旦遇到缓冲区的结束字符时, 并不收集结束字符, 从而要将字符串的长度减小一
int input(char s[], int n) {  // n是字符串数组的大小
    int j = 0, c = 0;         // j保存字符串的长度, c保存输入缓冲区中提取的一个字符
    for (int i = 0; i < n; ++i) { // 字符串的最大长度n - 1, 可以任意填装的区间[0, n - 1]  
        if (c == EOF || c == '\n') {       // 从输入缓冲区获取到结束字符  
            break;
        }
        else  if (c != '\x1a') {
            c = getchar();
            s[i] = c;   // 将接收到的字符保存起来
            j = i + 1;  // 字符串的长度提前增长一,便于下一个字符的收集
        }
    }

    // 找到字符串的末尾, 添加'\0'
    if (j < n - 1) --j;   // 从输入缓冲区获取的字符总数不大于字符串的可容纳内存
    else j = n - 1;       // 从输入缓冲区获取的字符总数大于字符串的可容纳内存
    s[j] = '\0';
    return j;
}

const char* replace(const char* s, const char* a, const char* b) {
    if (strcmp(s, a) == 0) 
        return b;

    char* res = (char*)malloc(2 * N * sizeof(char));
    if(!res) return NULL;
    int n = strlen(s);
    int m = strlen(b);
    char p[N];   // 保存单词的字符串
    // 句子的分割符为空格符或者'\0'
    // i指向单词的首字母, j指向单词的分割符或结束符
    // 即每个单词索引的区间为[i, j)
    // 考虑到句子的内存首地址则每个单词的地址区间为[s + i, s + j)
    int k = 0, flag = 0;  // k为res的索引, flag标记分隔符的类型
    int i = 0, j = 0;
    while(s[i] != '\0') {
        j = i;
        while(s[j] != ' ' && s[j] != '\0') 
            ++j;

        if (s[j] == ' ' || s[j] == '\0') {
            if (s[j] == ' ') flag = 0;
            else if (s[j] == '\0') flag = 1;

            memcpy(p, s + i, j - i);

            // 单词的索引区间[i, j), 最后一个字符的索引 j - i 
            // 等价于[i, j - 1], 最后一个字符的索引 (j - 1) - i + 1
            // 在这里下闭上开区间具有计算优势
            // 合理选择区间的开闭可简化问题
            p[j - i] = '\0';  

            // 判断当前分割得到的单词字符串与指定的单词字符串是否相等
            int len = 0;
            if (strcmp(p, a) == 0) {   // 相等
                len = m;
                memcpy(res + k, b, len + 1);
            }
            else {                     // 不等
                len = j - i;
                memcpy(res + k, p, len + 1);
            }

            if (!flag) {
                res[k + len] = ' ';
                res[k + len + 1] = '\0';
            }
            else {
                res[k + len] = '\0';
            }
            k += len + 1;
        }
        i = j + 1;
    }

    return res;
}

int main() {
    char s[N], a[N], b[N];
    input(s, N);
    input(a, N);
    input(b, N);

    const char* p = replace(s, a, b);
    if (!p) return -1;

    printf("%s\n", p);
    if(strcmp(p, b))
       free((void*)p);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 210

// input函数值得注意的地方:
// 每次判断缓存区的字符,如果不是结束字符都会收集该字符到字符串中
// 同时将字符串的长度增加一个, 便于收集缓冲区中的下一个字符
// 此时还未检测缓存区下一个字符是否是结束符号, 即无脑假设缓存区的字符都不是结束符号
// 于是一旦遇到缓冲区的结束字符时, 并不收集结束字符
// 当输入的字符串超过了字符串数组能够容纳的空间时, 硬生生在字符串尾部添加'\0'
int input(char s[], int n) {  // n是字符串数组的大小
    int j = 0, c = 0;         // j保存字符串的长度, c保存输入缓冲区中提取的一个字符
    for (int i = 0; i < n - 1; ++i) { // 字符串的最大长度n - 1, 可以任意填装的区间[0, n - 1)   
        if (c == EOF || c == '\n') {  // 从输入缓冲区获取到结束字符                          
            if (j < n) j--;           // 字符串长度减一
        }

        c = getchar();  // 从输入缓冲区中提取一个字符
        s[i] = c;   // 将接收到的字符保存起来
        j = i + 1;  // 字符串的长度提前增长一,便于下一个字符的收集
    }

    // 字符串结束符'\0'的索引等于字符串的长度值
    s[j] = '\0';
    return j;
}

const char* replace(const char* s, const char* a, const char* b) {
    if (strcmp(s, a) == 0) 
        return b;

    char* res = (char*)malloc(2 * N * sizeof(char));
    if(!res) return NULL;
    int n = strlen(s);
    int m = strlen(b);
    char p[N];   // 保存单词的字符串
    // 句子的分割符为空格符或者'\0'
    // i指向单词的首字母, j指向单词的分割符或结束符
    // 即每个单词索引的区间为[i, j)
    // 考虑到句子的内存首地址则每个单词的地址区间为[s + i, s + j)
    int k = 0, flag = 0;  // k为res的索引, flag标记分隔符的类型
    int i = 0, j = 0;
    while(s[i] != '\0') {
        j = i;
        while(s[j] != ' ' && s[j] != '\0') 
            ++j;

        if (s[j] == ' ' || s[j] == '\0') {
            if (s[j] == ' ') flag = 0;
            else if (s[j] == '\0') flag = 1;

            memcpy(p, s + i, j - i);

            // 单词的索引区间[i, j), 最后一个字符的索引 j - i 
            // 等价于[i, j - 1], 最后一个字符的索引 (j - 1) - i + 1
            // 在这里下闭上开区间具有计算优势
            // 合理选择区间的开闭可简化问题
            p[j - i] = '\0';  

            // 判断当前分割得到的单词字符串与指定的单词字符串是否相等
            int len = 0;
            if (strcmp(p, a) == 0) {   // 相等
                len = m;
                memcpy(res + k, b, len + 1);
            }
            else {                     // 不等
                len = j - i;
                memcpy(res + k, p, len + 1);
            }

            if (!flag) {
                res[k + len] = ' ';
                res[k + len + 1] = '\0';
            }
            else {
                res[k + len] = '\0';
            }
            k += len + 1;
        }
        i = j + 1;
    }

    return res;
}

int main() {
    char s[N], a[N], b[N];
    input(s, N);
    input(a, N);
    input(b, N);

    const char* p = replace(s, a, b);
    if (!p) 
       return -1;

    printf("%s\n", p);
    if(strcmp(p, b))
       free((void*)p);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 110

// input函数值得注意的地方:
// 每次判断缓存区的字符,如果不是结束字符都会收集该字符到字符串中
// 同时将字符串的长度增加一个, 便于收集缓冲区中的下一个字符
// 此时还未检测缓存区下一个字符是否是结束符号, 即无脑假设缓存区的字符都不是结束符号
// 于是一旦遇到缓冲区的结束字符时, 并不收集结束字符, 从而要将字符串的长度减小一
int input(char s[], int n) {
    int j = 0, c = 0;  // j保存字符串的长度, c保存输入缓冲区中提取的一个字符
    for (int i = 0; i < n - 1; ++i) {
        c = getchar();               // 从输入缓冲区中提取一个字符
        if (c == EOF || c == '\n') {  // 从输入缓冲区获取到结束字符
            if (j >= n - 1) --j;          // 字符串长度减一          
            break;
        }
        else {          // 从输入缓冲区获取到的字符不是结束字符
            s[i] = c;   // 将接收到的字符保存起来
            j = i + 1;  // 字符串的长度提前增长一,便于下一个字符的收集
        }
    }
    // 字符串结束符'\0'的索引等于字符串的长度值
    s[j] = '\0';
    return j;
}


const char* replace(const char* s, const char* a, const char* b) {
    char* res = (char*)malloc(2 * N * sizeof(char));
    if(!res) 
        return NULL;

    if (!strcmp(s, a)) {
        strcpy(res, b);
        return res;
    }

    int n = strlen(s), m = strlen(b);
    char p[N];   // 保存单词的字符串
    // 句子的分割符为空格符或者'\0'
    // i指向单词的首字母, j指向单词的分割符或结束符
    // 即每个单词索引的区间为[i, j)
    // 考虑到句子的内存首地址则每个单词的地址区间为[s + i, s + j)
    int k = 0, flag = 0;  // k为res的索引, flag标记分隔符的类型
    for (int i = 0, j = 0; i < n; ++i) {
        j = i;
        for (; j <= n && s[j] != ' ' && s[j] != '\0'; ++j);
        if (s[j] == ' ' || j == n) {
            if (s[j] == ' ') flag = 0;
            else if (j == n) flag = 1;

            memcpy(p, s + i, j - i);

            // 单词的索引区间[i, j), 最后一个字符的索引 j - i 
            // 等价于[i, j - 1], 最后一个字符的索引 (j - 1) - i + 1
            // 在这里下闭上开区间具有计算优势
            // 合理选择区间的开闭可简化问题
            p[j - i] = '\0';  

            // 判断当前分割得到的单词字符串与指定的单词字符串是否相等
            int len = 0;
            if (!strcmp(p, a)) {   // 相等
                len = m;
                memcpy(res + k, b, len + 1);
            }
            else {                 // 不等
                len = j - i;
                memcpy(res + k, p, len + 1);
            }

            if (!flag) {  // 当分割符是空格时, 为结果集中的单词添加空格和'\0'
                res[k + len] = ' ';
                res[k + len + 1] = '\0';
                k += len + 1;  // 维护结果集的索引(下一次分割得到的单词的首字母会覆盖'\0')
            }
            else {   // 当分割符是'\0'时, 循环即将结束, 对k的维护已经没有意义
                res[k + len] = '\0';
            }
        }
        i = j;
    }

    return res;
}

int main() {
    char s[N], a[N], b[N];
    input(s, N), input(a, N), input(b, N);

    const char* p = replace(s, a, b);
    if (!p) 
       return -1;

    printf("%s\n", p);
    free((void*)p);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 201

int input(char s[], int n) {
    int j = 0, c = 0;
    for (int i = 0; i < n; ++i) {
        c = getchar();
        if (c == EOF || c == '\n') break;
        s[i] = c;
        j = i + 1;
    }
    s[j] = '\0';
    return j;
}

void replace(const char* s, const char* a, const char* b) {
    if (strcmp(s, a) == 0) {
        printf("%s\n", b);
        return;
    }

    char p[N];
    int n = strlen(s);

    // 句子的分割符为空格符或者'\0'
    // i指向单词的首字母, j指向单词的分割符或结束符
    // 即每个单词索引的区间为[i, j)
    // 考虑到句子的内存首地址则每个单词的地址区间为[s + i, s + j)
    for (int i = 0, j = 0; i < n; ++i) {  
        j = i;
        for (; j <= n && s[j] != ' ' && s[j] != '\0'; ++j);
        if (s[j] == ' ' || j == n) {
            char* t = p;
            for (char* q = s + i; q < s + j; *t++ = *q++) {
                // 遍历到每个单词的最后一个字母,顺带为单词字符串添加结束符
                if (q == s + j - 1)   
                    *(t + 1) = '\0';  
            }
            t = p;
            // 判断当前分割得到的单词字符串与指定的单词字符串是否相等
            // 不等直接输出, 否则输出替换字符串
            strcmp(p, a) ? printf("%s ", p) : printf("%s ", b); 
        }
        i = j;
    }
    printf("\n");
}

int main() {
    char s[N], a[N], b[N];
    input(s, N - 1);
    input(a, N - 1);
    input(b, N - 1);
    replace(s, a, b);
    return 0;
}



小小蒟蒻
2个月前
#include <stdio.h>
#include <stdlib.h>
#define N 210

struct DATA {
    char c;
    int n;
};

int input(char s[], int n) {
    int j = 0;
    for (int i = 0; i < n; ++i) {
        int c = getchar();
        if (c == EOF || c == '\n') break;
        s[i] = c;
        j = i + 1;
    }
    s[j] = '\0';
    return j;
}

int lengest(char s[], int n, char* c) {
    int j = 0, m = 0;
    for (int i = 0; i < n; ++i) {
        // s[j] == s[i]时, 维持最大值与*c的值
        // s[j] == s[i]的状态是可能持续的, 所以可以用单独的for循环来维护这种状态
        // 即一种条件成立的情况下,可以按照特定条件将一个循环拆分成两个独立的循环
        // 内部循环是外部循环的一个子集
        for(; i < n && s[j] == s[i] && m < i - j + 1; ++i) {
            m = i - j + 1;
            *c = s[j];
        }

        if (s[j] != s[i]) j = i;
    }
    return m;
}

int count() {
    int n = 0;
    scanf("%d", &n);
    // scanf遇到空格和'\n'时会停止
    // 空格或'\n'将留在缓冲区中
    // getchar与scanf相反,会读取缓冲区中的空格或'\n'
    // 在scanf之后使用getchar要清理掉scanf的缓冲区
    for (int c = '\0'; (c = getchar()) != '\n'; );
    return n;
}

int main() {
    struct DATA res[N];
    char str[N];
    int n = count();
    for (int i = 0; i < 2 * n; ++i) {
        if(i < n) 
            res[i].n = lengest(str, input(str, N - 1), &res[i].c);
        else 
            printf("%c %d\n", res[i - n].c, res[i - n].n);
    }

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define N 501

struct DATA {
    char c;
    int n;
};

int input(char s[], int n) {
    int j = 0;
    for (int i = 0; i < n; ++i) {
        int c = getchar();
        if (c == EOF || c == '\n') break;
        s[i] = c;
        j = i + 1;
    }
    s[j] = '\0';
    return j;
}

int lengest(char s[], int n, char* c) {
    int j = 0, m = 0;
    for (int i = 0; i < n; ++i) {
        // s[j] == s[i]时, 维持最大值与*c的值
        // s[j] == s[i]的状态是可能持续的, 所以可以用单独的for循环来维护这种状态
        // 即一种条件成立的情况下,可以按照特定条件将一个循环拆分成两个独立的循环
        // 内部循环是外部循环的一个子集
        for(; i < n && s[j] == s[i] && m < i - j + 1; ++i) {
            m = i - j + 1;
            *c = s[j];
        }

        if (s[j] != s[i]) j = i;
    }
    return m;
}

int lengest(char s[], int n, char* c) {
    int j = 0, m = 0;
    for (int i = 0; i < n; ++i) {
        if (s[j] != s[i]) {
            j = i;  // 如果是统计最长的单词,这里要让i加一,跳过空格
        }
        else {
            if (m < i - j + 1) {
                m = i - j + 1;
                *c = s[j];
            }
        }
    }
    return m;
}

int count() {
    int n = 0;
    scanf("%d", &n);
    // scanf遇到空格和'\n'时会停止
    // 空格或'\n'将留在缓冲区中
    // getchar与scanf相反,会读取缓冲区中的空格或'\n'
    // 在scanf之后使用getchar要清理掉scanf的缓冲区
    for (int c = '\0'; (c = getchar()) != '\n'; );

    return n;
}

int main() {
    int n = count();
    struct DATA res[N];
    // 指向字符串们的二级指针
    // 对它进行[]操作就是一个指针数组
    char** str = (char**)malloc(n * sizeof(char*));  

    for (int i = 0; i < n; ++i) {
        // 用指针数组保存申请得到的字符串的首地址
        str[i] = (char*)malloc(N * sizeof(char));
        res[i].n = lengest(str[i], input(str[i], N - 1), &res[i].c);
        if (str[i]) free(str[i]);
    }
    if (str) free(str);

    for (int i = 0; i < n; ++i)
        printf("%c %d\n", res[i].c, res[i].n);

    return 0;
}



小小蒟蒻
2个月前
#include <stdio.h>
#define N 101

int input(char s[], int n) {
    int j = 0;
    for(int i = 0; i < n; ++i) {
        int c = getchar();
        if(c == EOF || c == '\n') break;
        s[i] = c;
        j = i + 1;
    }
    s[j] = '\0';
    return j;
}

void reverse(char* l, char* r) {
    for(; l < r; ++l, --r) {
        *l ^= *r;
        *r ^= *l;
        *l ^= *r;
    }
}

int removeExtraSpaces(char s[], int n) {
    int j = 0;
    for(int i = 0; i < n; ++i) {
        if(j > 0 && s[i] != ' ') s[j++] = ' ';
        for(; i < n && s[i] != ' '; s[j++], s[i++]);
    }
    s[j] = '\0';
    return j;
}

const char* reverseWords(char s[], int n) {
    n = removeExtraSpaces(s, n);
    reverse(s, s + n - 1);

    int j = 0;
    for(int i = 0; i < n + 1; ++i) {
        if(i == n || s[i] == ' ') {
            reverse(s + j, s + i - 1);
            j = i + 1;
        }
    } 
    return s;
} 

int main() {
    char s[N];
    int n = input(s, N - 1);
    printf("%s\n", reverseWords(s, n));
    return 0;
}



小小蒟蒻
2个月前
#include <stdio.h>
#define N 101

int input(char s[], int n) {
    int j = 0;
    for(int i = 0; i < n; ++i) {
        int c = getchar();
        if(c == EOF || c == '\n') break;
        s[i] = c;
        j = i + 1;
    }
    s[j] = '\0';
    return j;
}

void reverse(char* l, char* r) {
    for(; l < r; ++l, --r) {
        *l ^= *r;
        *r ^= *l;
        *l ^= *r;
    }
}

int removeExtraSpaces(char s[], int n) {
    int j = 0;
    for(int i = 0; i < n; ++i) {
        if(j > 0 && s[i] != ' ') s[j++] = ' ';
        for(; i < n && s[i] != ' '; ++i, ++j)
            s[j] = s[i];
    }
    s[j] = '\0';
    return j;
}

const char* reverseWords(char s[], int n) {
    n = removeExtraSpaces(s, n);
    reverse(s, s + n - 1);

    int j = 0;
    for(int i = 0; i < n + 1; ++i) {
        if(i == n || s[i] == ' ') {
            reverse(s + j, s + i - 1);
            j = i + 1;
        }
    } 
    return s;
} 

int main() {
    char s[N];
    int n = input(s, N - 1);
    printf("%s\n", reverseWords(s, n));
    return 0;
}



小小蒟蒻
2个月前
#include <stdio.h>
#include <ctype.h>
#define N 81

int input(char s[], int n) {
    int j = 0;
    for (int i = 0, c = 0; i < n; i++) {
        c = getchar();
        if (c == EOF || c == '\n') break;
        s[i] = c;
        j = i;
    }
    s[j] = '\0';
    return j;
}

int cmp(const char* a, const char* b) {
    while (*a != '\0' && *b != '\0') {
        if (isalpha(*a) && isalpha(*b)) {  // a,b同时为字母字符
            if (tolower(*a) < tolower(*b)) 
                return -1;
            if (tolower(*a) > tolower(*b))
                return 1;
        }
        else {
            if (*a < *b) return -1;
            if (*a > *b) return 1;
        }
        a++, b++;
    }
    if (*a == '\0' && *b != '\0')
        return -1;
    if (*a != '\0' && *b == '\0')
        return 1;
    return 0;
}

int main() {
    char s1[N], s2[N];
    input(s1, N);
    input(s2, N);

    switch (cmp(s1, s2)) {
    case -1: printf("<"); break;
    case 0:  printf("="); break;
    default: printf(">"); break;
    }
    return 0;
}