icoding复习3
1. 不调用库函数,自己实现字符串的比较操作:该操作当比较的两个字符是都是字母,且两个字符互为大小写
 (如a和A、e和E)时认为两个字符相同,否则不同,其比较结果按这两个字符的原值确定。函数的返回值规定如下:
 返回值 < 0:第一个不匹配的字符在 ptr1 中的值低于 ptr2 中的值
 返回值 == 0:两个字符串的内容相等
 返回值 > 0:第一个不匹配的字符在 ptr1 中的值大于在 ptr2 中的值
int str_compare(const char* ptr1, const char* ptr2);
 #include 
 #include 
 #include "dsstring.h" //请不要删除,否则检查不通过
 //又是字符串操作!!!! 
 int str_compare(const char* ptr1, const char* ptr2){
     int i;
     // a == 97 A == 65 
     for(i = 0; ptr1[i] && ptr2[i]; i++){
         if(ptr1[i] != ptr2[i]){//字符相等就继续,不等判断大小写关系 
             if(ptr1[i] + 'a' - 'A' == ptr2[i] || ptr2[i]+'a'-'A' == ptr1[i])
                 continue;//这一步可以分开写,没有判断是否ptr1[i]和ptr2[i]为字母,但是icoding监测可以通过
                 //其实当两个字符恰好相差32就不行了 
             else
                 return ptr1[i]-ptr2[i];
         }
     }
     //后面的代码可以略掉 
     if(ptr1[i])
         return (int)ptr1[i];
     else
         return (int)ptr2[i];
      
 }
 //解法2 icoding检测数据不全 ! 100
 int str_compare(const char* ptr1, const char* ptr2)
 {
     // a == 97 A == 65 
     int i;
     for (i = 0; ptr1[i] != '\0' || ptr2[i] != '\0';) {
         if (ptr1[i] == ptr2[i] )  //判断字符是否相等 
             i++;
         else if(ptr1[i] <= 'z' && ptr1[i] >= 'a'&& ptr1[i] - 32 == ptr2[i])
         //判断是否为大小写不同的相同字母, (如果同为相同的大写或者相同的小写之前检测了), 
             i++;
         else if(ptr2[i] <= 'z' && ptr2[i] >= 'a'&& ptr2[i] - 32 == ptr1[i])
             i++;
         else
             return ptr1[i] - ptr2[i];//可以自动转换为int
         //注意点第二三个if是必要的, 不能直接判断ptr1[1] -ptr2[i] == +-32 , 也有可能有ASC码正好相差32的非字母字符 
     }
     return 0;
 }
//90+问题代码
 int str_compare(const char* ptr1, const char* ptr2)
 {
     char a, b;
     int i;
     for (i = 0; ptr1[i] != '\0' && ptr2[i] != '\0'; i++) {
         a = ptr1[i];
         b = ptr2[i];
         if (a <= 'Z' && a >= 'A' && b <= 'z' && b >= 'a')
             a = a - 'A' + 'a';//有问题, 这部分的意思是a为大写, b同时也为字母并且为小写 , 那么
             //a转化为小写并且与b比较, 但是如果值不等的话会改变返回值大小 
         if (b <= 'Z' && b >= 'A' && a <= 'z' && a >= 'a')
             b = b - 'A' + 'a';
         if (a == b)
             continue;
         else
             return a - b;
     }
     return ptr1[i] - ptr2[i];
 } 
2.串替换
in,原始字符串,保持不变; out, 存放替换结果的字符串; outlen,out空间的大小
 oldstr,要替换的旧字符串; newstr,替换成的新字符串
 函数返回成功替换的次数,即有多少个子串被成功替换
 在替换过程中,任何情况下所得字符串(及结束符)不应该超过 outlen,
 如果某次替换所得字符串的长度超过 outlen,则不进行这次替换操作,整个替换操作结束。如:
 原始串为 "aaabbbccc",outlen 为14, oldstr 为 "c",newstr 为 "333" 时,
 两次替换后得 "aaabbb333333c",此时字符串占用空间为14字节。
 如果再进行替换,则会超出 out 所占用的空间,所以停止替换操作。
 此时函数应该返回 2, out指向的串为 "aaabbb333333c"
 再如:原始串为 "aaabbbccc",outlen 为10, oldstr 为 "bb",
 newstr 为 "123456",进行替换后所得的串应该为 "aaa123456" 
 (长度为9)与结束符一共占 10 个字节,此时函数应该返回 1
#include "dsstring.h"
 #include 
 #include 
int get_len(const char *str){
     int i;
     for(i = 0; str[i]; i++)
         ;
     return i;
 }
 //另一种写法
 int get_len(const char* s)
 {
     int i = 0;
     while (*(s + i)) {
         i++;
     }
     return i;
     //返回值是实际长度, 不包括空字符
 } 
//理解:旧串换新串,每一个新串要求能够全部放下并且不忽略尾部空字符, 操作的是字符指针...! 
 int str_replace(const char* in, char* out, int outlen, const char* oldstr, const char* newstr)
 {
     int i, j = 0, ostr, nstr = 0;//i 指示in, j指示out. 
     int n = 0;
     
     if(outlen <= 0) return false; 
     
     //out需要分配空间??? 不需要..... 
     //下面思路整理:
     //in的字符不与oldstr第一个字符匹配,直接复制, 进入下一轮循环 
     //判断剩余空间是否足够, 一种溢出是新串字符加out内已有字符长度溢出,一种是in剩余字符加out已有字符溢出,直接剩余全部复制
     //空间足够,判断字符是否匹配,判断匹配成功,那么ostr指向oldstr最后一个'\0' 
     //执行换串操作 ,n++ 
     //最后如果串换完并且in中字符全部复制完但是j没有达到outlen-2,放空字符 
     for(i = 0; i < get_len(in) && j < outlen - 1;){
     //对于j,总长度为outlen, 最后一个下标为outlen-1,最后一个位置放'\0' ,所以j最大取outlen-2 
     
         if(in[i] != oldstr[0]){
             out[j++] = in[i++];
             continue; 
         }
             
         if(j + get_len(newstr) >= outlen - 1 || get_len(in) - i + j >= outlen - 1)
         {//先看剩余空间可以换串吗 ,如果不能就剩余全部复制 
             for(; j < outlen;)
                 out[j++] = in[i++];l
             return n;
         }
         
         for(ostr = 0; otsr < get_len(oldstr); ostr++)
             if(oldstr[ostr] != in[i+ostr])
                 break;
                 
         if(ostr == get_len(oldstr) - 1){//if(!(oldstr[ostr]))等价 
             for(nstr = 0; j < get_len(newstr); j++)
                 out[j] = newstr[nstr++];
             n++;
             i += get_len(oldstr);
         }
         else
             out[j++] = in[i++]; 
     }
     
     for(; j < outlen - 1; j++)
         out[j] = '\0';
     out[j] = '\0';
    return n;
 }
 3. 块链串 
 #include 
 #include 
 #define BLOCK_SIZE 4    // 可由用户定义的块大小
 #define BLS_BLANK '#'   // 用于空白处的补齐字符
typedef struct _block {
     char ch[BLOCK_SIZE];    //块的数据域
     struct _block *next;    //块的指针域
 } Block;
typedef struct {
     Block *head;        // 串的头指针
     Block *tail;        // 串的尾指针
     int len;            // 串的当前长度
 } BLString;
//字符串初始化函数:
 void blstr_init(BLString *T) {
     T->len = 0;
     T->head = NULL;
     T->tail = NULL;
 }
 这些定义已包含在头文件 dsstring.h 中,请实现块链串的子串查找操作:
bool blstr_substr(BLString src, int pos, int len, BLString *sub);
 src为要查找的字符串
 pos为子串开始的下标
 len为子串的长度
 sub在函数调用运行前指向一个已经初始化好的空串,在函数返回时,sub指向串src从第pos个字符起长度为len的子串
 函数查找成功返回true,参数不正确返回 false
 #include 
 #include 
 #include "dsstring.h" // 请不要删除,否则检查不通过
 //满分代码
!!!!操作字符串长度 
 int len(const char* s)
 {
     int q = 0;
     while (*s != '\0') {//可以简化while(*s++) q++;
         q++;
         s++;//!!!
     }
     return q;
 }
 //易错点分析:
 //1. 对于字符指针的操作, len函数书写
 //2. 对于块的个数边界条件判定
 //3. 对于块指针操作,分类讨论
 //4. 尾指针置空,空白地方用'#'填充 
int StrAssign(BLString* S, const char* cstr)
 {//将cstr复制到块链串S中
  
     int i, j, k, len;
     Block *p, *q;
     len = strlen(cstr); //len为链串的长度
     if (len == 0)
         return 0;
     S->len = len;
     
     j = len / BLOCK_SIZE; //j为链串的结点数 ,也就是块个数` 
     if (len % BLOCK_SIZE)
         j++;
         
     for (i = 0; i < j; i++) {
         p = (Block*)malloc(sizeof(Block));
         if (!p)
             return 0;//可以简化
             
         //k指示每一个块内部字符ch[]下标
         for (k = 0; k < BLOCK_SIZE && *cstr; k++) //将字符串ctrs中的字符赋值给链串的数据域
             *(p->ch + k) = *cstr++;//!!!!!!
             
         if (i == 0) //如果是第一个结点
             S->head = q = p; //头指针指向第一个结点
         else {//q为跟踪指针 
             q->next = p;
             q = p;
         }
         if (!*cstr) //如果是最后一个链结点
         {
             S->tail = q; //将尾指针指向最后一个结点
             q->next = NULL; //将尾指针的指针域置为空
             for (; k < BLOCK_SIZE; k++) //最后一个结点用'#'填充
                 *(q->ch + k) = BLS_BLANK;
         }
     }
     return 1;
 }
 bool blstr_substr(BLString src, int pos, int len, BLString* sub)
 {
     char* t;
     if (pos < 0 || pos >= src.len || len < 1)
         return false;
     int n = pos / BLOCK_SIZE, h = pos % BLOCK_SIZE;
     Block* temp = src.head;
     
     for (int i = 0; i < n; i++)
         temp = temp->next;//temp直接指向pos位置那个块 
     
     char str[100];
     int i = 0;
     while (i < len) {
         if (h >= BLOCK_SIZE) {
             temp = temp->next;
             h = 0;
         } 
         else {
             if (!temp || temp->ch[h] == BLS_BLANK)
                 break;
             str[i++] = temp->ch[h++];
         }
     }
     str[i] = '\0';
     StrAssign(sub, str);
     return true;
 }