目录
一、深入浅出数组
1、数组的认知: a.静态分配空间(int a[100];400个字节)-->空间利用率差(不够用、浪费空间) b.所占内存空间特点:连续的(物理连续)-->malloc分配空间是否连续?不一定连续,链表连接所有空闲的空间,组成最终分配的空间 2、如何使用数组 a.定义数组:数组应该定义多大?char src[1024];-->柔性数组!!! 注意事项:可变长数组C99 C89:定义数组时,必须确定长度;(选择方式)-->通常使用宏的方式定义数组,使用后,一方面可以快速更改数组大小,另一方面可以加强可读性。 b.数组使用: 数组名的作用: 一维数组名:指针常量(元素类型的指针),保存的数组首元素的地址;
#include <stdio.h>
struct node
{
int len;
//char ch;
int array[0];//没有占用空间
};
int main(int argc, char const *argv[])
{
//c99:可变长数组:可以用变量来定义数组的长度
//注意事项:不能使用过程中已修改变量的值,来扩充数组的内存空间;
//柔性数组
printf("sizeof(struct node) = %ld\n",sizeof(struct node));
struct node n;
n.len = 10;
n.array = (int*)malloc(sizeof(int) * n.len);
int n; //局部变量--展空间--为初始化的变量自动赋值随机值; -122
int a[n];
int a1[0];
printf("Please input n:\n");
scanf("%d",&n);
for(int i = 0; i < n;i++)
{
a[i] = i + 1;
}
for(int i = 0; i < n;i++)
{
printf("a[%d] = %d\n",i,a[i]);
}
//n = 10;
//这个设置n的方法比没有解决我们的问题
return 0;
}
//数组名的作用
#include <stdio.h>
void func(char src[100])//退化指针:char *src-->所以为sizeof(src) = 8
{
printf("sizeof(src) = %ld\n",sizeof(src));
src++;
}
int main(int argc, char const *argv[])
{
int a[3] = {0};//局部数组
char buffer[1024] = "hello world";
func(buffer);//值没有改变
printf("%c\n",buffer[1]);
printf("%c\n",*(buffer + 1));
int *p = a;//p指向数组首元素 p == a
// memset(a,0,sizeof(a));
for(int i = 0;i < sizeof(a)/sizeof(int);i++)
{
//方法一
//scanf("%d",&a[i]);
//方法二:数组名:数组首元素的地址
//scanf("%d",a+i);
//方法三:用其他指针指向
scanf("%d",p++);
//这样不可以,数组名是一个指针常量,保存的是首地址数组
//scanf("%d",a++);
}
//这里如果不重新指向,就是指向数组范围外,为野指针
p = a;
for(int i = 0;i < sizeof(a)/sizeof(int);i++)
{
printf("a[%d] = %d\n",i,*(p + i));
}
return 0;
}
二、二维数组的数组名作用
二维数组名:指针常量(一维数组指针),保存首个一维数组的地址;
//二维数组
#include <stdio.h>
int main(int argc, char const *argv[])
{
//方法一
int aa[2][2];//-->两个int a[2]一位数组构成
//方法二:不可以省略列,但可以省略行
//int aa[][2] = {1,2,3,4};
//错误写法
//int aa[][] = {1,2,3,4};
/**
* 二维数组
* aa:指针常量,保存的是首个一维数组的地址;
* &aa:二维数组的地址
* *(&aa) = aa:对二维数组的地址取值等于首个一维数组的地址
* *aa:首个一维数组的首个元素的地址
*/
printf("&aa[0][0] = %p\n",&aa[0][0]);
printf("aa = %p\n",aa);
printf("&aa = %p\n",&aa);
printf("&aa[0][0] + 1 = %p\n",&aa[0][0] + 1);//四个字节
printf("aa + 1= %p\n",aa + 1);//八个字节-->二维数组中首个一维数组的地址
printf("&aa + 1 = %p\n",&aa + 1);//为什么是10?
for(int i = 0;i < 2;i++)
{
for(int j = 0;j < 2;j++)
{
//scanf("%d",&aa[i][j]);
scanf("%d",(*(aa+i)+j));
}
}
/**
* *(*(aa+i)+j)
* aa:二维数组中首个一维数组的地址;
* aa + i:二维数组中第i+1个一维数组的地址;
* *(aa+i):二维数组中第i+1个一维数组的首个元素的地址;
* *(aa+i)+j;二维数组中第i+1个一维数组的j+1个元素的地址;
* *(*(aa+i)+j):************的值;
*/
for(int i = 0;i < 2;i++)
{
for(int j = 0;j < 2;j++)
{
// printf("aa[%d][%d] = %d\n",i,j,aa[i][j]);
printf("aa[%d][%d] = %d\n",i,j,*(*(aa+i)+j));
}
}
return 0;
}
三、再谈数组名的作用
#include <stdio.h>
int main(int argc, char const *argv[])
{
char str[100];//"hello1"
char ktr[2][100];//"hello2""hello3"
char ptr[3][2][100];//"hello4""hello5""hello6""hello7"..
printf("Please input str:\n");
scanf("%s",str);//首元素的地址
printf("str = %s\n",str);
printf("Please input ktr:\n");
for(int i = 0; i < 2;i++)
{
//方法一
//scanf("%s",*(ktr + i));
//方法二
scanf("%s",ktr[i]);//*(ktr + i)
}
for(int i = 0; i < 2;i++)
{
//方法一
printf("ktr[%d] = %s\n",i,*(ktr + i));//ktr[i]
}
printf("Please input ptr:\n");
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 2;j++)
{
scanf("%s",*(*(ptr + i)+j));
//scanf("%s",ptr[i][j]);
}
}
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 2;j++)
{
printf("ptr[%d][%d] = %s\n",i,j,*(*(ptr + i)+j));//ptr[i][j]
}
}
return 0;
}
四、数组指针变量的应用场景
数组指针变量:保存数组的地址
如何定义一个数组指针变量 ? 右左法则 int(*pa)[2]; 数组指针的使用场景-->函数传参:定义函数
#include <stdio.h>
void print(char* str)
{
printf("str = %s\n",str);
}
void print2(char (*ktr)[100])
{
for(int i = 0; i < 2;i++)
{
//方法一
printf("ktr[%d] = %s\n",i,*(ktr + i));//ktr[i]
}
}
void print3(char (*ptr)[2][100])
{
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 2;j++)
{
printf("ptr[%d][%d] = %s\n",i,j,*(*(ptr + i)+j));//ptr[i][j]
}
}
}
int main(int argc, char const *argv[])
{
char str[100];//"hello1"
char ktr[2][100];//"hello2""hello3"
char ptr[3][2][100];//"hello4""hello5""hello6""hello7"..
printf("Please input str:\n");
scanf("%s",str);//首元素的地址
print(str);
//printf("str = %s\n",str);
printf("Please input ktr:\n");
for(int i = 0; i < 2;i++)
{
//方法一
//scanf("%s",*(ktr + i));
//方法二
scanf("%s",ktr[i]);//*(ktr + i)
}
print2(ktr);
// for(int i = 0; i < 2;i++)
// {
// //方法一
// printf("ktr[%d] = %s\n",i,*(ktr + i));//ktr[i]
// }
printf("Please input ptr:\n");
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 2;j++)
{
scanf("%s",*(*(ptr + i)+j));
//scanf("%s",ptr[i][j]);
}
}
print3(ptr);
// for(int i = 0;i < 3;i++)
// {
// for(int j = 0;j < 2;j++)
// {
// printf("ptr[%d][%d] = %s\n",i,j,*(*(ptr + i)+j));//ptr[i][j]
// }
// }
return 0;
}
五、指针数组
数组里面保存的都是指针
#include <stdio.h>
#include <stdlib.h>
void print4(char **pc)
{
for(int i = 0; i < 3; i++)
{
printf("pc[%d] = %s\n",i,*(pc+i));
//错误//函数参数改成**后正确
printf("pc[%d] = %s\n",i,pc[i]);//这里代表的是字符,不是字符串\地址
}
}
int main(int argc, char const *argv[])
{
int * pi[3] = {0};//int (*pi)[3]这个是数组指针,前面是指针数组
printf("sizeof(pi) = %ld\n",sizeof(pi));
//使用
#if 0
int num1 = 5;
int num2 = 6;
int num3 = 7;
pi[0] = &num1;
pi[1] = &num2;
pi[2] = &num3;
for(int i = 0;i < 3;i++)
{
printf("pi[%d] = %d\n",i,*pi[i]);
}
#endif
#if 0
//使用注意事项
//1\局部指针数组里元素都是野指针;需要分配地址
//2\用完之后释放空间,并置空
for(int i = 0;i < 3;i++)
{
pi[i] = (int *)malloc(sizeof(int));//为每一个地址开辟空间
scanf("%d",pi[i]);//直接使用,产生段错误
}
for(int i = 0;i < 3;i++)
{
printf("pi[%d] = %d\n",i,*pi[i]);
free(pi[i]);
pi[i] = NULL;
}
#endif
//存储的是字符串的首地址,初始化赋值后,不可以改变内容
char *pc[3] = {"hello1","hello2","hello3"};
print4(pc);
//为每个字符串开辟了空间,每个空间有100个字节,可以之后修改内容
char ktr[3][100] = {"hello1","hello2","hello3"};
// pc[0] = (char *)malloc(sizeof(char) * 50);
// pc[1] = (char *)malloc(sizeof(char) * 100);
return 0;
}