根据数据类型的不同:
- 数值数值
- 字符数组
- 指针数组
- 结构数组
C语言数组在存储时,是行优先
多维数组下,如二维数组,可以看成是嵌套:一个数组可以作为外部数组的一个元素
C语言数组是静态的,不能插入或删除元素(数组一旦被定义,占用的内存空间就是不可改变的,但是可以修改和读取数值),如果要改变一个数组,就要再造一个数组
注意:数组也是有类型的!!!
int a[10]; // 数组a的类型是int [10]
数组内存时连续的,(连续的内存为指针操作和内存处理提供了方便),数组可以作为缓存 使用,(临时存储数据的一块内存)
数组下标越界不会产生编译错误,只会在运行过程中产生错误
int a[3]={1,2,3}; // printf a[3],如a[4,5,6]...以后不知道是什么值
// 对于int a[3]={1,2,3,4,5};但是高级编译器会报错,或者
// 对于下面这种 编译器也不会报错
int a[3];
for (int i=0;i<5;i++)
{a[i]=i;
}
变长数组仍然是静态数据,一旦定义之后都是不可变的
array[length] or scanf(“%d”,&length);array[length]
#define MaxSize 10
typedef struct
{int data[MaxSize]; // 静态分配int length;
}SqList;
new是C++中的关键字
malloc 返回的是被动态分配内存的首地址
#include #define InitSize 10
typedef struct
{int *data; //动态分配int MaxSize;int length;
}SeqList;void InitList(SeqList *L)
{L->data=(int*)malloc(InitSize*sizeof(int));L->length=0;L->MaxSize=InitSize;
}void IncreaseSize(SeqList *L,int len)
{printf("%p\n",L->data); //00000000006916A0int *p=L->data;printf("%p\n",p); //00000000006916A0L->data=(int*)malloc((L->MaxSize+len)*sizeof(int)); //0000000000691700 ,就把L->data当做一个指针就行了printf("%p\n",L->data);for (int i=0;ilength;i++){L->data[i]=p[i];}L->MaxSize+=len;free(p);
}int main()
{SeqList L;InitList(&L);// for (int i=0;i// printf("%d\t",L.data[i]);// }// printf("\n%d\n",L.length);IncreaseSize(&L,5);return 0;
}
https://blog.csdn.net/L_fengzifei/article/details/126411708
创建数组:赋值个数小于开辟的内存空间,且剩余的元素会被初始化为0,
对于整型,初始化为0
对于浮点型,初始化为0.0
对于字符数组,字符数组初始化为\0
int a[10]={1,2,3};
// 只能以循环的方式进行输出
for (int i=0;i<10;i++){printf("%d\n",a[i]);
}// 方法2
int a[]={1,2,3,4}; // 自动计算需要开辟的内存空间// 比较常用的写法
int a[10]={0};
数组越界不会被编译器检测出来错误
下面还有一个越界的例子
int a3[3];
for (int i=0;i<3;i++)
{a3[i]=i;
}for (int i=0;i<3;i++)
{printf("%d\t",a3[i]); // 0,1,2
}printf("\n");// 越界不会报错!!!
for (int i=0;i<10;i++)
{printf("%d\t",a3[i]); // 0,1,2,3,3... 随机数
}
越界也会按照开辟的内存,计算sizeof()
int a[10];
int* p=a;
printf("%d\n",sizeof(a)); //40
printf("%d\n",sizeof(p)); //8int a2[10]={1,2,3};
int* p2=a2;
printf("%d\n",sizeof(a2)); //40 , 对应的是开辟的数组
printf("%d\n",sizeof(p2)); //8// 对于越界赋值,编译器不会出错
int a3[3];
for (int i=0;i<5;i++)
{a3[i]=i;
}
int* p3=a3;
printf("%d\n",sizeof(a3)); // 12
printf("%d\n",sizeof(p3)); // 8
数组指针:是指向数组的指针,!=指针数组
指针数组:数组中存放的是指针
数组名可以认为是做一个指针,指向数组的第0个元素,但是数组名不可变,数组名本身是常量
数组本身是指针这个说法不准确!!!
第0个元素的地址称为数组的首地址
数组指针 指向的是数组中的一个具体元素,而不是整个数组
指向数组的指针(数组指针),与数组名不同,数组名不可以改变,而数组指针可以改变
注意:++
具有inplace操作
(下面的具有 右结合性)
*p++ 等价于*(P++)
,不能使用*arr++
,因为数组名不能改变
*++p 等价于*(++P) 等价于*(p+1)
(*p)++只对数值进行改变
type *p=arr
p+1相当于移动了一个type类型的字节
int a[3]={1,2,4};
int* p=a;
// 下面三个是等价的
printf("%p\n",p);
printf("%p\n",a);
printf("%p\n",&a[0]);// printf("",a++); // 这个是错误的,数组名是不能改变的
printf("%d\n",*p++); // 1
printf("%d\n",*(p++)); // 1,*p赋值之后,再++
printf("%d\n",*p+1); // 2
printf("%d\n",*(p+1)); // 2
printf("%d\n",*(++p)); //2
printf("%d\n",*++p); //2
int main()
{int a[3]={1,4,5};int *p=a;// printf("%d\n",*p++);// printf("%d\n",*p);printf("%d\n",(*p)++);printf("%d\n",*p);// printf("%d\n",*(p++));// printf("%d\n",*p);for (int i=0;i<3;i++){printf("%d\n",a[i]);}return 0;
}
重要
[]
符号具有取内容的作用
a[i],*(a+i),p[i], *(p+i) 这四个是等价的
&a[i],(a+i),&p[i], (p+i) 这四个是等价的
int a[3]={1,2,3};
for (int i=0;i<3;i++)
{printf("%d,%d,%d,%d\n",a[i],*(a+i),p[i],*(p+i));printf("%p,%p,%p,%p\n",&a[i],(a+i),&p[i],(p+i));
}
创建数组:可以按行创建,也可以连续创建。部分赋值创建的时候,其他赋值元素默认初始化为0(注意部分赋值和完全不赋值随机初始化的区别,完全不赋值随机初始化的时候不是0)
如果是全部赋值,第一维度可以不写
可以理解为嵌套
// 按行创建
int a[2][3]={{1,2,3},{4,5,6}};// 按连续内存创建
int a[2][3]={1,2,3,4,5,6};// 部分赋值
int a[2][3]={{1},{2},{3}};
int a[2][3]={{0,1},{0,1,2},{3}}// 第1维度自动推导
int a[][3]={1,2,3}int a[][3]={1,2,3};
for (int i=0;i<1;i++){for (int j=0;j<3;j++){printf("%d\n",a[i][j]); // 可以打印但是不能赋值}
}// 注意!!!
// 下面的初始化是错误的,无法实现自动推导
// int a[][3];
// for (int i=0;i<3;i++)
// {
// for (int j=0;j<3;j++)
// {
// a[i][j]=i*j;
// }
// }// 嵌套理解
a[3][4] 中 a[0]是一个数组(也是一个一维数组名)
a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]
int a[2][3];
for (int i=0;i<2;i++)
{for (int j=0;j<3;j++){a[i][j]=i*j;}
}int (*p)[3]=a;
printf("%d\n",sizeof(a)); // 24
printf("%d\n",sizeof(a[0])); // 12(因为相当于一个一维数组名)
printf("%d\n",sizeof(p)); // 8
printf("%d\n",sizeof(p[0])); //4 ???
https://blog.csdn.net/L_fengzifei/article/details/126411708
a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]
对于一维数组及其指针
type *p=arr
p+1相当于移动了一个type类型的字节
对于二维数组及其指针,p+1应该移动整个一维数组对应的字节,type (*p)[n]
,(*p) 表示指针,int [n] 表示指针指向的数据类型
int a[1][3]={1,2,3};
for (int i=0;i<1;i++){// for (int j=0;j<3;j++){// printf("%d\n",a[i][j]);// }printf("%p\n",a[i]);printf("%p\n",&a[i][0]); // &a[i][0] 与a[i] 等价printf("%d\n",a[i][0]); // 这是数值
}int a[2][3]={{1,2,3},{4,5,6}};
// 下面三个是等价的
// *a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]*
printf("%p\n",a);
printf("%p\n",a[0]);
printf("%p\n",&a[0][0]);// 下面是等价的
int (*p)[3]=a;
printf("%p\n",p+1);
printf("%p\n",a+1);
printf("%p\n",a[1]);
printf("%p\n",&a[1][0]);
重要
a[i]==*(a+i)==p[i]==*(p+i)
a[i][j]==*(a[i]+j)==*(*(a+i)+j)==p[i][j]==*(p[i]+j)==*(*(p+i)+j)
int (*p)[3]=a;
for (int i=0;i<2;i++)
{for (int j=0;j<3;j++){printf("%d,%d,%d,%d,%d,%d\n",a[i][j],*(a[i]+j),*(*(a+i)+j),p[i][j],*(p[i]+j),*(*(p+i)+j));}
}/* /// 补充 ///// 理解对于1维数组int a={1,2,3};int* p=a;a[1]==*(P+1)==*(a+1)==p[1]&a[1]==p+1==a+1// 二维数组// 看成嵌套的一维数组int a[][2]={1,2,3,4};int (*p)[2]=a; *(*(p+1)+1) ==a[1][1]p指向了一个都是指针的数组(首地址),而数组元素的每个指针,指向了一个一维数组(首地址)p+1==a[1]==&a[1][0]*(p+1)==a[1]==&a[1][0] // 这个记忆方法放到下面可以理解// 下面三个方法是等价的printf("%d\n",*(a[1]+1)); //a[1]也是一个指针,表示一维数组printf("%d\n",*(*(p+1)+1)); // *(p+1) p+1表示一个一维数组,printf("%d\n",a[1][1]);
*/
重要 - 第二种表达方法
int a[2][3]={{1,2,3},{4,5,6}};int *p=&a[0][0];
for (int i=0;i<2;i++)
{for (int j=0;j<3;j++){printf("%d,%d\n",a[i][j],*((p+i*3)+j));}
}
对于字符型数组,赋值个数小于开辟的内存空间,则初始化为
"\0"
,printf("%c","\0")
打印不出来任何东西
字符型数组与数值数组的基本性质是一样的
字符数组就是字符串
c语言中没有字符串类型,所以借用字符数组存放一个字符串
char str[10]={0} // 默认初始化为\0// 一维
char s[10];// 多维
char s[2][3];// 部分赋值
char c[20]={' ','2'};// 全元素赋值,自动推导长度,这个属于字符数组,不属于字符串
char d[]={'h','e',...};// 注意!!!
char s[10];
// s="hello world"; // 这种方式不行
s[0]='0'; // 只能是下面这种方式
s[1]='2';
字符串 其实是字符数组
字符数组就是字符串
c语言中没有字符串类型,所以用 字符数组存放一个字符串
可以通过索引获得元素字符
在创建字符串的时候不能超出开辟的范围,不然会出错
注意:下面创建的字符串,具有读写权限
char s[30]={"hello world"}; // 等价于char s[30]={'h','e',...};// 其他常用方式
char s[10]="hello world";char s[]={"hello world"};
char s[]="hello world";// 为了避免\0的出现,最好的解决办法是
char s[]={0}; // 进行默认初始化// 索引
char a[10]="hello";
printf("%c\n",a[1]);
长度
strlen
计算不包括结尾的\0
sizeof
计算包含结尾的\0
#include // 必须要进行包含
char a[]="hello";
printf("%d\n",sizeof(a)); // 6
printf("%d\n",strlen(a)); // 5// sizeof 要么等价于实现开辟的内存空间,要么要包含`\0`
char a[10]="hello";
printf("%d\n",sizeof(a)); // 10 , 注意这是要开辟的数组!!!
printf("%d\n",strlen(a)); // 5// 对于数组越界 !!!
char a[3]="hello";
printf("%s\n",a); // 会发生未知字符
printf("%d\n",sizeof(a)); // 3
printf("%d\n",strlen(a)); //6
第二种创建方式
char s1[]="string1";
char *s2="string2"// 初始化注意事项
// char s1[10];
// s1="hello"; // 这种不行
char *s2;
s2="world"; // 这种可以
char s1[]="string"
这种方法定义的字符串所在的内存既有读取权限又有写入权限(可变),可以用于输入与输出函数
[]
可以指明字符串的长度,如果不指明则根据字符串自动推算
声明字符串的时候,如果没有初始化,(由于无法自动推算长度,只能手动指定)char s[10]
char *s1="string"
这种方法定义的字符串所在的内存只有读取权限,没有写入权限(不可变),只能用于输出函数
字符串访问
char arr1[]="hello world";
char *arr2="hello cpp";for (int i=0;i<11;i++)
{printf("%c,%c",arr1[i],*(arr1+i));
}
printf("\n");
for (int i=0;i<9;i++)
{printf("%c,%c\n",arr2[i],*(arr2+i));
}printf("%s\n",arr1); // hello world
printf("%s\n",arr2); // hello cpp
printf("%s\n",arr1+1); // ello world
printf("%s\n",arr2+2); // llo cpp
\0
不能显示,也没有控制功能
字符串以\0
结尾,注意字符数组不以\0
结尾
字符串逐个扫描,一旦遇到\0
结束处理
"string"会在字符串自动在末尾添加
\0
字符串的字符个数,要包括后面结尾的\0
创建的时候,要为\0,多开辟一个内存空间,所以总数要比字符串+1
// 创建字符串数组,下面这种方式只能逐个元素创建
// 当创建的字符个数小于开辟的数量,剩下的为随机初始化的内容,有可能并不是\0,注意随机初始化和部分初始化的
// 所以输出的可能字符个数可能大于30与,因为printf直到\0的时候才会结束输出
char s[30];
chr c;
int i;
for (c=65,i=0;c<=90;c++,i++){s[i]=c;
}
printf("%s\n",s)// 手动添加\0
// \0 的ASCII编码值是0
// 下面两个等价
s[i]=0;
s[i]='\0';
// strcat 字符串拼接 // inplace操作
char a1[20]="hello";
char a2[10]="world";
printf("%d\n",sizeof(a1)); // 20
printf("%d\n",sizeof(a2)); //10
strcat(a1,a2);
printf("%s\n",a1);
printf("%d\n",sizeof(a1)); // 20 char a1[]="hello";
char a2[]="world";
printf("%d\n",sizeof(a1)); // 6
printf("%d\n",sizeof(a2)); // 6
strcat(a1,a2);
printf("%s\n",a1);
printf("%d\n",sizeof(a1)); // 6 ???// 没有写入权限,失败
// char *a1="hello";
// char *a2="world";
// printf("%d\n",sizeof(a1)); // 20
// printf("%d\n",sizeof(a2)); //10
// strcat(a1,a2); // 由于没有写入权限所以不行
// printf("%s\n",a1);
// printf("%d\n",sizeof(a1)); // 20 // strcpy 字符串复制 // inplace操作
// 会将原来的数据全部进行覆盖
char a1[]="hellohello";
char a2[]="world";
printf("%d\n",sizeof(a1)); // 11
printf("%d\n",sizeof(a2)); // 6
strcpy(a1,a2); //world
printf("%s\n",a1);
printf("%d\n",sizeof(a1)); // 11 ???char a1[20]="hellohello";
char a2[10]="world";
printf("%d\n",sizeof(a1)); // 20
printf("%d\n",sizeof(a2)); // 10
strcpy(a1,a2); //world
printf("%s\n",a1);
printf("%d\n",sizeof(a1)); // 20
问题
// 对于数组越界 !!!
char a[3]="hello";
printf("%s\n",a); // 会发生未知字符
printf("%d\n",sizeof(a)); // 3
printf("%d\n",strlen(a)); //6char name[5];
strcpy(name,"zhangsan");
printf("%s\n",name); // 不发生越界??? 有的编译器会报错warning
char a='c';
printf("%p\n",&a);
printf("%p\n",a); // 这两个地址不同char b[10]="hello";
printf("%p\n",&b);
printf("%p\n",b); // 字符串的名字是地址
printf("%p\n",&b[0]); // 也是字符串第一个元素的地址int c[10]={1,2,3};
printf("%p\n",&c);
printf("%p\n",c); // 数组名也是地址
printf("%p\n",&c[0]); // 也是数组第一个元素的地址
https://blog.csdn.net/L_fengzifei/article/details/126411708
数组中所有元素保存的都是指针,就叫做指针数组
dataType *arr[]
,dataTye* (arr[])
表明是一个数组,每个元素的类型都是dataType*
注意 指针数组和二级数组的区分
int* arr[3]={&a,&b,&c};
int** p=arr; // 定义一个指向指针数组的指针,相当于(int*)* p=arrchar* str[2]={"hello","world"};
printf("%s\n",str[0]); // 输出"hello",char* s="hello";//下面的方法更好理解
char* s1="hello";
char* s2="world";
char* s[2]={s1,s2};/*
char *s="hello";char *s;
s="hello";
*/
数组中每个元素都是结构体
struct stu{char* name;int num;
}class[5];// 声明的时候初始化
struct stu{char* name;int num;
}class[5]={{"li",1},{"w",2}
};// 声明的时候初始化,自动推断元素个数
struct stu{char* name;int num;
}class[]={{"li",1},{"w",2}
};// 可以在结构体外,创建结构体数组
struct stu class[]={{"li",2},{"wang",3}
};// 访问数据
class[0].name;
class[1].num=2; //修改
因为是数组,所以数组名可以作为元素的首地址
struct stu class[]={{"li",2},{"wang",3}
};// 下面两个是等价的,都表示地址
printf("%p\n",class);
printf("%p\n",&class[0]);// 所以可以利用指针指向地址
struct stu* pstu=class; // 下面这两种访问方法都是等价的
struct stu* pstu=class;
for (int i=0;i<2;i++){printf("%s,%d\n",(pstu+i)->num,(pstu+i)->age);
}for (int i=0;i<2;i++,pstu++){printf("%s,%d\n",pstu->num,pstu->age);
}
上一篇:flink cdc MySQL2Doris 案例分享
下一篇:java开发规范