#include <stdio.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main1(){
int a[5] = {1,2,3,4,5};
printf("the size of int :%d\n", sizeof(int));
printf("the size of arr :%d\n", sizeof(a)); //求a数组的占用内存空间大小
printf("the length of arr :%d\n", sizeof(a) / sizeof(int)); //求数组的大小
for (int i = 0; i < 5; ++i) {
printf("a[%d]=%d, address: %x \n",i,a[i],&a[i]);
}
printf("%d,%d",a[10],a[1000]);
//越界访问数组,如果有权限访问,则会读到垃圾数据;如果没有权限访问,则会报错,发生访问冲突
//C语言编译器不检查数据越界,能编译不保证可以运行
}
/*
the size of int :4
the size of arr :20
the length of arr :5
a[0]=1, address: 61fe30
a[1]=2, address: 61fe34
a[2]=3, address: 61fe38
a[3]=4, address: 61fe3c
a[4]=5, address: 61fe40
数组在内存中是连续排列的,每个元素之间相差一个int,四个字节
int是四个字节,数组每个元素占4个字节
第M个元素的地址是: a+(M-1)*sizeof(int) 数组名a为数组的首地址
数组访问不要越界,虽然也能访问,但在不属于自己的权限内,可能会被其他进程占用,导致程序奔溃
* */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define N 10 //不可变常量
//没有分号结束,编译器把N放在常量池,没有内存实体,没有内存地址,无法修改其值,不可以打印其地址printf("%x",&N);会报错
const int M=10; //可变常量
//const有分号结束,系统会给M分配内存空间和地址,即有内存实体,只是无权限修改其值,可以通过其他途径修改.可以打印其地址 printf("%x",&M);
void main2(){
int a[N]; //只有N可以,int a[M] 不可以,错误
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main3(){ //数据定义时候初始化可以避免初始化内存单元不确定导致的许多问题
//给数组a的三个元素赋值
int a[] ={1,2,3};
//给数组b的10个元素初始化为0
int b[10] ={0};
//给数组c的前四个元素赋值为1,2,3,4,剩余的元素默认赋值0,duoble就是0.00000
int c[10] ={1,2,3,4};
int d[10] ={0};
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main4(){ //选择法排序
int a[6]={9,3,2,6,7,8};
for (int i = 0; i < 6; i++) {
int min=i; //最小值的数组下标
for (int j = i; j < 6; j++) {
if(a[j] < a[min]){
min = j;
}
}
if (a[min] != a[i]){
int t = a[i];
a[i] = a[min];
a[min] =t;
}
}
for (int k = 0; k < 6; k++) {
printf("%d,",a[k]);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//二维数组的初始化
void main5(){
int a[][4] ={{1,3,4,3}}; //N维数组大括号初始化时,第一维数字可以省略,相当于a[1][4]
int b[3][4] ={{0},{0},{0}};
int c[3][4] ={{1},{2},{3}};// {1 0 0 0},{2 0 0 0},{3 0 0 0}
//int d[3][] ={0}; 错误,第二维不能省,不确定一位数组有多少个元素
int e[2][2] ={1,2,3,4};
//用一维数组进行初始化二维数组
int x = 0;
for (int i = 0; i < 12; i++) {
b[i/4][i%4] = ++x;
printf("%6d\n",b[i/4][i%4]);
}
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; j++) {
printf("%4d, %x,%x", b[i][j],&b[i][j],b[i]+j);
}
printf("\nb[%d]=%x\n",i,b[i]); //二维数组中一位数组下标就代表其首地址
}
}
/**
1, 61fdf0,61fdf0 2, 61fdf4,61fdf4 3, 61fdf8,61fdf8 4, 61fdfc,61fdfc
b[0]=61fdf0 b[0]的地址和b[0][0]的地址是一样的,表示二维数组下的一位数组的首地址
5, 61fe00,61fe00 6, 61fe04,61fe04 7, 61fe08,61fe08 8, 61fe0c,61fe0c
b[1]=61fe00 b[1]的地址和b[1][0]的地址是一样的
9, 61fe10,61fe10 10, 61fe14,61fe14 11, 61fe18,61fe18 12, 61fe1c,61fe1c
b[2]=61fe10 b[2]的地址和b[2][0]的地址是一样的
结论 :1、 a[X] 代表第(X+1)行的首地址
2、&b[i][j] 等价于 b[i]+j ,也就是b[i]加1,就是加一个int类型的字节数,即加32个bit,4个字节
3、a[i][j] <=> *(&a[i][j]) <=> *(&a[i]+j)
4、静态二维数组会开辟一段连续的内存空间存储数据,也就相当于一个长的一维数据 a[i+j]
5、动态二维数组数据存储不连续,是一个指针数组,每个元素都是一个指针,存放另一个数组的首地址
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*输入一个正整数n(1<n≤10),根据以下公式生成1个n * n的方阵,然后输出此方阵对角线上元素的和。
公式为:a[i][j] = i * n + j +1
(0≤i<n , 0≤j<n)
例如,当n=3时,有方阵如下:
1 2 3
4 5 6
7 8 9
输出的对角线上元素和即为15。
*/
#define N 10
void main6(){
printf("please input integer n");
int n;
scanf("%d",&n);
int a[N][N] ={0};
int num=0; //用于赋值自然数
//一维循环初始化二维数组
for (int i = 0; i < n * n; ++i) {
a[i/n][i%n] = ++num;
printf("%-3d",a[i/n][i%n]);
if((i+1)%n == 0){ //换行
printf("\n");
}
}
//输出对角线的和
int res=0;
for (int j = 0; j < n; ++j) {
res += a[j][j];
}
printf("%d",res);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//用一个for循环初始化三维数组
void main(){
int a[2][3][4]={0}; //记住数组一定要初始化,否则会读到许多垃圾数据
printf("%d\n", sizeof(a));
int num =0;
int x= 0, y = 0, z= 0;
for (int i = 0; i < 2*3*4;i++) {
z = num /(3*4); //竖坐标:是二维平面个数的倍数, num%(3*4)是总个数在二维平面的余数,也就是二维数组的总个数
y = num%(3*4) /4; //纵坐标: num%(3*4)是总个数在二维平面的余数,再除以4,就是行数
x = num%(3*4) % 4; //横坐标:num%(3*4)是总个数在二维平面的余数,取余4,求出每行的余数,就相当于列数
a[z][y][x] = ++num ;
printf("%3d,%3d,%3d,%3d,%3d,%3d\n",i, num,a[z][y][x],z, y, x);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//用三个 for循环 初始化三维数组
void main8(){
int a[2][3][4] ={0}; //数组必须初始化,否则会出现垃圾数据
int num =0;
for (int i = 0; i < 2; ++i) { //面变化最慢
for (int j = 0; j < 3; ++j) { //行变化次之
for (int k = 0; k < 4; ++k) { //列变化最快
a[i][j][k] = ++num;
printf("%4d", a[i][j][k] );
}
printf("\n");
}
printf("\n\n");
}
}
/*
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
维数决定了数组中元素的组织方式及访问元素说用的下标个数,但本质上讲,所有的数组在内存中都是一维线性的,所有元素都是连续排列的,中间没有间隔。
以二维数组为例,内存中是先放第1行的元素,再放第2行的元素,依次类推,下面给出了大小为3×4的二维数组A的排列顺序:
A[0][0]-> A[0][1]-> A[0][2]-> A[0][3]->
A[1][0]-> A[1][1]-> A[1][2]-> A[1][3]->
A[2][0]-> A[2][1]-> A[2][2]-> A[2][3]
多维数组的存储方式与此类似,可以将下标看成是一个计数器,像计数的万位、千位、百位、十位和个位一样,右边的下标(靠后的下标)是低位,每一位都在上下界间变化,
变化的范围是0到声明时指定的下标值减1,当某一低位计数器超出范围时(达到声明时指定的下标值),左边下标加1,同时该低位计数器及其右边的更低位计算器置0(回到下界)。
这样,最左边一维下标变化是最慢的,最右一维下标变化最快。
* */