1.数组
数组的初始化必须出现在定义语句中
如 int a[3] = {1,2,3}
a 表示a[0]的地址,&a 代表数组a的取地址。
[]内不可为负数。C/C++语言中数组下标越界,编译器不会检查处错误,但是实际上会导致程序崩溃。
数组也可
以这样表达:
int b[100] = {[0...49]=100,[50...99]=200}; //意思是b[0]到b[49]都等于100,b[50]到b[99]都等于200
(延伸:...也可以用于switch 中
如:
switch()
{
case 1:
case 2:
case 3...10:
})
二维:int b[2][3]解析:第一部分 b[2], 第二部分 int [3];b是一维数组,只不过其中的两个要素都是一个int [3]的一维数组罢了
1.1变长数组(不初始化的赋值
)
int i = 3;
int a[i];
a[0] = 100;
1.2柔性数组
code1
1 #include <stdio.h> 2 #include <malloc.h> 3 4 typedef struct _soft_array 5 { 6 int len; 7 int array[]; 8 }SoftArray; 9 10 int main() 11 { 12 int i = 0; 13 SoftArray* sa = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) * 10);//分配内存并命名为sa 空间大小为10个int类型和一个空int型数组类型 14 15 sa->len = 10; 16 17 for(i=0; i<sa->len; i++) 18 { 19 sa->array[i] = i + 1; 20 } 21 22 for(i=0; i<sa->len; i++) 23 { 24 printf("%d\n", sa->array[i]); 25 } 26 27 free(sa); //释放内存!!!必须记得 28 29 return 0; 30 }
* 柔性数组即数组大小待定的数组
* C语言中结构体的最后一个元素可以是大小未知的数组
* C语言中一般由结构体产生柔性数组
1.3字符数组与字符串
char s1[5] = {'a', 'b', 'c', '\0'};
char s2[5] = {"abc"};
char s3[5] = "abc"; //三个表达式所达到的效果一样
任何数组的名字代表了首元素的地址,即s1 = &s1; “abc”代表 a 字符的地址,故有:字符串变量和字符数组,它们的变量名代表首字符地址
注意:字符串默认有一个null结束符,字符数组没有
printf("%c\n", s3[1]);
printf("%c\n", "abc"[1]);
--->延伸:常量字符串是一个匿名的字符数组的名字
顺便提一下 sizeof 和 strlen 的区别
sizeof(s2) = 3 //求s2字符串有几个字符(不包括'\0')
strlen(s2) = 5 //求s2有几个字符 (包括'\0'和乱码的字符)
2.内存地址(指针)
内存组织单元:字节(32位的计算机有内存2^32个字节)
2.1指针定义和初始化( 定义初始化分开写也行 )
int * p = &a;
2.2指针赋值
int b = 200;
p = &b;
2.3取目标(解引用)
*p = 201;
==> b = 201;
2.4取地址
int *(*k);
k = &p;
*p = 202; ==> b = 202;
2.5加减法(数组运算/指针运算)
int number[4] = {11,22,33,44};
int *p;
p = number; //等价于p = &number[0]; 数组运算时,数组名字代表首元素的地址
p = p+2; //若p原来指向 0x008000,运行之后p指向0x008008.因为p是int *类型的。 //等价于p = &number[2];
以下解释
类型的思想:
1 int *p1; //p1是int *类型 2 p1 = &a; 3 4 5 int *(*q); // *q 是 int*的类型 6 2 1 7 8 q = &p1; //故写成这样是可行的
==》取得的函数或者变量的类型方法:是将函数/变量的名字盖住,剩下的就是类型
如:int a[3]; 的
类型是 int[3]
例子1:
int a[5] = {1,2,3,4,5};
int (*p)[5];
p = &a; //此处的 a 代表整个数组,取数组a的地址,也就是取数组第一个元素的所在的地址
p =a; //此语句错误!!!!!
因为
p指向整个数组a的,因为p的类型是int [5] 的指针,只能用来指向整个数组,不可以用来指向一个变量
例子2:
float f[5] = {1,2,3,4,5};
float (*p2)[5] = {1,2,3,4,5};
==> p2 = &f; //p2指向float的整体(f在此处不看做地址,而是一个数组的名字) *p2 = f; p2 = &f;
因此,f[2] = 30;
可以写成: (*p2)[2] = 30;
匿名内存:malloc
int *p = malloc(100);//malloc分配的内存是没有名字的,然后给它定义类型 int * 和名字 p
3.函数指针
函数声明
int sumup(int a, float b);
int (*p3) (int a, float b); //指针p3使用来指向函数sumup的
【回顾:两者的类型都是 int (int a, float b);】
int* (*p4)(int a, float b);
从类型上看,int* (int a, float b) 是上式函数的指针。故有:p4 = &p3;
函数的调用
sumup (100,1.21);
(*p3) (100,1.21); //与上等价
*(p4) (100,1.21); //与上等价
4.void指针
(通常用于在分配完成后,不知是什么类型的指针。好处在于:void指针可以赋值给任何类型的指针)
定义与初始化:
void * p5 = malloc(100); //malloc函数就是一个void指针
在内存中放置数据需转化内存
int i;
for(i=0; i<25; i++)
{
*((int*)p5+1) = i+1; //将p5指向的那一块占100字节的内存存入{1,2,3,4....25}一共25个int型数据
}
5.空指针
表达形式:
int *p6 = NULL;
int *p7 = 0;
6.const指针
在C语言中不可以用来定义常量
const int b;
int const b; //等效上式
(在c++中,const int globle ;为const常量)
只能在初始化的时候赋值 !
int const b = 5;
在指针应用中,const前后的差别:
-->可以通过p来修改目标
const char *p = &b;
char const *p = &b;
-->p本身不能修改
char *const p = &b;