字符串数组的表示形式
在C语言中字符串数组有两种表示方法:
第一种,二维字符数组可以利用二维字符数组来表示字符串,格式是:char strs[row][col];
。例如:
char strs[4][6] = {"hello", "world", "c", "java"};// char 类型的二维数组// 注意,也不支持先声明再赋值。即下面的赋值方式是错误的char strs[4][6];strs = {"hello", "world", "c", "java"};
其中的 row 表示二维数组中的行,表示有几个字符串;而 col 表示二维数组中的列,表示能存放字符串的最大长度。
第二种,字符指针数组可以用一维的字符指针数组来保存字符串,格式是:char* strs[len];
。例如:
char* strs[4] = {"hello", "world", "c", "java"};// char* 类型的一维数组注意,也不支持先声明再赋值。即下面的赋值方式是错误的char* strs[4];strs = {"hello", "world", "c", "java"};
该一维数组中的每一个元素都是一个 char
类型的地址:
strs[0]
指向第一个字符串中的第一个字符。即 *strs[0]
等于 'h'
。第二个指针 strs[1]
指向第二个字符串中的第一个字符。即 *strs[1]
等于 'w'
。 每个 strs[i]
都表示一个字符串,指针都指向对应字符串的第一个字符。
因此实际上这个一维数组并不存放真正的字符串,而只是存放字符串的地址。
从键盘输入字符串数组
有时候我们需要批量从键盘输入字符串,无论是二维字符数组还是一维字符指针数组,都可以通过循环输入字符串的方式来给字符串数组赋值,而从键盘输入字符串的方式有 scanf
和 gets
两种,根据情况选择即可:
#include <stdio.h>int main() { // 声明二维字符数组,注意指定字符串个数和字符串最大长度 char strs[4][10]; // 通过循环批量输入字符串并赋值给字符串数组 for (int i = 0; i < 4; i++) { scanf("%s", strs[i]); // 或者使用 gets() 函数 // gets(strs[i]); } // 打印结果 for (int i = 0; i < 4; i++) { printf("%s\n", strs[i]); }}
一维字符指针数组表示的字符串数组的批量赋值 #include <stdio.h>#include <malloc.h>int main() { // 声明一维字符指针数组 char *strs[4]; // 通过循环批量输入字符串并赋值给字符串数组 for (int i = 0; i < 4; i++) { // 声明字符串,并为其分配内存空间 char *str = (char *) malloc(sizeof(char) * 10); gets(str);// 使用 gets 函数从键盘读取输入 strs[i] = str;// 赋值 // 或者使用 scanf() 函数 // scanf("%s", str); // 注意,我们不能直接使用 gets(strs[i]); 或者 scanf("%s", strs[i]); 来进行赋值 } // 打印结果 for (int i = 0; i < 4; i++) { printf("%s\n", strs[i]); }}
输出字符串数组
输出字符串数组,实际上就是循环数组输出每个字符串,而输出字符串的函数有 printf
和 puts
。
无论是二维字符数组还是一维字符指针数组,都可以通过循环遍历输出字符串数组中的所有字符串:
#include <stdio.h>int main() { // 二维字符数组声明的字符串数组 char strs[4][10] = {"tom", "jack", "rose", "lily"}; for (int i = 0; i < 4; i++) { printf("%s\t", strs[i]); } printf("\n"); // 一维指针数组声明的字符串数组 char *strs2[4] = {"java", "javascript", "python", "c"}; for (int i = 0; i < 4; i++) { puts(strs2[i]); }}
访问字符串数组中的字符串
如果要访问二维字符数组声明的字符串数组中的字符串,可以通过两种方式:
下标,例如:strs[i]
数组名加下标,例如:*(strs + i)
#include <stdio.h>int main() { char strs[4][10] = {"tom", "jack", "rose", "lily"}; // 通过数组下标来访问,例如:strs[i],其中 i 是数组下标 printf("%s\n", strs[1]); // 通过数组名加下标的方式来访问,例如:*(strs + i),其中 strs 是数组名,而 i 是数组下标 printf("%s\n", *(strs + 2));}
如果要访问一维字符指针数组声明的字符串数组中的字符串,也可以通过上面的两种方式来访问:
#include <stdio.h>int main() { char *strs[4] = {"tom", "jack", "rose", "lily"}; // 通过数组下标来访问,例如:strs[i],其中 i 是数组下标 printf("%s\n", strs[1]); // 通过数组名加下标的方式来访问,例如:*(strs + i),其中 strs 是数组名,而 i 是数组下标 printf("%s\n", *(strs + 2));}
即无论是二维字符数组声明的字符串数组还是一维字符指针数组声明的字符串数组,都可以通过下标或者数组名加下标的方式访问数组中的字符串。
修改字符串数组中的字符串
只有二维字符数组声明的字符串数组才可以通过 strcpy
或者 sprintf
函数进行赋值,而一维字符指针数组声明的字符串数组不允许修改数组中的字符串:
#include <stdio.h>#include <string.h>int main() { // 1.二维字符数组声明的字符串数组 char strs[4][10] = {"tom", "jack", "rose", "lily"}; // 1.1 使用 strcpy 函数进行赋值 strcpy(strs[1], "java"); // 1.2 使用 sprintf 函数进行赋值 sprintf(strs[2], "tomcat"); // 输出字符串,查看是否修改完成 for (int i = 0; i < 4; i++) { printf("%s\t", strs[i]); } // 2.一维字符指针数组声明的字符串数组,无法对字符串进行修改 char *strs2[4] = {"java", "javascript", "c", "c++"}; // 2.1 使用 strcpy 函数进行赋值,错误的示范 // strcpy(strs2[1], "JAVASCRIPT"); // 2.2 使用 sprintf 函数进行赋值,错误的示范 // sprintf(strs2[2], "C"); // 下面是错误的示例: // 通过数组下标来修改,这是错误的 // strs[1]="张三"; // 通过数组名加下标的方式来修改,这也是错误的 // *(strs+2)="李四";}
访问字符串数组中的字符串的字符
如果是二维字符数组声明的字符串数组,可以通过如下两种方式来访问(其中 i 和 j 都是指数组的下标,一个是横坐标,一个是纵坐标,都从 0 开始):
下标,格式是:字符串数组名[i][j]
。例如,strs[0][1]
。数组名加下标,格式是:*(*(字符串数组名 + i) + j)
。例如,*(*(strs + 1) + 2)
。 #include <stdio.h>int main() { // 1.二维字符数组声明的字符串数组 char strs[4][10] = {"tom", "jack", "rose", "lily"}; // 1.1通过数组下标访问字符串数组中字符串中的字符 char c; c = strs[1][1]; printf("%c\n", c);// 'a' // 1.2通过数组名加下标的方式访问 c = *(*(strs + 1) + 2); printf("%c\n", c);// 'c'}
如果是一维指针数组声明的字符串数组,也可以通过上面两种方式来访问:
#include <stdio.h>int main() { // 2.一维指针数组声明的字符串数组 char *strs[4] = {"tom", "jack", "rose", "lily"}; // 2.1通过数组下标访问字符串数组中字符串中的字符 char c; c = strs[1][1]; printf("%c\n", c);// 'a' // 2.2通过数组名加下标的方式访问 c = *(*(strs + 1) + 2); printf("%c\n", c);// 'c'}
修改字符串数组中的字符串的字符
如果是二维字符数组声明的字符串数组,可以通过如下两种方式来修改字符(其中 i 和 j 都是指数组的下标,一个是横坐标,一个是纵坐标,都从 0 开始):
下标,格式是:字符串数组名[i][j]='新字符'
。例如,strs[0][1]='X'
。数组名加下标,格式是:*(*(字符串数组名 + i) + j)='新字符'
。例如,*(*(strs + 1) + 2)='X'
。 #include <stdio.h>int main() { // 1.二维字符数组声明的字符串数组 char strs[4][10] = {"tom", "jack", "rose", "lily"}; // 1.1通过数组下标访问字符串数组中字符串中的修改 strs[1][1] = 'X'; printf("%c\n", strs[1][1]);// 'X' // 1.2通过数组名加下标的方式修改 *(*(strs + 1) + 2) = 'Y'; printf("%c\n", *(*(strs + 1) + 2));// 'Y' // 打印字符串,查看是否修改成功 for (int i = 0; i < 4; i++) { puts(strs[i]); }}
但是对于通过一维指针数组声明的字符串数组,里面的字符串是无法修改的,而字符串里面的字符更不能修改。
#include <stdio.h>int main() { // 2.一维字符指针数组声明的字符串数组 char *strs[4] = {"tom", "jack", "rose", "lily"}; // 2.1通过数组下标访问字符串数组中字符串中的修改 // strs[1][1] = 'X';// 错误的写法 // 2.2通过数组名加下标的方式修改 // *(*(strs + 1) + 2) = 'Y';// 错误的写法}
遍历字符串数组中的所有字符串
即遍历字符串数组,无论是二维字符数组声明的字符串数组还是一维字符指针声明的字符串数组,都可以通过 for 循环等循环语句来遍历数组,然后通过下标(例如,strs[i]
)或者数组名加下标(例如,*(strs + i)
)的访问字符串:
#include <stdio.h>int main() { // 1.二维字符数组声明的字符串数组 char strs[4][10] = {"java", "javascript", "c", "c++"}; // 1.1通过 for 循环 for (int i = 0; i < 4; i++) { printf("%s\t", strs[i]); } printf("\n"); // 1.2通过 while 循环 int i = 0; while (i < 4) { printf("%s\t", *(strs + i)); i++; } printf("\n"); // 2.一维字符指针数组声明的字符串数组 char *strs2[4] = {"tom", "jack", "rose", "lily"}; // 2.1通过 for 循环 for (i = 0; i < 4; i++) { printf("%s\t", strs2[i]); } printf("\n"); // 2.2通过 while 循环 i = 0; while (i < 4) { printf("%s\t", *(strs2 + i)); i++; }}