第二天2017/03/29: 字符串操作

1、堆、栈的生长方向

【记忆知识】
栈的生长方向:开口向下(后定义的变量的内存地址更小)
堆的生长方向:开口向上(后分配内存的变量的内存地址更大)
【注意】堆、栈的生长方向和内存存放方向是两个不同的概念,例如:分析a和b的地址大小(栈的生长方向)、a[0]和a[2]的地址的大小(内存存放方向)
    int a[10];
    int b[10];
答:
    a的地址大于b的地址,
但是a[0]的地址小于a[2]的地址。

2、指针铁律

这里写图片描述
C编译器不允许这样使用!

这里写图片描述
因为p指向字符串常量“abcdefg”,*p就表示字符串常量“abcdefg”,想用*p对常量“abcdefg”进行修改,肯定会报错误(即写入位置发生冲突)
3、指针的相关知识

函数调用时,可以用n级指针改变n-1级指针的值。

==================================================================================

【字符串操作技巧】

while((*to++ = *from++) != ‘\0’) ; 字符串拷贝

strstr\strchr + while的用法

下面讲解字符串的一些经典的相关操作

4、字符串拷贝
这里写图片描述
【注】此处不用额外写上 *to = ‘\0’;

//上述代码等价于:
    *to = *from;
    from++;
    to++;

5、siring字符串的相关函数操作【非常重要】

举例:在长字符串中寻找一个短字符串出现的次数。(提示:用函数strstr)

这里写图片描述
6、两头堵

#include <iostream>
using namespace std;

int strlen_trimSpace1(char *p) //函数1
{//求出除去前后空格的字符串的长度
    int count = 0;
    int i = 0,j = 0;
    j = strlen(p)-1;  //记得 -1(减1)
    while(isspace(p[i]) && p[i]!='\0')  //从前往后
    {   //isspace(c)检查参数c是否为空格字符
        i++;
    }
    while(isspace(p[j]) && j>0)   //从后往前
    {
        j--;
    }
    count = j-i+1;
    memcpy(p,p+i,count);
    p[count] = '\0';

    cout<<p<<endl; //输出修改后的结果p

    return 0;
}
int strlen_trimSpace2(char *p,char *q) //函数2
{//求出除去前后空格的字符串的长度
    int count = 0;
    int i = 0,j = 0;
    j = strlen(p)-1;  //记得 -1(减1)
    while(isspace(p[i]) && p[i]!='\0')  //从前往后
    {   //isspace(c)检查参数c是否为空格字符
        i++;
    }
    while(isspace(p[j]) && j>0)   //从后往前
    {
        j--;
    }
    count = j-i+1;
    memcpy(q,p+i,count);
    q[count] = '\0';

    cout<<q<<endl; //为了不修改输入的p字符数组,定义q作为接受数组

    return 0;
}
int main()
{
    int ret = 0;
    //“两头堵”问题
//对于字符串分配内存有三种方式:堆、栈、全局区(常量区)
    char input[] = "     abcd1111abcd2222abcd333abcd4    "; //除去前后两头空格剩下的字符串必须没有空格
    char outstr[100] = " ";
    strlen_trimSpace1(input);

    //下面运行会崩溃,因为input1是常量,而在strlen_trimSpace函数中对input指向的常量字符串修改,会崩溃
    char *input1  = "     abcd1111abcd2222abcd333abcd4    "; 
    //strlen_trimSpace1(input1);   
    strlen_trimSpace2(input1,outstr);  


    if(ret!=0)
    {
        cout<<"strlen_trimSpace Error!"<<endl;
        return 0;
    }

    getchar();
    return 0;
}

7、字符串反转

void reserve_str(char *str)
{
    int i = 0,j = strlen(str)-1;
    char *h = str;
    char *r = str+j;
    char ch;
    while(h < r)
    {
        ch = *h;
        *h = *r;
        *r = ch;
        h++;
        r--;
    }
    cout<<str<<endl;
}
int main()
{
    //char *str  = "ABCDEFGHIJKLMN"; //不能用字符串常量,因为不能修改
    char str[] = "ABCDEFGHIJKLMN";
    reserve_str(str);
    getchar();
}

8、字符串合并

char * s1_s2(char* s1,char* s2)
{
    //char str[100]; //程序崩溃,因为str是栈中的局部变量,不能返回
    char *str = (char*)malloc(sizeof(char)*100); //正确做法:在堆中分配能返回的str指针
    char *s = str;  //因为str经过两个while循环后被修改,所以用s保存首地址(返回s即可)

    char *p1 = s1;
    char *p2 = s2;
    while(*str++ = *p1++);
    str--; //去掉'\0'字符
    while(*str++ = *p2++); 

    return s;
}
int main()
{
    char str1[] = "ABCD";
    char str2[] = "1234";
    char *out = s1_s2(str1,str2);
    cout<<out<<endl;
    //记得释放在被调函数中分配的堆上的内存
    if(out!=NULL)
        free(out);

    getchar();
}

8、字符串中常见的错误

0-0)没有给字符变量分配内存就开始使用它(使用方式:strcpy等)
(0-1)越界
(0-2)
(1)字符串和字符数组的区别:是不是带有'\0'.

(2)疑问:字符数组打印时为什么打印出“烫烫烫烫”?
    因为printf打印时,没有'\0'结束符,因此打印出乱码。
    strcpy等好多字符串操作函数遇见'\0'才结束!
(3strlen是一个函数,它不包括'\0'
sizeof是一个运算符,球数据实体的大小

(4)三种给字符串分配内存的内存四区图(栈、堆、全局)

char str1[20] ;
char *str2  = "AAAA";
char *str3  = (char*)malloc(100);

这里写图片描述

(5) [] 与 * 本质上是一样的。

(6)在程序执行的时候,把字符串指针p的地址给修改了,但是没有察觉,因此使对p进行理所应当的操作时,发生意料之外的结果。
例1:释放a时为什么程序崩溃?
这里写图片描述
程序解读:开始时a指向分配的字符串的头地址,经过for循环后,a指向字符串末尾。
此时释放a:free(a)是释放了未知的地址,肯定会发生错误,程序崩溃。
【修改】应该讲a指向分配的字符串的头地址再进行释放。

例2:为什么打印不出来to和from?
这里写图片描述

(7)再进行返回指向字符串的指针时,能否返回出来?

在全局区和堆区分配的可以返回
在栈上分配的不可以返回
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值