数组
1. 数组特性
# include <stdio.h>
# include <string.h>
int main(void)
{
//数组初始化
int a[5];
int b[5] = {5, 6, 7, 8, 9};
int c[5] = {0, 6};
int d[5] = {0};
int e[5] = { [0 ... 2]=1, [3 ... 4]=2 };
int f[ ] = {1, 2, 3, 4, 5};
char ch[] = "12345";
//单个输出各数组内容
printf("%d\t%d\t%d\t%d\t%d\n",b[0], b[1], b[2], b[3], b[4]);
printf("%d\t%d\t%d\t%d\t%d\n",c[0], c[1], c[2], c[3], c[4]);
printf("%d\t%d\t%d\t%d\t%d\n",d[0], d[1], d[2], d[3], d[4]);
printf("%d\t%d\t%d\t%d\t%d\n",e[0], e[1], e[2], e[3], e[4]);
//获取数组大小和长度
printf("a[] sizeof= %d\n", sizeof(a));
printf("f[] len= %d\n", sizeof(f)/sizeof(*f));
printf("ch[] len= %d\n", sizeof(ch)/sizeof(*ch));
//循环输出数组地址及其相应内容、数组所占字节数
int i;
for (i=0;i<5;++i)
{
//scanf("%d", &a[i]); // 输入
printf("%p-->%d\n", &a[i], a[i]); // 输出
}
//清空
unsigned int g[3] = {0};
memset(a, 0, sizeof a); // 用来对一段内存空间全部设置为某个字符
bzero(a, sizeof a); // 置字节字符串前n个字节为零且包括‘\0’
//十六进制输出的a和a[0]的地址
printf("g\t= %#x\n&g[0]\t= %p\n", g, &g[0]);
//scanf("%s", ch); //数组名为地址
//数组越界访问
printf("example:a[-1]=%d, a[5]=%d\n", a[-1], a[5]);
return 0;
}
运行结果
5 6 7 8 9
0 6 0 0 0
0 0 0 0 0
1 1 1 2 2
a[] sizeof= 20
f[] len= 5
ch[] len= 6
0xbfc74500-->8
0xbfc74504-->-1217364042
0xbfc74508-->-1217310720
0xbfc7450c-->-1217363943
0xbfc74510-->112
g = 0xbfc744f4
&g[0] = 0xbfc744f4
example:a[-1]=0, a[5]=5
1)数组初始化可以不赋值、全赋值、不完全赋值、赋零值;不完全赋值时余下自动清零,赋零值时等效于清空;数组可以范围赋值,缺省长度赋值。
2)元素内存连续分配,元素所占字节由数据类型决定。
3)数组大小等于数据类型*元素个数。缺省长度赋值时大小由系统按元素个数分配,字符串包含字符’\0’元素。
4)数组可定义时清空,使用函数清空。
5)数组名a是表示地址的常量,也是数组的起始位置。
6)a[i] = *(a+i),取起始地址向后偏移 i×sizeof(数据类型)字节的值。
7)数组越界不检查,例如: a[-1],a[5]。
2. 一维数组
# include <stdio.h>
int main(void)
{
//定义初始化
int a[3] = {0, 100, 200};
//单个赋值
a[0] = 100;
a[1] = 200;
a[2] = 300;
//循环赋值
int i;
for (i=0;i<3;++i)
{
scanf("%d", &a[i]); // 输入
printf("a[%d]=%d\n", i, a[i]); // 输出
}
return 0;
}
3. 二维数组
# include <stdio.h>
int main(void)
{
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int b[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int c[ ][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
//二维数组理解:在线性连续d空间挖了两个坑,每个坑装"int [3]"(有三个小元素的元素,小元素为int型)
int (d[2]) [3] = { {77, 88, 99} , {1, 2, 3} };
// d[0] d[1]
// d[0][0] d[0][1] d[0][2] , d[1][0] d[1][1] d[0][2]
int i, j;
for (i=0; i<3; ++i)
{
for (j=0; j<4; ++j)
{
//scanf("%d", b[i][j]);
printf("%d\t", b[i][j]);
}
printf("\n");
}
return 0;
}
4. 字符数组
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s1[9] = {'a', '\0', 'c', '\0'};
char s3[5] = {'a', 'a', 'a'}; //"aaa"
s3[1] = 'B';
//输出单个字符和所有字符
printf("%c, %s\n", s3[1], s3);
//字符'\0'
if('\0'==0 && '\0'==NULL)
printf("\'\\0\' is 0 and NULL.\n");
//字符的整型输出
int i;
for(i=0; i<5; ++i)
{
printf("s3[%d]= %d\n", i, s3[i]);
}
//strlen、sizeof
int ret;
ret = strlen(s1); // 返回字符数'\0'截止
printf("strlen(s1)= %d\n", ret);
ret = sizeof(s1); // 返回字符数含'\0'及数组范围内后面字符
printf("sizeof(s1)= %d\n", ret);
//字符串操作API
strcpy(s1, s3);
strncpy(s1, s3, 2); //字符串复制
strcat(s1, s3);
strncat(s1, s3, 2); //字符串拼接
puts(s1);
return 0;
}
5. 字符串保存
#include <stdio.h>
#include <string.h>
int main(void)
{
// 栈
char s2[20] = {'a', 'b', [15 ...18] = 'e','\0'}; //字符串应以'\0'结束
char str[] = "hello";
const char *p = "wrold!";
char str2[2][5] = {"my","name"};
char * pr[2] = {"lisi", "wangwu"};
printf("sizeof:str2= %d, pr= %d\n", sizeof(str2), sizeof(pr));
// 常量区
printf("%s\n", "ABC");
printf("%c\n", "ABC"[1]); // 字符串类型为匿名数组
printf("%p, %p, %p, %p, %p\n", &"ABC", &"ABC"[0], &"ABC"[1], &"ABC"[2], &"ABC"[3]);
return 0;
}
6. 数组与指针
#include <stdio.h>
//C允许多次声明函数原型,因为以下写法完全等价,所有不会报类型声明错误
void function(int a[5]);
void function(int a[ ]);
void function(int *a);
int main(int argc, char const *argv[])
{
//数组中的地址类型
int a[5] = { 1, 2, 3, 4, 5 };
int *p1 = a; //数组名视为数组首元素的地址,类型为元素的类型*
int *p2 = &a[0]; //元素类型*
int(*p3)[5] = &a; //数组类型*
int b[2][3] = { { 1, 2, 3 }, { 7, 8, 9 } };
int(*p4)[3] = b;
int(*p5)[3] = &b[0];
int(*p6)[2][3] = &b;
int *p7 = &b[0][0];
//数组取值
printf("a[2]: %d\n", a[2]);
printf("*(a+2): %d\n", *(a + 2));
printf("*(&a[0]+2): %d\n", *(&a[0] + 2));
//sizeof 指针和数组
int *p = a;
printf("p: %d\n", sizeof(p)); // 4 bytes
printf("a: %d\n", sizeof(a)); // 20 bytes
//数组传参
function(a);
return 0;
}
void function(int a[ ])
{
printf("function sizeof(a): %d\n", sizeof(a)); // 4 bytes 退化为指针
}
7.柔性数组
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node
{
int stlen;
char msg[0];//结构体定义变量后也不为msg[0]分配内存
};
int main(int argc, char const *argv[])
{
printf("sizeof(struct node)= %d\n", sizeof(struct node));
char buf[100] = { 0 };
fgets(buf, 100, stdin); //从键盘获得最多100个字符存到buf中(含空格回车)
int n = strlen(buf) + 1; //计算buf的内容字符数,+1给'\0'
struct node *p = malloc(sizeof(struct node) + n); //申请动态内存=结构体固定内存+从键盘获得内容大小
p->stlen = n;
strncpy(p->msg, buf, n); //拷贝n字节buf内容到msg
printf("sizeo of struct: %d\n", sizeof(struct node) + n);
printf("msg: %s", p->msg);
return 0;
}
8. 变长数组
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
fprintf(stdout,"printf enter n:");
scanf("%d", &n);
int a[n]; //不能初始化,程序运行才分配内存
//但可不初始化的赋值
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < n; i++)
{
printf("a[%d]= %d\n", i, a[i]);
}
return 0;
}