一、数组
1> 数组通俗的讲就是用来存储一组数据的,它的特点就是只能存储一种类型的数据。里面存放的数据被称为元素。
2> 格式: 类型 数组名 [ 元素个数 ]; => int a[5];
错误写法: int a[]; // 定义时不可以不指定元素个数
3> 初始化:初始化是指在数组定义的同时给数组元素赋值。
注意: 只有在定义时, 并且元素个数是常量[表达式]时, 才可以用{}初始化, 未被初始化的元素会被自动赋值为0。
(常量可以是 数字, #define的宏, const变量, 字符常量等)。
4> 初始化的方式
int a[5] = {1, 2,3, 4, 5};
int a[] = {1, 2, 3,4, 5}; // 初始化时可以省略元素个数, 相当于 int a[5] = {...};
int a[5] = {1,2}; // 初始化部分元素: 只给前两个元素赋值, 其它元素默认为0.
int a[5] = {[3] =4, [4] = 5}; // 初始化指定元素: 只给a[3]和a[4]赋值, 其它元素默认为0
int a[5] = {}; // 所有元素赋值为0
int a['A'-60] = {1,2, 3}; // 相当于 int a[5] = {...};
错误写法1: int a[5]; a = {1, 2, 3, 4,5}; // 初始化只能在定义时使用,定义后数组名就是个常量, 不能被赋值。所以必须要逐个元素来赋值。
错误写法2: int n = 5; int a [n] = {1, 2, 3, 4, 5}; // 元素个数必须为常量或常量表达式时才能在定义时初始化. 如果是变量或变量表达式, 不能初始化。
但是可以这样: int a[n]; a[0]= 1; a[1] = 2; // 注意这样就不是初始化了, 没有赋值的元素的值不是0,而是任意数。
5> 数组元素的赋值
a[0] = 1;a[1] = 2;
注意: 如果数组经过{ }初始化后, 没有被主动赋值的元素值为0;如果是在定义后逐个赋值, 没有被主动赋值的元素值可能为任意值。
6> 计算数组元素个数
int n = sizeof (a) / sizeof (int);
注意:如果把数组名作为函数参数,函数参数接收的是数组的地址,使用sizeof(a)打印出的是指针的大小8个字节,而不是整个数组所占的字节数。所以必须要把数组中元素的个数作为参数传递给函数。
eg:
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:12px;">int main() { int ages[]={10,21,32,12,12}; //计算数组元素的个数 int count =sizeof(ages)/sizeof(int); printf ("%d\n",count ); return 0; }</span></span></span>
7> 数组元素的遍历
遍历: 按顺序查看数组的每一个元素
for (i = 0; i < n; i++)
printf("a[%d]= %d\n", i,a[i]);
数组在内存中的存储细节
数组名就是数组的地址
eg:int ages[3]={10,19,18};在内存中的存储形式如下图所示:
其中:ags的地址是第一行地址(也是第一个元素的地址):ffc19;
ages[0]的地址是:ffc19;
ages[1]的地址是ffc23;
ages[2]的地址是ffc27;
其中每个变量在内存中的存储形式如下:
数组与函数
注意点:1>数组作为函数参数,可以省略元素个数;
2> 数组作为函数的参数,传递是整个数组的地址,修改函数形式参数组元素的值,会影响到外面的实参数组。
eg:<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:12px;">#include <stdio.h> void change(int array[])//当数组作为函数参数传递时,会当做指针变量来使用,占8个字节。 { array[0]=100; } int main() { int ages[6]={11,22,32,43,12,21}; printf ("ages==%p\n",ages); change(ages); printf("%d\n",ages[0]); return 0; }</span></span>
本来数组ages第一个元素为11,但在change函数中有重新定义了第一个元素及结果改为100。
二、字符串
1、字符串其实就是一个以\0结尾的字符数组。字符串通常以""表示, 使用""会自动在后面加'\0'字符,字符串由字符数组组成。
2、初始化
char name[10] = {'J', 'a', 'c', 'k','\0'};
char name[10] = {'J', 'a', 'c', 'k',0};因为'\0' 的ASCII码值为0
注意:char name[10] ={'a', 'b'}; \\ 也是一个字符串, 因为字符数组默认后面的值都是0 (即'\0')。
但是:char name[2] = {'a','b'};
char name[] = {'a','b'}; 就不是字符串了, 因为它们只有两个元素, 不以\0结束。
每个字符串都是由一个字符数组组成,但是不能说任何一个字符数组都能组成一个字符串。
3、通常还是使用双引号来定义
char name[10] ="Jack"; // 使用双引号会在末尾自动添加'\0'
char name[] ="Jack"; // 可以不指定数组大小
4、定义字符串的两种方式:
1>利用数组:char name[]="itcost";
特点:字符串里面的字符是可以改变的。适用场合:字符串内容需要经常修改。
2> 利用指针:char *name = "itcost";
特点:此时的字符串是一个常量字符串,里面的内容不能修改。适用场合:字符串内容不需要修改。
单引号'' 和双引号""区别:
'' :单引号只能扩住单字节的字符(ASCII表中都是单字节)。
"" :双引号扩住的是字符串。
记数问题:
sizeof:计算所占内存,计算占的字节数。
strlen:计算字符串长度(计算的是字符数,不包括\0。如果遇到\0,则结束记数)。
eg: strlen("哈Jack"); // 返回 7, 一个汉字占三个字符
printf 函数打印字符串的原理
printf函数中使用name2作为参数, 这个数组名其实就是传递了数组name2的地址, printf("%s",a)这个函数就是从提供的地址开始输出字符, 一直到\0结束输出. 所以,如果一个字符串不以'\0'结束,那么就会一直打印,直到遇到一个'\0'为止,如果打印到未被赋值的内存区域,就会打印出乱码。
字符串的遍历
编写一个函数来判断一个字符串中是否包含某个特定字符, 如果包含就返回1, 否则返回0。<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:12px;"> #include <string.h> int contains_char(char str[],char c) { for (int i= 0; i <strlen(str);i++){ if (str[i] ==c) return 1; } return 0; }</span></span>