字符串与字符数组

字符串是由一系列字符组成的字符数组,并以空字符 '\0' 结尾。

字符数组与字符串的概念在 C 语言中密不可分,是计算机处理文本时的基础。

字符数组与字符串数组

字符数组

字符数组:一个存储字符的数组 char str[6] = "hello";,通常用于表示字符串。

字符数组 str 包含5个字符 'h', 'e', 'l', 'l', 'o' 和一个隐含的结尾字符 '\0',表示字符串的结束。

因此,字符数组初始化时,大小应比存储的字符串长读至少多一个字节。

char c[10]="1234567890";
printf("%s\n", c);
//输出结果为:123456789烫烫烫
//表示此时赋值没有结束符,使用%s输出会在'\0'处停止

字符串数组

包含多个字符串的数组。例如:

char names[3][10] = {"Alice", "Bob", "Charlie"};

这个 names 数组包含三个字符串,每个字符串最多可以容纳 9 个字符(最后一个字符是 '\0')。

字符串的打印

printf 函数用于格式化输出字符串和字符。此时,使用 %s%c 来打印字符串和字符有明显区别

如果使用 %s 打印一个字符数组,程序会输出从该地址开始的所有字符,直到遇到 '\0'。而使用 %c 只会打印单个字符。

void print(char c[])
{
    int i=0;
    while(c[i]!=0)
    {
        printf("%c", c[i]);
        //%c是单字符逐一打印
        i++;
    }
}
int main()
{
    char c[10]="123456789";
	printf("%s\n", c);
    //%s从起始地址开始打印字符串,在'\0'处结束
    //此处"c"是字符数组名,表示字符数组的起始地址
    print(c);
}

字符串的初始化

scanf 函数

在使用 scanf 函数读取字符串时,有一些重要的注意事项:

getsputs 函数

getsputs 是处理字符串输入输出的函数:

使用getsputs来输入输出字符串:

int main()
{
	char c[20];
	while (gets(c) != NULL) 
	{
		puts(c);
	}
}

字符数组与指针

字符数组的名称表示该数组的首地址,可以作为指针传入函数。

代码注释与介绍

#include <stdio.h>

// 定义一个函数 change,它接受一个字符指针作为参数
void change(char *p)
{
    *p = 'H';        
    // 将 p 指向的第一个字符修改为 'H'
    p[1] = 'E';      
    // 将 p 指向的第二个字符修改为 'E'
    *(p + 2) = 'L';  
    // 将 p 指向的第三个字符修改为 'L'
}

int main()
{
    char c[10] = "hello";  // 定义一个字符数组 c,并初始化为字符串 "hello"
    change(c);  // 调用 change 函数,并将字符数组 c 的首地址传递给它
    puts(c);    // 输出修改后的字符串
    
    // 输出:HELlo
    return 0;
}

change 函数接受一个字符指针 p 作为参数,这个指针指向一个字符数组的首地址。如,p 将指向数组 c

通过指针 p 的偏移,修改数组 c 中的字符:

指针与字符数组的初始化

int main()
{
    char *p = "hello";  
    // p 指向存储在常量区中的字符串 "hello"
    char c[] = "hello"; 
    // 在栈区中分配内存并存储 "hello"
    
    c[0] = 'H';  
    // 修改字符数组 c 的第一个元素,合法操作,c 现在变成 "Hello"
    
    // p[0] = 'H'; // 试图修改常量区的内容是非法的,程序会崩溃
    
    p = "world"; // 合法操作,指针 p 现在指向另一个字符串常量 "world"
    
    // c = "world"; // c 是常量,不能对它重新赋值
}

常量区(或称为只读数据区)是内存的一部分,用来存储程序中那些不需要修改的常量数据,比如字符串常量。如,在代码中直接写 "hello" 这样的字符串时,它就被存储在常量区。

特点:常量区的内容是只读的,任何试图修改它的操作都会导致程序错误(通常会崩溃)。

常量区与栈区的区别:常量区的字符串不可修改,而栈区的字符数组可以修改。对常量区的写操作会导致程序崩溃。

指针 p 和字符数组 c[] 的区别

数组名是常量

指针 p 和字符数组 c[]p 可以指向不同的字符串常量(如从 "hello""world"),但不能修改它指向的字符串内容(常量区只读)。而 c[] 是字符数组,存储在栈区,可以修改数组的内容(如把 "hello" 改为 "Hello"),但不能改变 c 的指向。

其他:字符串操作函数练习

mystrlen 字符串长度

#include <stdio.h>
int mystrlen(char *c)
{
    int i;
    while(*c)
    {
        i++;
        c++;
    }
    return i;
}

int main()
{
    char c[20];
    while(gets(c)!=NULL)
    {
    printf("%d\n",mystrlen(c));
    }
}

mystrcpy 复制字符串

#include <stdio.h>
void mystrcpy(char *str1, char *str2)
{
    int i=0;
    while(*str2)
    {
        str1[i] = str2[0];
        i++;
        str2++;
    }
    str1[i]=0;
}

int main()
{
    char c[20];
    char d[20];
    while(gets(c) != NULL)
    {
        gets(d);
        mystrcpy(c, d);
        printf("%s\n", c);
    }
}

mystrcmp 比较字符串

#include <stdio.h>

int mystrcmp(char *str1, char *str2)
{
    int d;
    while(*str1 && *str2)
    {
        d = *str1 - *str2;
        if(d != 0) break;
        str1++;
        str2++;
    }
    if(d == 0)
    {
        d = *str1 - *str2;
    }
    return d;
}

int main()
{
    char c[20];
    char d[20];
    while(gets(c)!=NULL)
    {
        gets(d);
        printf("%d\n", mystrcmp(c, d));
    }
}