一、数组的概念
1.1 数组
数组是一组具有相同数据类型的有序变量的集合,在内存中表现为一块连续的存储区域。
1.2 数组的定义
数组定义:在普通变量定义后加[常量]
- 类型标识符 数组名[常量表达式]
- 错误:[变量]:error C2057: expected constant expression
1.3 数组的初始化
数组初始化:用{}给数组赋予初值
- 初始化元素的个数可以不全。(用1个到总数个常量和变量)
- 未初始化全,把其余的归零。
- 数组清零:char array[10] = {0};
- 不指定个数 int array[] = {2,23,5,6};
1.4 求数组空间
- sizeof(array)也可以说是:sizeof(元素)*元素的个数。
- 求数组个数:int i = sizeof(array)/sizeof(int);
- 实际在开发中,不直接写数组个数,而是用求数组个数。以利于总数发生变化时,遍历数组时不需要修改每一处。
- 除法在编译时运算是常数,不会减低运行效率
1.5 数组元素的调用
-
任何一个元素都是一个对应类型的变量,可以参与符合该类型的任何运算。
- 表示方法:使用下标[]符号,下标内可以是变量和常量。
- C语言的越界问题:如果超过定义的数组个数使用数组,就是越界。
- C语言内部没防止越界,只能程序员通过代码来防止出现。
1.6 冒泡排序
- 比较相邻的元素。如果前者比后者大,就交换这两个元素。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。
- 这样循环一轮下来,最终会将数组中最大数值的元素推到数组尾部。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
1.7 数组做参数
数组作为参数时,有如下特征:
- 可以不指定长度,也可以随便指定任何长度。
- 数组做参数时性质已经变了,本质上是传递了数组的地址(指针)给形参。
- 数组的空间特征已经消失了,无法通过形式参数获取来源数组的元素个数。
- 无论实参数组有多少个元素,使用sizeof获取形式参数的大小结果一定是4。(因为任何一个指针变量占用的大小都是4个字节)
二、字符串数组
2.1 定义
字符串数组是一种特殊的数组。特征是:
- 必须是char类型的数组。
- 在数组定义的有效空间内,必须含有一个数值是‘\0’的字节。
- ‘\0‘作为字符串的结束标志。
2.2 字符串数组初始化
2.2.1 指定元素个数的数组
1 char str1[10] = {‘a‘,‘b‘}; 2 char str2[10] = "aab";//不可超过9个有效字符
2.2.2 不指定个数的字符串数组,根据初始化个数包括‘\0‘
1 char str3[] = "abcdef"; //申请7个字节的数组空间 2 char str4[] = {‘x’, ‘y‘, ‘z‘,108}; // 申请是4个字节的数组空间
2.2.3 数组长度和字符串长度
- strlen函数:是用来计算字符串中有效字符的长度。(不包括结尾符)
- sizeof:求字符串数组的元素个数,sizeof得出的结果至少比strlen大1以上。
- strlen函数:计算方法是从数组头循环到结尾符‘\0‘结束,得出的字符串有效字符长度总是小于sizeof得出的的数值。
- sizeof:得出的数组长度与数组内每个元素存储的数值无关;而strlen函数返回的字符串长度,与结尾符‘\0‘在数组中的位置有关。
三、指针
3.1 指针的概念
- 指针的定义:一个内存变量或数组变量内存地址就是指针。
- 在32位操作系统中,任何内存变量的地址都是一个0-4G之间的数字。0x00000000---0xffffffff
3.2 指针变量
- 指针变量 :存放指针(内存地址)的变量称为指针变量。
- 任何类型的指针变量的空间大小都是4个字节。
- 指针变量记录的内存地址,也称为它指向的地址。
3.3 指针变量的定义
- 变量类型 * 指针变量名称[=地址]例如:int i=0;int *p=&i;
- 同时定义2个以上的指针变量时,每个变量前面都要加*
- int *p1,p2;//p2是int类型。
- int p1,*p2;//p2才是int*类型。
3.4 指针变量的赋值
- 指针变量不可以直接使用整数变量或常量赋值;
- int *p = 200; //错误:不能使用整数常量赋值
- int i=100,*p1 = i; //错误:p1是指针变量,i是整型变量
- 各种不同种类的指针变量之间不能直接赋值。 (除非强制转换语句)
- int i = 10;
- int *p=&i; //正确:类型相同
- char*pc =p; //错误:类型不同
- 使用*符号:对指向的内存地址上的内容进行读或写操作。
- 指针变量指向了某个内存地址,就可以通过*符号或者[]符号,来读写所指向的内存地址上的数据。
- 读写操作的所覆盖的内存空间的长度,要依据这个指针变量的来源类型的长度来决定。(对内存空间赋值或者取值)
- 指针的降级:使用了*符号或[]符号都能是指针变量降级为它的来源类型。
- int *p = &i; //定义指针变量时使用的*符号
- int j = *p; //调用指针变量操作指向内存地址上的内容使用*符号
- p[0]=10; //就如同数组变量定义时使用的是[],调用元素时也使用[]符号
- 以上的*p和p[0]都降级为了int类型
- 使用*和[]符号取值或赋值的效果:
1 int i = 0x12345678, *p=&i; 2 char*pc =(char*)p; //强制转化 3 printf("*p=0x%x,*pc=0x%x\n",*p,*pc); 4 printf("*p=%d,*pc=%d\n",p[0],pc[0]); 5 pc[0]=-1; 6 pc[1] =-3; 7 *p=100;
尽管所有类型的指针变量占用的内存空间都是4个字节,但是不同类型的指针变量到指向的内存地址上取值和赋值效果是大不相同的。
这就是为什么同样是4个字节的变量,当指针变量类型不同时不能相互赋值的原
- 指针加减的加减运算:
- 指针加减1(++ --): 偏移指针的1个来源类型的尺寸(sizeof)。
- 指针加减n(+= -=):p += n; //物理上:偏移4*n个字节,逻辑上:偏移n个int的空间
- 指针法和下标法的对比:指针变量仍然可以按照数组的取值方式,例如:int* p;
- p[0]等价于*p
- p[n]等价于*(p+n)
- 两种方法都会降级为来源类型,例如:p[1]和*p都是int类型
- 其他指针运算:
- 两个指针加减:
- int *p1=&i,*p2=a;
- p1+p2; //错误:cannot add two pointers
- p1-p2; //正确:(只能相同类型指针相减)
- 物理上:p1-p2的结果是6而不是24,是sizeof(int)的整数倍
- 逻辑上:两个指针相距6个int的空间
- 两个指针变量或常量比较:== != < > <= >=
- 两个指针加减:
- 指针变量做形式参数时,经常用于改变主调函数的实参数值:(使用取值符号*或者下标[]来远程操作实参)