|
一、字符串的定义
char *str1 = {"Hello world!"}; // 方式一 (可省略{})
char str2[] = {"Hello world!"}; // 方式二 (可省略{})
char str3[] = {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0'}; // 方式三(1) 方式一的本质是定义了一个char型指针str1, 指向的是字符串常量Hello world!,因此str1所指向地址中的内容是不可更改的,即不能使用类似str1[0] = 'h';的语句对其进行赋值操作。但是指针str1仍然可以指向其他地址,例如可利用str1 = str2;语句将str1指向str2所指向的地址。 此外,字符串的结尾会被编译器自动加上结束符\0。
(2) 方式二定义了以一个char型数组str2,str2指向数组第一个元素所处内存的地址。此时内存空间是由栈分配的,地址一经分配就不能更改,因此str2不能再指向其他内存空间,但其所指向的内存空间中的内容是可以更改的,即可以使用类似str2[0] = 'h';的语句对其进行赋值操作。字符串的结尾也会被编译器自动加上结束符\0。
(3)方式三中如果没有指定大小的话,编译器只会会根据字符串大小分配空间,但不会在字符串结尾添加'\0'。为避免其他异常情况的出现,务必在字符串结尾处手动加上'\0'。以该方式定义字符串时不允许有空的单字符'',即' '中的空格不能省略;
常用运算符sizeof()和strlen()函数这两种方式来计算字符串的长度。
sizeof()的值是在编译时计算得到的,因此不能用于计算动态分配的内存空间大小。sizeof()可用于基本类型、结构体以及数组等静态分配的对象所占空间大小的计算,其返回值与内存中存储的内容无关。
例如,在32位系统中,char类型变量占用的空间为一个字节 ,即sizeof(char)的值为1。而字符型指针char *的本质是一个int型变量,所以其占用的空间大小为四个字节,即sizeof(char *)的值为4。
函数strlen()的函数原型为size_t __cdecl strlen(const char *); ,其声明位于头文件string.h中。 strlen()是在运行时计算的,其返回值为从给定的地址开始到遇见的第一个NULL之间的长度。 返回的长度并不包含NULL所占用的空间。
【小结】运算符sizeof()与函数strlen()的区别。
sizeof() | strlen() | 编译时计算。 | 运行时计算。 | 数组、结构体等静态变量。 | char *类型的变量,必须以'\0'结尾。 | 数组名传给sizeof()不会退化。 | 数组名传给strlen()会退化为指针。 | 利用sizeof()和strlen()分别计算上述三种定义方式定义的字符串的长度:
printf("sizeof(str1)=%d\n", sizeof(str1));
printf("sizeof(str2)=%d\n", sizeof(str2));
printf("sizeof(str3)=%d\n", sizeof(str3));
printf("sizeof(str4)=%d\n", sizeof(str4));
printf("strlen(str1)=%d\n", strlen(str1));
printf("strlen(str2)=%d\n", strlen(str2));
printf("strlen(str3)=%d\n", strlen(str3));
printf("strlen(str4)=%d\n", strlen(str4));计算结果为
sizeof(str1)=4 // 即sizeof(char *),返回的是字符型指针的大小,故sizeof无法计算方式一定义的字符串的长度。
sizeof(str2)=13 // 包含'\0'。
sizeof(str3)=13 // 包含'\0'。
sizeof(str4)=16 // 返回的是实际分配的内存大小,而不是字符串的长度。
strlen(str1)=12 // 不包含'\0'。
strlen(str2)=12 // 不包含'\0',故比sizeof(str2)的值小1。
strlen(str3)=12 // 不包含'\0',故比sizeof(str3)的值小1。
strlen(str4)=12 // 返回的是字符串的实际长度(不包含'\0'),而不是实际分配的内存大小。二、字符串的遍历
// 逐个访问字符串中的字符并逐行打印
// 思路一:根据数组长度逐个遍历
void travel_str(void)
{
int i = 0;
char str[] = {"Hello World!"};
int len = strlen(str); // 计算字符串大小
// 逐个遍历
for(i=0;i<len;i++)
{
printf(&#34;%c\n&#34;, str);
}
}
// 思路二:利用指针进行遍历
void travel_str(void)
{
char str[] = {&#34;Hello World!&#34;};
char *ch = str;
// 不能直接采用原指针str遍历,因为此处的str不能改变其指向的地址。
// 即使可以也会因为str指向了别处导致str原来指向的内存无法被释放,造成内存泄露。
while(*ch != &#39;\0&#39;) // 以&#39;\0&#39;作为字符串结束标志
{
printf(&#34;%c\n&#34;, *ch++);
}
}

羽墨志 | C语言遍历字符串
三、字符串数组的定义
// 方式一:必须指定第二维的大小,且应大于等于数组最长字符串的长度
char str_arr1[][10] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;};
// 方式二
char *str_arr2[] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;};四、字符串数组的遍历
// 遍历数组中的字符串
// 思路一
void travel_str_array(void)
{
unsigned char i = 0, size = 0;
// char str_arr[][10] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;};
char *str_arr[] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;};
size = sizeof(str_arr)/sizeof(str_arr[0]); // 获取数组大小
for(i=0; i<size; i++)
{
// printf(&#34;%s\n&#34;, str_arr);
printf(&#34;%s\n&#34;, *(str_arr+i));
}
}
// 思路二
void travel_str_array(void)
{
char *str_arr[] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;, NULL};
char **str = str_arr; // 采用临时指针指向原数组,避免因原数组指针移动导致内存泄露。
// 采用该方法遍历时建议采用方法二定义数组,并在数组最后手动添加NULL。
while(*str != NULL)
{
printf(&#34;%s\n&#34;, *str++);
}
// 另一种循环方式
#if 0
char **ptr = NULL;
for(ptr=str_arr; *ptr!=NULL; ptr++)
{
printf(&#34;%s\n&#34;, *ptr);
}
#endif
}【小结】
- 若采用指针遍历字符串数组时,务必在数组最后手动添加NULL,以确保能够准确找到字符串数组的结尾。否则,指针会指向其他非目标位置,甚至导致程序崩溃。
- 若通过计算数组大小来遍历字符串数组时,尾部无需添加NULL。如果手动添加了NULL ,则在遍历数组时应将数组长度减去1,因为编译器多分配了一个指向NULL的指针。访问NULL指针会导致程序崩溃。具体分析见第五节。
五、遍历字符串数组中的字符
void travel_str_array_by_char(void)
{
unsigned char i,j = 0;
char *str_arr[] = {&#34;Monday&#34;, &#34;Tuesday&#34;, &#34;Wednesday&#34;, &#34;Thursday&#34;, &#34;Friday&#34;, &#34;Saturday&#34;, &#34;Sunday&#34;, NULL};
int len = sizeof(str_arr)/sizeof(str_arr[0]);
char **str = str_arr;
// 利用指针遍历字符串数据中的字符
for(str=str_arr; *str!=NULL; str++)
{
for(j=0; j<strlen(*str);j++)
{
printf(&#34;%c &#34;, *((*str)+j));
}
printf(&#34;\n&#34;);
}
// 利用字符串数组大小和字符串长度来遍历字符串数组中的字符
for(i=0; i<len-1; i++)
{
for(j=0;j<strlen(str_arr);j++)
{
// printf(&#34;%c &#34;,*(*(str_arr+i)+j));
printf(&#34;%c &#34;,str_arr[j]);
}
printf(&#34;\n&#34;);
}
// 错误示例
#if 0
for(i=0; i<len; i++)
{
// 当i=len-1时,str_arr = NULL,此时strlen(NULL)访问NULL指针,程序崩溃。
for(j=0;j<strlen(str_arr);j++)
{
// printf(&#34;%c &#34;,*(*(str_arr+i)+j));
printf(&#34;%c &#34;,str_arr[j]);
}
printf(&#34;\n&#34;);
}
#endif
} |
|