字符串和字符数组

 

1、字符串

严格意义上来说,C语言并没有字符串原生的字符串的类型,而是通过字符指针来实现的:char *p = "LINUX";。而对于其他的高级语言来说,比如C++的就存在字符串类型: string p1 = "I LOVE LINUX"; 。

    字符串在内存中其实就多个字节组成的,且地址都是连续的;指针指向字符串的的头部;字符串的结尾是以"\0"(是真能整的零)作为字符串结束的标志。

"\0" 的理解:

    \0 是一个 ASCII 字符,其实是编码为零的字符,是真正的零。这个和数字零是不同的,数字零的 ASCII 是48。

注意:

    当定义一个字符串的时候:char *p = "LINUX",系统会在这个字符串的结尾处自动添加'\0',作为结束的标志,所以'\0'虽然是连接这最后一个字符,但是并不属于这个字符串。

    分配的字符串,是被保存到文字常量区

int main(int argc, char *argv[])
{
    char *p = "I LOVE LINUX";
    printf("%c\n", *p);
    printf("%s\n", p);
    while (1);
}

输出结果为:

II LOVE LINUX

 

2、字符数组

定义:char p[] = "I LOVE LINUX";

    其实就是将字符串放到数组中,在一块连续的内存中依次排放,则数组名则是指向字符串第一个地府的地址 。

int main(int argc, char *argv[])
{
    char p[] = "I LOVE LINUX";
    for (int i = 0; i < 12; i++)
    {
        printf("%c", *(p + i));
    }
    while (1);
}

   或者也可以直接printf("%s\n", p);,输出。

    字符数组是将整个字符串一次存在数组中,以上面为例,其实就是一个12个元素的数组。char p[12]={'I','','L','O','V','E','','L','I','N','U','X'},12 个元素依次排放。

注意: 因为是字符串,所以字符串结尾的地方编译器也是会自动添加 \'0,所以char *P[],里面其实是13个字节,分配的字符数组,是被分配到堆中。

3、sizeof、strlen与字符串、字符数组

 

sizeof:

    是 C 语言的运算符,计算变量的所占据的内存空间的大小。

strlen:

    是函数,计算字符串的长度。遇到'\0'就结束。

计算:

char str[20] = "0123456789";
int a = strlen(str); 
ubt b = sizeof(str);

a = 10,因为strlen() 是计算字符串的长度的函数,当遇到‘\0’就结束,所以得到的数值是10

b = 20 ,因为sizeof 函数是计算分配内存空间的大小的,很显然数组是分配了20个字节,所以得到的就是20了。

 

char *str1 = “abcde”;
char str2[] = "abcde";
char str3[8]={'a',};
char str4[] = "0123456789";
sizeof(str1); // 4
sizeof(str2); // 6
sizeof(str3); // 8
sizeof(str4); // 11
 

    分析,首先可以知道sizeof 函数是计算分配内存空间大小的。str1 显然就是一个指针嘛,不论怎么样,只占所占的字节数,永远都是四个字节;str2 是字符数组,虽然字母是五个,但是必须知道字母的后面接有一个看不见的'\0'作为字符串的结束的标志,所以就总共了6个字符,所以就是6个字节了;str3 显然已经定义了数则的长度是8,所以只能是八个字节;str4 显然也是一个字符数则,十个字符加上一个'\0'字符串结束标志,总共11个字符,所以11个字节。

 

4、C语言和字符串处理函数


C语言:  char st[100]


(1)字符串的长度

strlen(st)

(2)字符串的比较

strcmp(st1,st2);   // 全部比较
strncmp(st1,st2,n);  // 比较前面 n 个

(3)附加

strcat(st1,st2)
strncat(st1,st2,n);  // st2 的前面 n 个连接到 st1

(4)拷贝

strcpy(st1,st2);
strncpy(st1,st2,n);  // 复制 st2 前面的 n 个字节到 st1

(5)查找

where = strchr(st,ch)   ch为要找的字符。
where = strspn(st1,st2); 查找字符串。

 

5、字符串的操作


(1)字符串的长度

例子1:

int strlen_v1(char *src)
{
    char *y = src;
 
    while (*y++);
 
    return (y - src -1);
}

    因为字符串在内存中都是连续进行排放的,所以可以通过计算地址的方式进行计算。这里需要注意: *y++ 的计算顺序(*y++ 与(*y)++ 会在其他

的地方做总结)。*y 计算的是每个字符的值,当不等于字符串的结束符之前('\0'),则一直向后移动一个,当移动到'\0'的时候,这个时候显然是不成立的,但是y 还是要接着向后移动一个,所以字符串的长度就是,y - src -1。这里与不用 *y++ 做对比:

int strlen_v1(char *src)
{
    char *y = src;
    while (*y)
    {
        y++;
    }
    return (y - src);
}

例子2:

int strlen_v2(char *src)
{
       int i = 0;
    char *y = src;
 
    while (*y)
        {
             i++;
             y++;
        }
    return i;
}

    当 *y 等于\0 的时候,就会被退出,返回 i 值,就是字符串的长度。

(2)字符串比较函数

int strcmp_v1(char *string1, char *string2)
{
    // 重新赋值指针,不要改变原先的指针
    char *str1 = string1;
    char *str2 = string2;
 
    while ((*str1) && (*str2) && (*str1 == *str2))
    {
        str1++;
        str2++;
    }
    
    if ( *str1 > *str2)
    {
        return 1;
    }
    if (*str1 < *str2)
    {
        return -1;
    }
    else
        return 0;
}

(3)附加: 将字符串 str2 接到 str1 的后面

char * stringstring(char * str1, char *str2)
{
    char *s1 = str1;
    char *s2 = str2;
    while (*s1)
        s1++;
    while (*s2)
    {
        *s1 = *s2;
        s1++;
        s2++;
    }
    *s1 = '\0';
    return str1;
}
int main(int argc, char *argv[])
{
    char p[] = "LINUX";  
    char pp[] = "I LOVE";
    
    printf("%s\n", stringstring(pp,p));
    while (1);
}

    s1结束的时候是执行字符串的 '\0',所以附加的字符就在这个地方开始进行字符串的拷贝。当 s2 结束的时候,完成了所有字符的拷贝,所以在结束的位置添加字符串结束的标志 '\0' 。这里注意到主函数使用的是字符数组而不是字符串,原因是字符串的话,这些字符串是被存放到文字常量区,这个区域是只读的区域,指针指向了文字常量区,可以访问,但是完全不可以对其进行写的操作;而以字符数组的方式的话,是被分配到栈中的,对于栈的操作是可读可写的操作。

(4)字符串的拷贝

 

void strcpy_v1(char *dest, char *src)
{
    char *d = dest;
    while (*src)
    {
        *d++ = *src++;
    }
    *d = '\0';
}
int main(int argc, char *argv[])
{
    char src[] = "I LOVE LINUX";  
    char dest[13];
    strcpy_v1(dest, src);
    printf("%s\n", dest);
    while (1);
}

    需要对字符串进行写操作,所以还是必须以字符数组的方式进行定义,不能以字符串的方式进行定义。


(6)实现字符串str1中查找str2,返回找到的地址

 

char * mystrstr(char * str1, char *str2)
{
    if (str2 == NULL)
    {
        return nullptr;
    }
    char *p = str1;
    while (*p)
    {
        char *p1 = p;
        char *p2 = str2;
        while ((*p1) && (*p2) && (*p2 == *p1))
        {
            p1++;
            p2++;
        }
        if (!*p2)
            return p;
        p++;
    }
    return nullptr;
}
int main(int argc, char *argv[])
{
    char src[] = "I LOVE LINUX";  
    char dest[] = "LINUX";
    printf("%s\n", mystrstr(src, dest));
    while (1);
}

(7)实现字符串的反转

void strRev(char *s)
{
    char *rev = s;
 
    char temp;
 
    // 让 rev 指针直到最后一个字符串的字母
    char *end = rev + strlen(rev) - 1;
    while (end > rev)
    {
        temp = *rev;
        *rev = *end;
        *end = temp;
 
        end--;
        rev++;
    }
}
posted @ 2015-11-03 21:58  qxj511  阅读(448)  评论(0编辑  收藏  举报