目录
strlen(数组地址) 字符串求长度, 遇到'\0'结束,不算‘\0’
一:数组概念
具有相同类型和名称的变量集合,这些变量就是数组元素,个数确定,连续存放
用循环处理数组,不能整体使用。
二:数组定义
数据类型 数组名[长度]; 长度为整形常量或者整形常量表达式
正确形式举例
#define N 10 void main() { int arr[5]; int arr[N]; int arr[] = { 1,2,3 }; }
错误形式举例
void main() { int n = 10; int arr[1.1];// 错误长度不是整形 int arr[n];// 错误,长度不能为变量 int arr[]; // 错误,前面不给长度,后面还不给元素,编译器就懵逼了 int arr[0];//更不行 }
注意点
- 先定义后使用
- 数组名必须为合法标识符,不能与其他变量同名
- 数组名是地址常量
- 长度必须为整形常量或者整形常量表达式
一维数组初始化
- 对全部元素初始化;可以省略长度
int arr[]={1,2,3}
- 对于部分元素初始化;不可以省略长度,其余的元素会补0(\0)
- 不允许指明的长度小于实际的长度
int arr[1]={1,2};//错误
- 即使数组元素全部相等,也不能整体赋值
- 字符数组初始化方法
//字符 char s1[] = { 'c','h','e','n'}; //没有\0这个是字符,不能用puts输出 puts(s1);// 找到\0才会停止 //字符串 char s1[] = { 'c','h','e','n','\0'}; char s2[5] = "chen"; //这两种方式定义的是字符串,等价 //可以用puts输出 puts(s1); //puts自带换行功能 printf("%s\n", s2);// 等价
二维数组初始化
- 按行给二维数组赋初值
//把第一个括号内的元素赋值给第一行 //不考虑内存对其,这个两个数组的存放方式相同 int arr[2][3] = { {1,2,3},{4,5,6}};//二维数组按行存放连续 int arr1[6] = { 1,2,3,4,5,6 };
- 第二种方式一次赋初值
int arr[2][3] = { 1,2,3,4,5,6 };
- 对部分元素赋初值
//第一行第一个元素初始化为1, 第二行第一个元素初始化为3 //未初始化的默认为0 int arr[2][2] = { {1},{3} };//正确 //int arr[3][3] = { {1},{},{3} }; 错误括号里必须要有东西 int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) printf("%d\t", arr[i][j]); }
输出
- 全部赋初值为0
int arr[2][2] = { 0 };//全部赋初值为0
- 给全部元素或者按行赋初值,行数可以省略,列数不可省略
//以下都是正确形式 int arr[][2] = { {1,2},{3,4} }; int arr2[][2] = { {1},{3} }; int arr3[][2] = { 1,2,3,4 };
int arr[][2];// 错误 不能又没有行数,元素还不给出来
字符数组初始化
辨别字符数组和字符串
- 存的是字符还是字符串,看看右面有没有放\0的位置就可以知道
//字符 char s1[] = { 'c','h','e','n'}; //没有\0这个是字符,不能用puts输出 puts(s1);//错误 找到\0才会停止 char s2[]={"chen"}; //字符串 char s1[] = { 'c','h','e','n','\0'}; char s2[5] = "chen"; //这两种方式定义的是字符串,等价 //可以用puts输出 puts(s1); //puts自带换行功能 printf("%s\n", s2);// 等价
`char arr[] = { "chen" };` 和 `char arr1[] = "chen";` 这两种声明数组的方式看似相似,但实际上有细微的区别: 1. `char arr[] = { "chen" };`: - 这是一个不太常见的声明方式。 - 它实际上是创建了一个字符数组,数组的每个元素都是一个字符。 - 在这个声明中,`"chen"` 被视为一个字符数组, 所以整个字符串作为一个单独的元素被放入到 `arr` 数组中。 这可能导致编译错误或者意想不到的行为,因为字符串字面量实际上是字符数组。 注意: 如果你的编译器没有报错并接受了 `char arr[] = { "chen" };` 这种声明方式, 那么可能是编译器的特定行为或者对C标准的某种解释。然而, 这并不是标准C语言中推荐的声明方式。在大多数情况下,这种声明可能会导致未定义的行为。 关于 `\0` 的包含情况,如果编译器接受了这种语法, 它可能会将 `"chen"` 视为一个指向字符数组的指针, 并尝试将这个指针作为数组的第一个元素。这样,`arr` 实际上将包含指针的值, 而不是字符串 `"chen"` 的单个字符。在这种情况下,数组不会包含空字符 `\0` 作为其元素。 为了更清楚地理解编译器的行为,你可以检查 `arr` 的内容, 例如,通过打印数组的每个元素或查看内存表示。 这样可以帮助你确定编译器实际上是如何处理这种声明的。 但请记住,即使你的编译器接受这种语法,它也可能不是跨不同编译器或平台的可移植或可靠的做法。 2. `char arr1[] = "chen";`: - 这是一种常见的声明方式。 - 它创建了一个字符数组,并自动计算数组的大小,包括结尾的空字符 `\0`。 - 数组 `arr1` 将包含字符 `'c'`, `'h'`, `'e'`, `'n'`, 和一个结尾的空字符 `\0`,总共5个字符。 总的来说,第二种声明方式 `char arr1[] = "chen";` 是正确且常用的,而第一种方式可能不会按预期工作。通常在C语言中声明字符串时,应该使用第二种方式。
二维字符数组
- 二维字符数组
在C语言中,声明 `char arr[3][4];` 定义了一个二维字符数组。 这里的 `3` 和 `4` 分别代表数组的维度大小: - `3` 表示这个数组有3行。 - `4` 表示每行数组有4个字符。 所以,`arr` 是一个包含3行,每行4个字符的二维数组。 你可以将它视为一个字符表格, 其中每行可以包含一个最多3个字符的字符串(考虑到字符串末尾的空字符 `\0`)。 例如,你可以这样初始化这个数组: ```c char arr[3][4] = { "row1", "row2", "row3" }; ``` 在这个例子中,每行都包含了一个3字符的字符串 和一个隐含的空字符 `\0` 作为字符串的结尾。这种结构非常适合存储一系列的短字符串
//输出演示 void main() { // 行标为字符串个数,列标为字符串长度 char arr[][7] = { "Chen", "is", "a", "cool", "guy", "indeed", }; //使用行标,访问某一个字符串 puts(arr[0]); // 输出 Chen printf("%s %s", arr[1], arr[2]); // 输出is a //使用行标和列标可以进到字符串里面,输出单个字符 printf("%c", arr[4][0]); //输出 g }
void main() { char arr[5][5]; //方式1单个输入 scanf("%s", arr[1]); //输入放在第一行, scanf不能接收空格 gets(arr[1]);//输入放在第二行, 可以接收空格,遇到换行符结束 //方式2使用循环对整体初始化 int i; for (i = 0; i < 5; i++) { gets(arr[i]);// 按回车输入下一个字符 } //输出字符串 for (i = 0; i < 5; i++) { puts(arr[i]); } }
B
B
D
数组元素引用
- 格式 : 数组名[下标]
- 下标: 从0到长度减1, 如定义 int arr[5]; 下标的上线为 5-1=4 ;C对下标越界不检查
- 可以为整形变量,整形表达式,数组元素,返回值函数调用
//都对 int test() { return 3;//返回下标3 } void main() { int a = 3; int arr[] = { 1,2,3,4,5 }; arr[a] = 666; arr[test()] = 666; arr[1 + 2] = 666; }
- 每个元素相当于一个变量,变量这么用元素就怎么用
- 定义完成后不能对整个数组进行操作,一般是用循环配合元素
arr = {1, 2, 3, 4, 5}; // 错误!不能在声明之后这样赋值
二维数值数组
格式: 数组名[下标][下标]
void main() { int arr[2][3] = { 1,2,3,4,5,6 }; int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf("%d\t", arr[i][j]); } printf("\n"); } }
N*N数组(方阵)的特点
例如: int arr[2][2]={1,2,3,4}; 其中 i=2,j=2,N=2
主对角线元素 i=j
次对角线元素 i+j=N-1
下三角 i<=j 行标小于列标
上三角 i>=j 行标大于列标
这些表达式是用于在二维数组(特别是方阵)中识别和处理不同部分的元素的常见方法。 假设有一个 `N*N` 的二维数组 `arr[N][N]`,其中 `i` 和 `j` 分别表示行索引和列索引, 它们都是从 0 开始的。下面解释这些表达式的含义: 1. **主对角线元素 `i=j`**: - 在一个方阵中,主对角线是从左上角到右下角的斜线。 - 主对角线上的元素满足行索引和列索引相等,即 `arr[i][i]`。 - 例如,在一个 3x3 矩阵中,主对角线上的元素是 `arr[0][0]`, `arr[1][1]`, `arr[2][2]`。 2. **次对角线元素 `i+j=N-1`**: - 次对角线(有时称为反对角线)是从右上角到左下角的斜线。 - 次对角线上的元素满足行索引和列索引之和等于 `N-1`。 - 在一个 3x3 矩阵中,次对角线的元素是 `arr[0][2]`, `arr[1][1]`, `arr[2][0]`。 3. **下三角 `i>=j`(行标大于等于列标)**: - 下三角包含主对角线和主对角线以下的所有元素。 - 对于数组中的任意元素 `arr[i][j]`,如果 `i` 大于等于 `j`,则该元素位于下三角。 - 在 3x3 矩阵中,下三角的元素是 `arr[0][0]`, `arr[1][0]`, `arr[1][1]`, `arr[2][0]`, `arr[2][1]`, `arr[2][2]`。 4. **上三角 `i<=j`(行标小于等于列标)**: - 上三角包含主对角线和主对角线以上的所有元素。 - 对于数组中的任意元素 `arr[i][j]`,如果 `i` 小于等于 `j`,则该元素位于上三角。 - 在一个 3x3 矩阵中,上三角的元素是 `arr[0][0]`, `arr[0][1]`, `arr[0][2]`, `arr[1][1]`, `arr[1][2]`, `arr[2][2]`。 理解这些概念对于处理矩阵和执行相关的算法非常重要, 尤其是在涉及线性代数、图像处理或者数据结构方面的编程中。
3 3
2 2
12 13
D
D
C
3 5 7
错题
7,0
字符串数组长度以及字符串长度
字符数组的长度: 占内存字节的个数 ; 使用sizeof(数组名), 测试
字符数组中存放字符串长度: 有效字符串个数 \0之前,不含\0
void main() { char arr[] = "Chen\0 is a cool guy"; //末尾还隐藏了个\0 printf("字符数组占内存大小=%d\n", sizeof(arr));// 算空格 printf("有效字符串的长度=%d", strlen(arr)); }
注意:字节个数,末尾有\0也要补\0
长度数到\0结束就可以
会区分转义字符和字符串结束符
void main() { char arr[] = "\\n\078\087\0"; //解释 第一个'\'就是告诉后面的'\'你就是个'\',所以这两个算一个 // 'n'自己算一个 //'\07' 这个8进制的字符表示形式 算一个 // '8' 自己算一个 // '\0' 直接结束了(不算字符串长度),因为他后面是8,他俩想在一起条件也不允许啊 // 末尾有'\0', 系统也会自动在补上一个'\0' printf("字符数组占内存大小=%d\n", sizeof(arr)); printf("有效字符串的长度=%d", strlen(arr)); }
A
A
A
A
字符串函数
导入 #include<string.h>
strlen(数组地址) 字符串求长度, 遇到'\0'结束,不算‘\0’
会看字符串有效长度
void main() { //strlen测试的结果 char s0[] = "0111\0116"; // 6 char s1[] = "0111\0a"; //4 char s2[] = "\xaa\08\n"; //1 char s3[] = "\t\n\\\0888"; // 3 char s4[] = { '1','2','\0','3' }; //2 printf("%d\n", strlen(s0)); printf("%d\n", strlen(s1)); printf("%d\n", strlen(s2)); printf("%d\n", strlen(s3)); printf("%d\n", strlen(s4)); }
strcpy 字符串赋值(覆盖)
strcpy(地址1,地址2); 把地址2的指向内容(带上自己的'\0')复制到地址1然后:在末尾追加'\0'
可以用于对字数组的赋值
void main() { char arr[10] = "initial"; //arr = "error"; 不对 strcpy(arr, "true"); puts(arr); //输出 true }
strcpy 如果原来的数组里面有数据,会覆盖原来的数据。从头开始。 有多长覆盖就覆盖多长
strcmp(地址1,地址2)字符串比较,
比较的是ASCII,一次比较;
返回值 >0, 地址1大
<0 二大,
=0两者相等, (感觉和汇编的很像呢!,dest-src)
void main() { char s0[] = "aab"; char s1[] = "aba"; if (strcmp(s0, s1) > 0) printf("s0 nb"); else printf("s1 nb"); //必然输出这个 }
strcat(地址1,地址2)字符串追加
功能:把2追加到 1上,并在末尾补‘\0’ ;
从地址1的\0处 开始追加 ,也就是把地址1的'\0'覆盖
void main() { char s0[10] = "ch"; // 最好给被追加的数组来个长度 char s1[] = "en"; strcat(s0, s1); puts(s0); //输出 chen }
//不一样哦 void main() { char s0[10] = "c\0h"; // 找到\0,直接开始追加 char s1[] = "hen"; strcat(s0, s1); puts(s0); //输出 chen }
void main() { char s1[100] = "aachen", * p; p = s1 + 2; //指向 c的地址 等价于 p=&s1[2] strcpy(s1, p);// s1里面存放的内容 chen\0en\0 puts(s1); //输出chen }