字符数组
#include <stdio.h>
int main(int argc, char const *argv[])
{
char Array[6] = {'D','A','V','I','D','\0'};
printf("%c\n",Array[3]); // 'k'
for(int i = 0; i < 6; i++)
{
printf("%c",Array[i]);
}
printf("\n");
// 输出字符串用%s
printf("%s\n",&Array[0]);
printf("%s\n",Array);char Array1[6] = {"DAVID"};// ""表示字符串,字符串末尾有\0
printf("%s\n",Array1);// 最常用的方法
char Array2[6] = "DAVID";
printf("%s\n",Array2);return 0;
}
练习:定义一个整型数组,遍历数组中的每个元素,并把数组中的每个元素的地址都打印出来
int array[3] = {1,2,3};
printf("%p\n",array); // FF14
printf("%p\n",&array[0]); // FF14
printf("%p\n",&array[1]); // FF18
printf("%p\n",&array[2]); // FF1Cprintf("%d\n",*array);
printf("%d\n",*(array+1));
数组元素地址解引用
int a = 10;
printf("%d\n",a);printf("%p\n",&a);
// * 表示将地址里面的内容取出,我们把它称为解引用
printf("%d\n",*(&a));//--------------------------
char Array[5] = {'j','a','c','k'};
printf("%c\n",Array[0]);
printf("%c,%c\n",*(Array+0),*(&Array[0]));
printf("%c,%c\n",*(Array+1),*(&Array[1]));
printf("%c,%c\n",*(Array+2),*(&Array[2]));
printf("%c,%c\n",*(Array+3),*(&Array[3]));
字符串常
-
字符串常量在内存中的存储,实质是一个匿名数组
-
匿名数组,同样满足数组两种涵义的规定
printf("%s\n","hello");
printf("'h' addr:%p\n","hello");
printf("'e' addr:%p\n","hello" + 1); //地址+1
printf("'o' addr:%p value:%c\n","hello" + 4,*("hello" + 4)); //地址+1
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char array[5] = "jack";
char array1[5] = "rose";
printf("%c\n",array[1]);
// "Jack"是匿名数组
printf("%c\n","jack"[1]);
printf("array addr : %p\n",array);
printf("array1 addr : %p\n",array1);
printf("jack addr : %p\n","jack");
printf("array msg : %s\n",array);
printf("jack msg : %s\n","jack");printf("%c\n","rose"[0]);
printf("111:%c,%c\n",*("rose"+1),"rose"[1]);
printf("%ld\n",sizeof("rose"));
printf("%d\n",strlen("rose"));
char Array[1000] = {0};
// 计算实际空间的大小
printf("%ld\n",sizeof(Array));
// 计算数组里面的内容大小遇到'\0'结束
// 计算实际的数组内容大小
printf("%d\n",strlen(Array));
return 0;
}
多维数组(二维数组)
概念:若数组元素类型也是数组,则该数组称为多维数组,就是一维数组的集合
int a0[3];
int a1[3];
int a[2][3];//a[0]-->a0 a[1]-->a1
int ; a[3] // 数组
int [3]; a[2] // 数组
第一种解释:
定义一个二维数组。该数组是由2个一维数组组成,分别是a[0] a[1]
每个一维数组由3个元素组成,所以二维数组有6个元素
数据类型 二维数组的名字[有多少个一维数组][每个一维数组有多少个元素]
// 代码释义:
// 1, a[2] 是数组的定义,表示该数组拥有两个元素
// 2, int [3]是元素的类型,表示该数组元素是一个具有三个元素的整型数组
第二种解释:
该数组一共有2行,每行由3个元素组成(2行3列)
数据类型 二维数组名[行][列]
所谓的行:表示这个二维数组一共有多少个一维数组
所谓的列:表示这个二维数组每个一维数组有多少个元素
//1、定义
//int arr[3][4];
//2、定义的时候初始化
//1)分行给二维数组初始化
/* int arr[3][4] = { {10,20,30,33},
{40,50,60,66},
{70,80,90,99}}; */
//2)将所有的数据全部写在一个大括号里面,按照数组的排列顺序进行赋值
//int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
//int arr[3][4] = {{1,2,3,4},{5},6,7};//3)清空数组
//int arr[3][4] = {0};
//4)如果对全部元素进行赋值,则定义数组的时候可以省略第一维的长度
//int arr[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
//int arr[][] = {1,2,3,4,5,6,7,8,9,10,11,12}; 错误
//int arr[3][] = {1,2,3,4,5,6,7,8,9,10,11,12}; 错误
二维数组解引用
// 二维数组初始化字符串
char buf1[2][5] = {"jack","rose"};
printf("%s,%s\n",&buf1[0][0],buf[0]);
printf("%s,%s\n",&buf1[1][0],buf[1]);// 取二维数组中的某个字符
printf("%c,%c,%c,%c\n",buf1[0][1],*(&buf1[0][1]),*(buf1[0]+1),*(*(buf1+0)+1));
printf("%c,%c,%c,%c\n",buf1[1][2],*(&buf1[1][2]),*(buf1[1]+2),*(*(buf1+1)+2));
数组地址偏移
#include <stdio.h>
int main()
{
char Names[3][5] = {"jack","rose","ken"};
// printf("Names[0] %p,%p\n",Names[0],&Names[0][0]);
// printf("Names[1] %p,%p\n",Names[1],&Names[1][0]);
// printf("Names[2] %p,%p\n",Names[2],&Names[2][0]);
// Names[0]相当于&Names[0][0]
printf("Names[0]+1=%p,%p\n",Names[0]+1,&Names[0][1]);
printf("Names[0][0]:%c,%c\n",Names[0][0],*(Names[0]+0));
printf("Names[0][2]:%c,%c\n",Names[0][2],*(Names[0]+2));printf("&Names[0]+1=%p,%p\n",&Names[0]+1,&Names[1]);
printf("*(&Names[0]+1)=%c,%c\n",*(&Names[0]+1)[0],*(&Names[1])[0]);
printf("*(&Names[0]+1)=%c,%c,%c,%c\n",(*(&Names[0]+1))[1],(*(&Names[1]))[1],
*(*(&Names[0]+1)+1),*(*(Names+1)+1));
printf("%c,%c,%c,%c\n",Names[2][2],*(Names[2]+2),(*(Names+2))[2],*((*(Names+2)+2)));return 0;
}
指针基础
-
指针的概念:
-
一个专门用来存放内存地址的变量,指针也就是指针变量
-
-
地址。比如 &a 是一个地址,也是一个指针,&a 指向变量 a
-
专门用于存储地址的变量,又称指针变量。
-
指针基础
指针的概念:
一个专门用来存放内存地址的变量,指针也就是指针变量
地址。比如 &a 是一个地址,也是一个指针,&a 指向变量 a
专门用于存储地址的变量,又称指针变量。
野指针
概念:指向一块未知区域的指针,被称为野指针。野指针是危险的。
产生原因:
指针定义之后,未初始化
指针所指向的内存,被系统回收
指针越界
空指针
概念:空指针即保存了零地址的指针,亦即指向零地址的指针。
NULL地址其实就是 (void *)0,就是0。
指针运算
指针加法意味着地址向上移动若干个目标。
指针减法意味着地址向下移动若干个目标。
指针偏移:指针的加减称为指针的偏移,偏移的单位由指针的类型大小所决定所谓指针的类型大小指的是指针变量所指向的内存空间的数据类型。
大端模式:高位数据存放在内存的低地址端,低位数据存放在内存的高地址端。
小端模式:高位数据存放在内存的高地址端,低位数据存放在内存的低地址端。
函数的定义
函数头:函数对外的公共接口
函数名称:命名规则与变量一致,一般取与函数实际功能相符合的、顾名思义的名称。
参数列表:即黑箱的输入数据列表,一个函数可有一个或多个参数,也可以不需要参数。
返回类型:即黑箱的输入数据类型,一个函数可不返回数据,但最多只能返回一个数据
函数体:函数功能的内部实现
语法汇总:
当函数的参数列表为void时,表示该函数不需要任何参数。
当函数的返回类型为void时,表示该函数不返回任何数据。
关键字return表示退出函数。若函数头中规定有返回数据类型,则 return 需带一个类型与之匹配的数据;②若函数头中规定返回类型为 void,则 return 不需携带参数。
总结:
- 函数名前面为返回值的类型,哪怕此函数没有返回值,也要写上void
- 函数的返回类型要顶格
- 函数返回类型与函数名空一格
- 函数参数要写(),哪怕里面没有任何内容,如果没有内容最好这样写void func(void)
- 函数调用者调用子函数的时候,可以不接收返回值。
- 注意:
- 大括号表示函数的工作范围,如果离开此范围,数据就不属于此函数管辖
- 函数不能在main(){}里面实现,虽然不会报错,如果不调用,这个子函数是不会被执行的
- 所有函数的实现都在主函数外面实现。
实参与形参
概念:
- 函数调用中的参数,被称为实参,即arguments
- 函数定义中的参数,被称为形参,即parameters
实参与形参的关系:
实参与形参的类型和参数个数必须一一对应。
形参的值由实参初始化。
形参与实参位于不同的内存区域,彼此独立。
gcc 编译器编译原理
1.将c文件进行预编译,作用是将头文件里面的内容进行展开,就是将头文件的内容拷贝到main函数上面
gcc main.c -o main.i -E
2.生成汇编程序,作用是将c文件编译成更加底层的编程语言汇编程序
gcc main.i -o main.s -S
3.将汇编程序生成未链接的可执行程序
gcc main.s -o main.o -c
4.将未连接的可执行程序生成已链接的可执行程序
gcc main.o -o main.exe
函数多文件封装:
将自行的公共接口进行独立放到单独的c文件,编译存储,如果想直接使用,主函数直接调用即可,但是编译的时候需要添加此文件一起编译。