概述
- 关键字: static
- 运算符: & 、*(一元)
- 如何创建并初始化数组
- 指针(在已学过的基础上)、指针和数组的关系
- 编写处理数组的函数
- 二维数组
数组
定义与初始化
void main(){
char ch[] = "my name is chentian";
int arr[] = {23,45,11,10,5,90};
float arrF[] = {10.12,20.3,40.5};
}
/*day_mon1.c -- 打印每个月的天数*/
#include "stdio.h"
#define MONTHS 12
void main(){
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for(index = 0;index < MONTHS; index++){
printf("index=%d,days=%d\r\n",index + 1, days[index]);
}
}
使用const声明数组
这样程序只能从数组中索引值,不能把新值写入数组
const int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
初始化失败怎么办?以下是未初始化数组
/*no_day.c -- 为初始化数组*/
#include "stdio.h"
#define SIZE 4
void main(){
int no_data[SIZE]; /*未初始化数组*/
int i;
printf("%2s%14s\n","i","no_data[i]");
for(i=0;i<SIZE;i++){
printf("%2d%14d\n",i,no_data[i]);
}
}
初始化数组
/*somedata.c -- 部分初始化数组*/
#include "stdio.h"
#define SIZE 4
void main(){
int some_data[SIZE] = {1314,6666}; /*未初始化数组*/
int i;
printf("%2s%14s\n","i","some_data[i]");
for(i=0;i<SIZE;i++){
printf("%2d%14d\n",i,some_data[i]);
}
}
自动判断数组的长度
/*day_mon2.c -- 让编译器计算元素个数*/
#include "stdio.h"
void main(){
const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
int i;
for(i = 0;i < sizeof days/sizeof days[0];i++){
printf("i=%d,days=%d\n",i+1,days[i]);
}
}
- sizeof days: 字节加上数量的总长度
- sizeof days[0]: 单个字节的长度
指定初始化器(C99)
C99新增了新特性:
指定初始化器(designated initializer)
。利用该特性初始化指定的数组元素.列如初始化最后一个元素
/*designate.c -- 使用指定初始化器*/
#include "stdio.h"
#define SIZE 10
void main(){
int arr[SIZE] = {31,[9]=31}; //给数组的第一个和最后一个赋值
int i;
for(i=0;i<SIZE;i++){
printf("arr[%d] = %d\n",i,arr[i]);
}
}
给数组元素赋值
/*arrayFuZhi.c -- 给数组元素赋值*/
#include "stdio.h"
#define SIZE 10
void main(){
int days[SIZE];
int i;
for(i = 0; i < SIZE; i++){
days[i] = i * (SIZE+i);
printf("i=%d,days[%d]=%d\n",i+1,i,days[i]);
}
}
数组下标越界
/*bounds.c -- 数组下标越界*/
#include "stdio.h"
#define SIZE 10
void main(){
int days[SIZE] = {31,28,[9]=31};
int i;
for(i = 0; i < SIZE; i++){
printf("%d\n",days[i]);
}
printf("%d\n",days[11]);
printf("%d\n",days[-1]);
}
指定数组的大小
int days[SIZE];//字符常量
int days[10];//字面常量
多维数组
int days[3][10]={{/*days[0][0]*/},{/*days[0][1]*/},{/*days[0][2]*/},{/*days[0][3]*/},{/*days[0][4]*/},{/*days[0][5]*/},{/*days[0][6]*/},{/*days[0][7]*/},{/*days[0][8]*/},{/*days[0][9]*/}},{{/*days[1][0]*/},{/*days[1][1]*/},{/*days[1][2]*/},{/*days[1][3]*/},{/*days[1][4]*/},{/*days[1][5]*/},{/*days[1][6]*/},{/*days[1][7]*/},{/*days[1][8]*/},{/*days[1][9]*/}},{{/*days[2][0]*/},{/*days[2][1]*/},{/*days[2][2]*/},{/*days[2][3]*/},{/*days[2][4]*/},{/*days[2][5]*/},{/*days[2][6]*/},{/*days[2][7]*/},{/*days[2][8]*/},{/*days[2][9]*/}}
其他多维数组
三维数组:
int days[2][2][2]={{{},{}},{{},{}}},{{{},{}},{{},{}}}
指针和数组
/*pnt_add.c -- 指针地址*/
#include "stdio.h"
#define SIZE 4
void main(){
short datas[SIZE];
short* pti;
short index;
double bills[SIZE];
double* ptf;
pti = datas; //pti = datas; : pti = & datas[0];
ptf = bills;
for(index = 0; index < SIZE;index++){
printf("pti=%-10p,ptf=%10p\n",pti+index,ptf+index);
}
}
pti = datas; : pti = & datas[0];意味着 pti得到的是datas[0]的地址,又因为数组的有序性原因,所以是数组的内存地址是连在一起的,所以pti+index就是垮了一个数据类型的字节找到了下一个索引(datas[1])的内存地址
数组、函数、指针
指针运算
指针加减整数
#include "stdio.h"
int main(){
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof arr / sizeof arr[0];
int* p = arr;
int i;
for(i = 0; i < sz; i++){
printf("%d ",*p);
p++;//p = p + 1
}
return 0
}
#include "stdio.h"
int main(){
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof arr / sizeof arr[0];
int* p = arr;
int i;
for(i = 0; i < 5; i++){
printf("%d ",*p);
p += 2;//p = p + 2
}
return 0
}
#include "stdio.h"
int main(){
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof arr / sizeof arr[0];
int* p = &arr[9];
int i;
for(i = 0; i < 5; i++){
printf("%d ",*p);
p -= 2;//p = p - 2
}
return 0
}
#include "stdio.h"
int main(){
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof arr / sizeof arr[0];
int* p;
for(p = &arr[0];p < &arr[10];){
*p++ = 0;
}
return 0
}
指针减去指针
int my_strlen(char* s){
char *p = s;
while(*p != '\0){
p++;
}
return p - s;
}
int main(char* s){
int arr[10] = {1,2,3,4,5,6,7,8,9};
printf("%d\n",&arr[9] - &arr[0]);//指针减指针得到的是中间元素的个数
//printf("%d\n",&arr[0] - &arr[9]); //小地址减大地址的绝对值是中间元素的个数
return 0;
}
int main(char* s){
char ch[5] = {0};
int arr[10] = {1,2,3,4,5,6,7,8,9};
printf("%d\n",&arr[9] - &ch[0]);//err。有数值但是是乱的
return 0;
}
strlen-求字符串长度(模拟)
#include "stdio.h"
int my_strlen(char*);
int main(){
char arr[] = "bit";
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
int my_strlen(char* str){
//char* start; //其实就是str
char* start = str;
char* end = str;
while(*end != '\0'){
end++; //end到\0(结尾)时跳出循环,此时end指向的地址就是\0
}
return end -start;
}
#define N_VALUE 5
float valus[N_VALUE];
float* vp;
for(vp = &values[N_VALUE]; vp > &values[0];){
*--vp = 0;
}
#define N_VALUE 5
float valus[N_VALUE];
float* vp;
//因为C语言不保证它可行
for(vp = &values[N_VALUE-1]; vp >= &values[0];vp--){
*vp = 0;
}
标准规定
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但不允许与指向第一个元素之间的那个内存位置的指针进行比较。
#include "stdio.h"
int main(){
int arr[10] = {0};
printf("%p\n",arr);
printf("%p\n",&arr[0]);
//arr与arr[0]的地址相同,说明arr首地址(绝大部分)
return 0;
}
//例外-&数组名-数组名不是首元素的地址-数组名表示整个数组- &数组名取出的是整个数组的地址
//sizeof(arr) - sizeof(数组名)-数组名-数组名表示的是整个数组-sizeof计算的是整个数组的大小(单位:字节)
#include "stdio.h"
int main(){
int arr[10] = {0};
printf("%p\n",arr);
printf("%p\n",&arr[0]);
printf("%p\n",&arr);
return 0;
}
如果地址是一样的?可以尝试以下代码
#include "stdio.h"
int main(){
int arr[10] = {0};
printf("%p\n",arr);
printf("%p\n",arr + 1);
printf("%p\n",&arr[0]);
printf("%p\n",&arr[0] + 1);
printf("%p\n",&arr);
printf("%p\n",&arr + 1);
return 0;
}
#include "stdio.h"
int main(){
int arr[10] = {0};
int* p = arr;
int i;
/*for(i = 0; i<10;i++){
//内存地址相同
printf("%p === %p\n",p+i,&arr[i]);
}*/
for(i = 0;i < 10;i++){
//printf("%d ",arr[i]);
printf("%d",*(p + i));
}
return 0;
}
但是数组和指针不同
- 数组可以存放n个数据
- 指针存放的是一个数据的内存地址
- 通过指针可以访问数组
- 指针不止止是可以访问数组
二级指针
/*Secondary.c -- 二级指针*/
#include "stdio.h"
int main(){
int a = 10;
int* pa = &a;//pa是一级指针
return 0;
}
/*Secondary.c -- 二级指针*/
#include "stdio.h"
int main(){
int a = 10;
int* pa = &a;//pa是一级指针
int** ppa = &pa;//ppa就是二级指针
return 0;
}
/*Secondary.c -- 二级指针*/
#include "stdio.h"
int main(){
int a = 10;
int* pa = &a;//pa是一级指针
int** ppa = &pa;//ppa就是二级指针
int*** pppa = &ppa;//pppa就是三级指针,以此类推
return 0;
}
理解:
- a -地址-> 0x0012ff40(比方) -存的数值-> 10 -类型-> int
- pa -地址-> 0x0012ff48(比方) -存的数值-> 0x0012ff40 (pa有能力找到a,pa是指向a的,所以pa是指针变量) -类型-> int*
- paa -地址-> 0x0012ff4c(比方) -存的数值-> 0x0012ff48 (paa有能力找到pa,paa是指向pa的,所以paa是指针变量) -类型-> int**
清楚的写法
/*Secondary.c -- 二级指针*/
#include "stdio.h"
int main(){
int a = 10;
int* pa = &a;//pa是一级指针
int* * ppa = &pa;//ppa就是二级指针
int** *pppa = &ppa;//pppa就是三级指针以此类推
return 0;
}
指针数组
指针数组本身是数组
指针数组是存放指针的数组
#include "stdio.h"
int main(){
int a = 10;
int b = 20;
int c = 30;
int* pa = &a;
int* pb = &b;
int* pc = &c;
//如果有多个数组需要存放就要多个变量,那我们可不可以通过数组的形式存放呢?
return 0;
}
整型数组 - 存放整型
字符数组 - 存放字符
指针数组 - 存放指针
写法:
int arr[10];
int* arr2[3]; //指针数组
/*ArrayProinterOne.c -- 指针数组*/
#include "stdio.h"
int main(){
int a = 10;
int b = 20;
int c = 30;
int* arr2[3] = {&a,&b,&c};
int i;
for(i=0;i<3;i++){
printf("%d\n",*(arr2[i]));
}
return 0;
}
数组指针
数组指针本身是指针