C04-array-string
本文最后更新于:1 小时前
C数组
数组中每个元素的数据类型必须相同,对于
int a[4];
,每个元素都必须为 int类型。数组长度 length 最好是整数或者常量表达式,例如 10、20*4 等,这样在所有编译器下都能运行通过
访问数组元素时,下标的取值范围为 0 ≤ index < length,过大或过小都会越界,导致数组溢出,发生不可预测的情况
数组内存是连续的。连续的内存为指针操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等)提供了便利,这使得数组可以作为缓存(临时存储数据的一块内存)使用。
在我们没有明确数组的元素个数时,在程序中想知道数组单元个数可以使用 sizeof(a)/sizeof(a[0]), sizeof(a) 是得到数组 a 的大小,sizeof(a[0]) 是得到数组 a 中单个元素的大小(因此可以不必要是a[0],a[i]都行),例:
1 |
|
数组的初始化
可以先定义数组再给数组赋值,也可以在定义数组的同时赋值,例如:int a[4] = {20, 345, 700, 22};
数组元素的值由’{ }’包围,各个值之间以’,’分隔。
对于数组的初始化需要注意以下几点:
- 可以只给部分元素赋值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:
int a[10]={12, 19, 22 , 993, 344};
表示只给 a[0]~a[4] 5个元素赋值,而后面 5 个元素自动初始化为 0。
当赋值的元素少于数组总体元素的时候,剩余的元素自动初始化为 0:
对于short、int、long,就是整数 0;
对于char,就是字符 ‘\0’;
对于float、double,就是小数 0.0。
我们可以通过下面的形式将数组的所有元素初始化为 0:int nums[10] = {0};
char str[10] = {0};
float scores[10] = {0.0};
由于剩余的元素会自动初始化为 0,所以只需要给第 0 个元素赋值为 0 即可。
只能给元素逐个赋值,不能给数组整体赋值。例如给 10 个元素全部赋值为 1,只能写作:
int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
而不能写作:int a[10] = 1;
如给全部元素赋值,那么在定义数组时可以不给出数组长度。例如:
int a[] = {1, 2, 3, 4, 5};
等价于int a[5] = {1, 2, 3, 4, 5};
如果省略掉数组的大小,数组的大小则为初始化时元素的个数。例如:
int a[] = {1, 2, 3};
得到一个有三个元素的数组
二维数组
对于二维数组的初始化要注意以下几点:
- 可以只对部分元素赋值,未赋值的元素自动取“零”值。例如:
int a[3][3] = {{1}, {2}, {3}};
是对每一行的第一列元素赋值,未赋值的元素的值为 0。赋值后各元素的值为:
1 0 0
2 0 0
3 0 0
再如:int a[3][3] = {{0,1}, {0,0,2}, {3}};
赋值后各元素的值为:
0 1 0
0 0 2
3 0 0
如果对全部元素赋值,那么第一维的长度可以不给出。例如:
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
可以写为:int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么它就是二维数组。当然,前提是各个元素的类型必须相同。根据这样的分析,一个二维数组也可以分解为多个一维数组,C语言允许这种分解。
例如,二维数组a[3][4]可分解为三个一维数组,它们的数组名分别为 a[0]、a[1]、a[2]。
这三个一维数组可以直接拿来使用。这三个一维数组都有 4 个元素,比如,一维数组 a[0] 的元素为 a[0][0]、a[0][1]、a[0][2]、a[0][3]。
二维数组在逻辑上是方阵,由行和列组成。
但是二维数组在物理上是线性的,按行来依次进行存放,内存是连续的。
二维数组名即首行的地址,C 语言中的地址一般均是空间首地址。故二维数组名是首行首地址,该数组名加 1 表示跳过一整行,到达第二行的首地址,以此类推。
二维数组名加 1 表示跳过一个对象(一行)的空间,为下一个对象(下一行)的地址。即跳过一个对象所有属性(一行中所有列元素)对应的空间,到达下一个对象(下一行)的起始位置。
传递数组给函数
有三种方式可以向函数传递数组
方式 1
形式参数是一个指针(您可以在下一章中学习到有关指针的知识):
void myFunction(int *param){}
方式 2
形式参数是一个已定义大小的数组:
void myFunction(int param[10]){...}
方式 3
形式参数是一个未定义大小的数组:
void myFunction(int param[]){...}
二维数组传递给函数
方法1: 第一维的长度可以不指定,但必须指定第二维的长度:
void print_a(int a[][5], int n, int m)
方法2: 指向一个有5个元素一维数组的指针:
void print_b(int (*a)[5], int n, int m)
方法3: 利用数组是顺序存储的特性,通过降维来访问原数组!
void print_c(int *a, int n, int m)
1 |
|
从函数返回数组
C 语言不允许返回一个完整的数组作为函数的参数。但是可以通过指定不带索引的数组名来返回一个指向数组的指针。
如果想要从函数返回一个一维数组,必须先声明一个返回指针的函数,如下:
int * myFunction(){...}
另外,C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
下面的函数,它会生成 10 个随机数,并使用数组来返回它们
1 |
|
srand((unsigned)time(NULL))是初始化随机函数种子:
1、是拿当前系统时间作为种子,由于时间是变化的,种子变化,可以产生不相同的随机数。计算机中的随机数实际上都不是真正的随机数,如果两次给的种子一样,是会生成同样的随机序列的。 所以,一般都会以当前的时间作为种子来生成随机数,这样更加的随机。
2、使用时,参数可以是unsigned型的任意数据,比如srand(10);
3、如果不使用srand,用rand()产生的随机数,在多次运行,结果是一样的。
C字符串
用来存放字符的数组称为字符数组,例如:
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
C语言规定,可以将字符串直接赋值给字符数组,例如:
char str[10] = {"Hello"};
char str[10] = "Hello";
为了方便,也可以不指定数组长度:
char str[] = {"Hello"};
char str[] = "Hello";
在C语言中,字符串总是以’\0’作为结尾,所以’\0’也被称为字符串结束标志,或者字符串结束符。
‘\0’是 ASCII 码表中的第 0 个字符,英文称为 NUL,中文称为“空字符”。该字符既不能显示,也没有控制功能,输出该字符不会有任何效果,它在C语言中唯一的作用就是作为字符串结束标志。
用” “包围的字符串会自动在末尾添加’\0’,但逐个字符地给数组赋值并不会自动添加’\0’。
如果没有在字符数组最后增加 \0 的话输出结果有误:
1 |
|
输出结果:
Greeting message: Hello烫烫烫?侵7(?╔?╚╔╔
可以手动在初始化字符串之后加上’\0’,也可以这样做:
char str[30] = {0}; //将所有元素都初始化为 0,或者说 '\0'
,然后再给字符串数组赋值。
字符串长度
所谓字符串长度,就是字符串包含了多少个字符(不包括最后的结束符’\0’)。例如”abc”的长度是 3,而不是 4。
sizeof 计算的是变量的大小;strlen 返回的是该字符串的长度,遇到 \0 结束,\0 本身不计算在内;前者不受字符 \0 影响,后者以 \0 作为长度判定依据。
在C语言中,我们使用string.h头文件中的 strlen() 函数来求字符串的长度,它的用法为:length strlen(strname);
strname 是字符串的名字,或者字符数组的名字;length 是使用 strlen() 后得到的字符串长度,是一个整数。
下面是一个输出str字符串长度的例子
1 |
|
字符串的输入和输出
字符串的输出
在C语言中,有两个函数可以在控制台上输出字符串,它们分别是:
puts():输出字符串并自动换行,该函数只能输出字符串。
printf():通过格式控制符%s输出字符串,不能自动换行。除了字符串,printf() 还能输出其他类型的数据。
1 |
|
字符串的输入
在C语言中,有两个函数可以让用户从键盘上输入字符串,它们分别是:
scanf():通过格式控制符%s输入字符串。除了字符串,scanf() 还能输入其他类型的数据。
gets():直接输入字符串,并且只能输入字符串。
但是,scanf() 和 gets() 是有区别的:
scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。
1 |
|
常用的操作字符串函数
序号 函数 & 目的
1 strcpy(s1, s2);
复制字符串 s2 到字符串 s1,strcpy() 会把 s2 中的字符串拷贝到 s1 中,字符串结束标志’\0’也一同拷贝,将 s2 复制到 s1 后,s1 中原来的内容就被覆盖了。另外,strcpy() 要求 s1 要有足够的长度,否则不能全部装入所拷贝的字符串。
2 strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾,strcat() 将把 s2 连接到 s1 后面,并删除原来 s1 最后的结束标志’\0’。所以 s1 必须足够长,要能够同时容纳 s1 和 s2,否则会越界(超出范围)。
strcat() 的返回值为 s1 的地址。
3 strlen(s1);
返回字符串 s1 的长度。
4 strcmp(s1, s2);
返回值:如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。
5 strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6 strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!