嵌入式学习day01-day08

目录

Linux命令

快捷键

新建

查看

文件类型:7种 bcd-lsp

文件权限

路径cd

复制cp

移动mv

删除rm

打开终端

关闭终端

vi编辑器

简单编程步骤:

命令行:

插入模式 i o a I O A

底行模式:

vscode编辑器

gcc编译器

C基础

计算机数据类型

进制转换

非数值型数据

词法符号

关键字:32

虚拟内存空间:

标识符

运算符

算术运算符

运算符

1.1逻辑运算符

1.2位运算符

负数运算

1.3关系预算符

1.4 三目运算符 (条件运算符)

1.5 赋值运算符

 优先级

分隔符

变量

常量

数值型常量

浮点型常量

字符常量

字符串常量

标识常量

 输入输出

按字符输入输出

按格式

输入输出

 垃圾字符回收

分支语句

if

switch

循环语句

for

while

 while

do...while

循环控制语句

数组

特点:

数组名

数组大小

初始化

清零函数

bzero

memset

字符数组

字符数组输入输出

[1] 计算字符串实际元素个数

strlen

sizeof和strlen的区别:

冒泡排序

 选择排序

二维数组

数组名

初始化

内存分配

遍历数组

 指针

定义指针

 操作符

 初始化

运算符

关系运算 

指针大小

指针修饰

const     

修饰普通变量

修饰指针 

const  *  p

*  const  p

const  *  const  p

void

大小端

二级指针

 指针和数组

指针和一维数组

直接访问

间接访问

运算:

指针和二维数组

数组指针

指针数组

命令行参数


Linux命令

linux中一切皆文件

两大特殊文件:

根目录:/

家目录: ~

快捷键

放大终端:Ctrl shift +

缩小终端:Ctrl -

清屏: Ctrl L

用户名:     whoami

主机名:     hostname

:$中间(~):当前路径  

默认在家目录  pwd

pwd:查看当前路径

新建

文件夹: mkdir 文件夹名字

文件: touch 文件名.后缀

多层嵌套:文件夹

mkdir -p 文件夹名字/名字/名字    mkdir -p a/b/c

同一路径下:

文件夹:不能创建同名文件夹,会报错

文件:更新时间戳

查看

ls      查看当前路径下所有内容

ls -a  查看当前路径下所有内容,包括隐藏内容

ls -l    查看当前路径下所有内容de详细信息

文件类型:7种 bcd-lsp

b:块设备文件 /dev

c:字符设备文件 /dev/input

d:目录文件 文件夹

-:普通文件 .c .h .txt

l:软链接文件 <linuxC高级>

s:套接字文件 <网络编程>

p:管道文件 <IO>

文件权限

rwx: r:读 w:写 x:执行

rwx rwx rwx

自己 组内 其他

r:4 w:2 x:1 -:0

路径cd

下一级:cd 文件夹名字

上一级:cd ..

当前: cd .

上一次:cd -

根目录:cd /

家目录:cd ~ 或 cd 或 cd /home/hq

绝对路径:从根目录开始 /home/hq/24081/1

相对路径:以当前位置为参照物

复制cp

文件 cp        要复制的文件名 目标地址(文件夹)

文件夹 cp -r 要复制的文件夹名 目标地址(文件夹)

另存为 cp     要复制的文件名 目标地址/新名字

移动mv

mv  要移动的文件/文件夹 目标地址

重命名: mv 要移动的文件/文件夹 目标地址/新名字

删除rm

删除后,文件不可恢复

文件: rm 文件名

文件夹: rm -r 文件夹

-f 强制

打开终端

1.  直接点击

2.  Ctrl shift n 当前文件夹

3.  Ctrl alt t 家目录

关闭终端

1.  直接点击

2.  Ctrl d (快捷方式)

3.  exit (命令)

vi编辑器

打开:vi 1.c   初始默认在命令行模式

vi编辑器3种模式:

命令行模式:复制、粘贴、撤销、光标移动

插入模式:编写代码

底行模式:保存、退出、复制、分屏、查找、替换

简单编程步骤

1.  创建文件 touch file.c

2.  打开vi编辑器 vi file.c 默认在命令行模式,需要切换到插入模式

3.  编写代码

4.  进入底行模式 w保存

5.  运行程序: gcc file1.c 编译c文件,生成可执行文件

6.  运行: ./a.out

命令行:

复制 yy nyy(光标选中y n:行数 复制几行)

删除(剪切) dd ndd

粘贴 p

撤销 u

反撤 ctrl r

光标移动首行 gg

光标移动最后一行首行 G

光标移动行首 0

光标移动行尾 $

插入模式 i o a I O A

底行模式:

指定行复制 5,10y 复制5-10行

指定行删除 5,10d

保存 w

退出 q

保存并退出 wq

强制 !

vsp 分屏本文件

vsp 文件名 分屏打开另外一个文件

查找 /找的东西

替换 s/a1/a2 光标所在行的第一个a1替换成a2

s/a1/a2/g 光标所在行的所有a1替换成a2

%s/a1/a2/g 改变全文

1,$s/a1/a2/g 改变全文

设置行号 set nu

取消 set nonu

取消高亮 nohl

vscode编辑器

建议打开整个文件夹

code 文件夹名字

gcc编译器

高级语言(C语言)---机器识别不了,借助编译器

简写

gcc file2.c 生成可执行文件名a.out

./a.out

另一种简写

gcc file2.c -o file2(可执行文件名,可自己命名)

./file2

完整编译步骤

预处理、编译、汇编、链接

1.  预处理

展开头文件、删除注释,替换宏定义

gcc -E hello.c -o hello.i

2.  编译

检查语法错误,有错报错,没错会转变成汇编语言,生成汇编文件

gcc -S hello.i -o hello.s

3.  汇编

把汇编文件生成不可执行的二进制文件

gcc -c hello.s -o hello.o

4.  链接

链接库文件,最终生成机器能够识别的二进制的可执行文件

gcc hello.o -o hello(可执行文件,可以自己取名)

C基础

计算机存储单位:位  0 1

1字节byte=8位bit

换算:

1B=8bit

1KB=1024B 

1MB=1024KB

1GB=1024MB

1TB=1024GB

计算机数据类型

二进制      0 1            10 (1/0组合排列)

八进制      0-7            010(在最前方加0)

十进制      0-9      

十六进制   0-9  a-f     0X10 (在最前面加0x)

abcdef
101112131415

进制转换

十进制转二进制:

    短除法:除以二取余,余数自下而上排列     12:1100

拆分法:8421

二进制转八进制:

    三个二进制数转换为一个八进制数  

二进制转十六进制:

    四个二进制数转换为一个十六进制数

数值型数据

字符型 用 ' ' 包裹

man man :查看man手册

man手册:用来查看一些命令、函数的用法

     1 可执行程序或 shell 命令

     2 系统调用(内核提供的函数)

     3 库调用(程序库中的函数)

man ascii 查看ASCII码表

'\0' 0 字符串结束标志

'\n' 10 换行

空格 32

'0'   48 字符0

'A'   65

'a'   97

字符转数字 '2'-48==2

'A' +32 = 'a'

'A' +' ' = 'a'

词法符号

关键字32

存储类型:auto   static   extern   register

数据类型:int    short   long   c har   float   double   signed   unsigned

分支:if  else   switch   case   default

循环:for   do   while    go to    break   continue

构造数据类型:struct   enum   union

其他:void   const   sizeof   typedef   return  volatile

虚拟内存空间:

32位:4G

64位:2^64 2^48

栈区:系统自动开辟、回收 (函数体内部定义的变量)

堆区:程序员手动开辟(malloc)、回收(free)

全局区、静态区:

常量区:char *p="hello"

标识符

定义变量名、数组名、函数名时,遵循标识符命名规则:

1.  由字母、数字、下划线(_)组成

2.  开头不能是数字

3.  不能和关键字重名

4.  见名知意

运算符

算术运算符 逻辑运算符 关系运算符 位运算符 三目运算符 赋值运算符

算术运算符

+ - * / % ++ --

/:如果是整数相除,结果向下取整

int a=5/2;

printf("%d\n",a); //2 %d整型 int

float a=5/2;

printf("%f\n",a); //2.000000 %f浮点型 float 默认打印小数点后六位

float a=5.0/2;

printf("%f\n",a); //2.500000

printf("%.1f\n",a); //2.5 .1保留一位小数

float a=(float)5/2; // int 5短暂的强制转换成float float 5只在当前这一行

printf("%.1f\n",a); //2.5

%取余

只能用于整数运算

5%2==1

++

a++ <==> a=a+1

独立成句:

int a=5;

1)  ++a;

printf("%d\n",a); //6

2)  a++;

printf("%d\n",a); //6

赋值运算:

int a=5;

1)int b= a++; // = +

printf("%d %d\n",a,b);//6 5

2)int b= ++a; // + =

printf("%d %d\n",a,b);//6 6

打印语句

int a=5;

1)printf("%d\n",a++); //5

printf("%d\n",a); //6

2)printf("%d\n",++a); //6

printf("%d\n",a); //6

运算符

1.1逻辑运算符

与  :&&         全真则真,有假则假;

或  :||            一真则真,全假则假;

非  :!             非真即假,非假即真;

判断是否成立,输出结果为0(否)或1(是);

终端验证条件是否成立:

printf("%d\n",118>99); //  条件成立输出     1

printf("%d\n",18>99);   //  条件不成立输出 0

printf("%d\n",118>99 && 5>9 ); //  输出 0

printf("%d\n",118>99 || 5>9 );    //  输出 1

printf("%d\n",!(118>99) || 5>9 ); //  输出 0

 0为假,非零为真

printf("%d\n",5&&6);              //    1

printf("%d\n",(10/2)&&6);       //    1

printf("%d\n",(10/2==5)&&6); //    1

 截断法则   

             逻辑与运算中,前边表达式结果为假,后边表达式不再执行,返回假;

             逻辑或运算中,前边表达式结果为真,后边表达式不再执行,返回真;

例:

       解析:

         (m=a>b)为假,后面表达式不再执行,则n=2;

1.2位运算符

位与:&    位或: |    异或: ^      取反:~     左移: <<     右移:  >>

&  位与:全1则1,有0则0

|    位或:有1则1,全0则0

 异或:相同为0,不同为1

int a=6,b=10;                          将6和10换算为二进制数:

int c=a&b                                  //6 : 0110     

                                                         ↓↓↓↓       按位比较

printf("%d\n",c);//输出2             //10:1010       全1则1,有0则零

                                                         ↓↓↓↓ 

                                                 //&:  0010换算为十进制数→→2

负数运算

整数以补码的二进制进行存储、计算

原码

反码

补码

正数

相同

相同

相同

负数

相同

原码除符号位之外,其他按位取反

反码+1

int a=-6,b=10;

int c=a&b;

printf("%d\n",c); //10

int 4字节 = 32位

-6原码: 最左边表示符号位 0正数 1负数

     1000 ... 0110

-6反码:

      1111 ... 1001

-6补码:

      1111 ... 1010

10补码:

      0000 ... 1010

-6补码 & 10补码:

      1111 ... 1010

      0000 ... 1010

      0000 ... 1010 补码     10

~ 取反

1-->0 0-->1

int a=-6;

int c=~a;

printf("%d\n",c); //5

-6原码:                           最左边表示符号位 0正数 1负数

      1000 ... 0110

-6反码:

      1111 ... 1001

-6补码:

      1111 ... 1010

~  取反:

      0000 ... 0101 === 5

<<左移

左移几位右边几个0

int a=6<<2;          //6转成二进制→110,再左移两位→11000

printf("%d\n",a);   //11000===24

右移两位也可这么计算:

     6*2^2=24

    -6*2^2=-24

X右移n位,即:结果=X*2^n

>>右移

右移几位,右边丢弃几位

6>>2              //6转成二进制→110,再右移→001

6/2^2=1

1.3关系预算符

大于:>       大于等于:   >=      小于:<         小于等于:<=         

等于:==       不等于:!=  

1.4 三目运算符 (条件运算符)

表达式1 ? 表达式2 : 表达式3;

int a=3,b=5;

int max=a>b?a:b;            判断表达式1是否成立,成立执行表达式2,不成立执行表达式3;

printf("%d\n",max);    //5

1.5 赋值运算符

赋值:=       加等:+=        减等:-=        乘等:*=    

除等:/=      取余等:%= 

a-=5 <===> a=a-5;

扩展逗号运算符(顺序求值运算符)

(表达式1,表达式2,表达式3,...,表达式n)  

运算结果是最后一个表达式的结果

int a=3,b=5;                       运算结果是最后一个表达式结果:

a=(a*3,a+2,a-1);                                                     a = a-1 = 2

printf("%d\n",a); //2

 优先级

单算移关与    异或逻条赋

单目运算符:++   --   ~    !

算术运算符: /   *   %   +   -

移位运算符: <<   >>

关系运算符:>    >=   <   <=   ==    !=

位与运算符:&

异或运算符:^

位或运算符:|

逻辑运算符:&&   ||

条件运算符:?   :

赋值运算符: = ......

分隔符

空格 tab 换行

变量

程序运行过程中会发生变化的量

格式

存储类型 数据类型 变量名

 (auto)          int             a;

存储类型:    决定变量存储的位置

数据类型 :决定开辟空间大小

变量名 :   遵循标识符命名规则

名称

大小(字节)

取值范围(了解)

int

整型

4

char

字符型

1

-2^7~2^7-1

short

短整型

2

long

长整型

32位:4;64位:8

float

单精度浮点型

4

有效位数:6-7位

double

双精度浮点型

8

15-16位

局部变量和全局变量的区别

局部变量

全局变量

定义位置

函数体内部

函数体外边

初值

未初始化,值为随机值

未初始化,值为0

作用域

当前函数体内部

整个程序

生命周期

同当前函数共存亡

同整个函数体共存亡

存储位置

栈区

全局区

32:   2^32字节==4G

64:   2^64  2^484

栈区:     系统自动开辟、回收 (函数体内部定义的变量)

堆区:     程序员手动开辟(malloc)、回收(free)

全局区、 静态区: 全局变量、static修饰的变量

常量区: char *p="hello"

常量

数值型常量

八进制  十进制  十六进制

浮点型常量

float   double

字符常量

程序中用‘ ’包裹

char a='q';

char b='\n';      \n换行

char c='n';       n字符

转义字符:\

char a='A';

printf("%c\n",a);    //A

char b='123';

printf("%c\n",b);    //'3'

char c=0101;

printf("%c\n",c);    //A

char d='\101';

printf("%c\n",d);    //A

char e='\x41';

printf("%c\n",e);    //A

字符串常量

结束标志:用" "包裹 '\0'字符串

例: "hello" 5个字符+'\0'字符串结束标志 == 6个字符

标识常量

宏定义

格式:#define       宏名      常量值 或 表达式 或 函数

宏名:一般用大写,目的跟变量区分开

特点:先进行单纯的替换,替换完之后再计算

#define N 2                                //  N=2

#define M N+3                          //   M=N+3=2+3

#define NUM N+M/2+1            //    NUM=N+M/2+1

void main()                                                       ↓

{                                                              = 2+2+3/2+1

     int a = NUM;

     printf("%d\n",a); //

}

宏定义实现求最大值

#include<stdio.h>

#define MAX a>b?a:b                          //  定义MAX 为  a>b?a:b

int main()

{

     int a=6,b=9;

     printf("%d\n",MAX);

     return 0;

}

 输入输出

按字符输入输出

       getchar   :   输入

语法格式:int getchar(void);

功能:终端输入一个字符

参数:无

返回值:输入字符的ASCII码值

int a = getchar();
printf("%d\n",a);

       putchar  : 输出

语法格式:int putchar(int c);

功能:终端输出一个字符

参数:字符的ASCII码值

返回值:字符的ASCII码值

按格式

int a=getchar();
putchar(a);
putchar('\n');  // 或 putchar(10); \n 的ascii码为10

输入输出

       scanf :   输入

语法格式:int scanf(const char *format, ...);

功能:按格式向终端输入

参数:多个

返回值:成功输入的元素个数

int a;
scanf ("%d",&a);
printf ("%d\n",a);

       printf : 输出

语法格式: int printf(const char *format, ...);

功能:按格式终端输出

格式:

%d                int

%c                char

%f                 float            %.nf    保留n位小数

%lf                double

%s                字符串

%p                指针

%o   %#o      八进制

%x    %#x     十六进制

int a=1;
char b='B';
float c=2.000;
printf("%d %c %f\n",a,b,c);  // 输出的格式要跟元素格式相对应

//输出结果为:1 B 2.000000

参数:多个参数        

返回值:输出元素的个数

int a=011;              // 定义a为八进制数11,0开头所以为八进制数
printf("%o\n",a);		// 11
printf("%#o\n",a);		// 011

位宽

 printf("%3d\n",a)    //  可以改变d前的数字,改变输出的位宽

int a = 6;
    b = 66;
    c = 666;
    printf("%3d\n",a);  //如果d前数字小于输出数据的位数,则无法改变位宽
    printf("%3d\n",b);
    printf("%3d\n",c);
输出结果为:
  6
 66
666

 垃圾字符回收

1.通过一个空格回收一个或多个空格、tab

2.%*c    *抑制符   回收任意一个字符

3.getchar

分支语句

if

基本格式

if(表达式)
{
	语句块1;
}else
{
	语句块2;
}
  //运行顺序:先判断括号内表达式是否成立 成立则执行语句块1 反之执行2

int age=20;
    if(age>18)
    {
        printf("work\n");
    }else
    {
        printf("study\n");
    }                
  //20>18,执行第一语句块printf("work\n"); 输出work

 分层结构

if(表达式1)
{
	语句块1;
}else if(表达式2)    //表达式1成立,执行语句块1,反之执行第二个if语句;
{
	语句块2;
}else
{
	语句块n;
}
===============================
100-90	A
89-80	B
79-70	C
<70		补考
int s=0;
    scanf("%d",&s);
    if(s>=90 && s<=100)           
    {
        printf("A\n");
    }else if(s>=80 && s<=89)        
    {
        printf("B\n");
    }else if(s>=70 && s<=79)
    {
        printf("C\n");
    }else
    {
        printf("补考\n");
    }

 嵌套结构

if(表达式1)
{
	if(){};   //表达式1成立,执行if(){},反之执行else后语句块1
}else
{
	语句块1;
}
======================
if(s>=0 && s<=100)
{
	if(){};
}else
{
	printf("error\n");
}

注意

else前边必须有if; if后边可以没有else

当分支语句中,语句块只有一行时可以省略{ }.

switch

switch (表达式)
    {
    case 常量值1:
        /* code */        //表达式结果分别与每个常量值比较,相等输出对应常量值后的程序
        break;
    case 常量值2:
        /* code */
        break;
    default:
		/* code */
        break;
    }
==========================
case后的常量值只能是数字或字符

循环语句

for

for(表达式1;表达式2;表达式3)
{
	语句块;
}
表达式1:循环变量赋初值
表达式2:终止条件
表达式3:增值或减值
================================
for (int i = 0; i < 5; i++)
    {
        printf("%d\n",i);
    }

 双层for

for(int i=1;i<6;i++)
    {
        for(int j=1;j<=4;j++)
        {
            printf("i:%d j:%d\n",i,j);
        }
    }
=========================================
for(int i=1;i<10;i++)
    {
        for(int j=1;j<=i;j++)
        {
            // printf("%d*%d=%2d ",i,j,i*j);
            printf("%d*%d=%d\t",i,j,i*j);
        }
        putchar(10);
    }

while

int  i=1;
while(i<5)
{
	printf("%d\n",i);  // 1<5表达式成立,执行内部程序
    i++;
}

 while

int  i=1;
while(i<5)                  //当i<5时,执行{}内语句块,直到不满足i<5;
{
	printf("%d\n",i);
    i++;
}
============================
int i=2,sum=0;      
    while(i<=6)           
    { 
        if(i%2==0)       
        {
            sum+=i;       
        }
        i++;
    }
    printf("%d\n",sum);

while (1)   死循环; 

do...while

do...while
int i=12;
     do
    {
        printf("%d ",i);
        i++;
    } while (i<=6); 

//do while :先执行{}内语句块,再判断while后表达式;

//while ;   先判断while后表达式,再执行{}内语句块;

    while(i<=6)
    {
        printf("%d ",i);
        i++;
    }

//     单行注释  Ctrl /
/**/  多行注释  选中一片代码  ctrl  shift  a  不支持嵌套多行注释

while 先判断,后执行

do...while 先执行,后判断

循环控制语句

break 结束整个循环

continue 结束本次循环,继续下一次循环

return main函数中,结束整个程序

for (int i = 1; i < 7; i++)
    {
        if (i == 3)
        {
            break;      //结束整个循环;
            continue;   //跳过本次循环,进入下次循环;
            return 0;   //结束整个程序;
        }
        printf("i:%d ", i);
    }
printf("qqqqq\n");

数组

由一个或多个相同类型数据组成的集合

特点:

数据类型相同

内存连续

格式:

存储类型 数据类型 数组名[元素个数]

int a[5];

只有在定义数组时,[ ] 里表示元素个数,其他情况下,[ ] 里表示索引

例:

int a[5]={2,3,4,5,6};

printf("%d %d %d\n",a[0],a[2],a[4]); //2 4 6

访问元素:数组名[索引] //索引从0开始

数据类型保持一致

int a[5]={2,3,4,5,6};

char b[5]={'q','w','e'};

数组名

数组名也是数组首地址,是一个地址常量,不能被修改

int a[5]={2,3,4,5,6};
printf("%d %d %d\n",a[0],a[2],a[4]);
printf("%p\n",a);          //数组名字,就是数组的首地址;
printf("%p\n",&a[0]);

数组大小

int a[5]={2,3,4,5,6}; //20
int a2[5]={2,3}; //20
int a3[5]={2}; //20          //int数据类型,大小为4字节,元素个数×数据类型大小
int b[]={2,3,4,5,6}; //20
int b2[]={2,3}; //8 
int b3[]={2}; //4
printf("%ld\n",sizeof(a));

元素个数*数据类型大小 5*4=20

初始化

● 完全初始化

int a[5]={2,3,4,5,6};

● 部分初始化

int a[5]={2,3};

未初始化部分,值默认为0

int a[5]={}; //0 0 0 0 0

int a[5]={0}; //0 0 0 0 0

● 未初始化

int a[5];

值为随机值

可单独赋值a[0]=2;

int a[5]={};
    for(int i=0;i<5;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=0;i<5;i++)
    {
        printf("%d\n",a[i]);
    }
int a[5]={9,8,7,6,5};
    for(int i=0;i<5;i++)
    {
        printf("%p\n",&a[i]);  //循环打印a[5]每个元素
    }   // 输出: 9 8 7 6 5 
        

清零函数

bzero

#include <strings.h>

void bzero(void *s, size_t n);

功能:数组清零

参数:    s:数组首地址       n:字节大小     size_t==int

返回值:无

int a[5]={};
for(int i=0;i<5;i++)
scanf("%d",&a[i]);
for(int i=0;i<5;i++)
printf("%d\n",a[i]);

bzero(a,sizeof(a));
for(int i=0;i<5;i++)
printf("%d\n",a[i]);

memset

#include <string.h>

void *memset(void *s, int c, size_t n);

功能:数组清零

参数:   s:数组首地址      c:要设置的值     n:字节大小

返回值:数组首地址

int a[5]={};
for(int i=0;i<5;i++)
scanf("%d",&a[i]);      //循环输入;
for(int i=0;i<5;i++)
printf("%d\n",a[i]);    //循环打印,遍历a[5]内容;


memset(a,0,sizeof(a));  //清零
for(int i=0;i<5;i++)
printf("%d\n",a[i]);

按字节赋值 int 4字节 1字节=8位 00000001 00000001 00000001 00000001

字符数组

存放字符串

char a[]={'n','i','c','e'}; //4    4个单个字符,4×1=4;
char b[5]={"nice"};         //5    定义数组元素为5个,5×1=5;    
char c[33]="nice";          //33   定义数组元素为33个,33×1=33;
char d[]="nice";            //5    字符串最后有'\0'结束标志,也算作一个字符 5×1=5;

字符数组输入输出

1.  for

for(int i=0;i<5;i++)
scanf("%c",&ch[i]);    //循环向ch[5]输入字符;   
for(int i=0;i<5;i++)  
printf("%c",ch[i]);    //循环打印,遍历ch[5]的内容;

2.  %s

char ch[33]={0};
scanf("%s",ch);
printf("%s\n",ch);
 //scanf 默认遇到空格或回车赋值结束,如果想保留空格,可以:
scanf("%[^\n]",ch);

3.  gets puts

[1] 计算字符串实际元素个数

char a[33]="hello world";

int i;

for(i=0;a[i]!='\0';i++);

printf("%d\n",i);//11

strlen

#include <string.h>

size_t strlen(const char *s);

功能:计算字符串实际元素个数 不包括'\0'

参数:字符数组首地址

返回值:字符串实际元素个数

int num=strlen(a);

printf("%d\n",num);//5

或

printf("%d\n",strlen(a));//5

sizeof和strlen的区别:

1.  sizeof是关键字,strlen是函数

2.  sizeof计算元素实际开辟的空间大小,strlen计算字符串实际元素个数;sizeof计算包括'\0',strlen不包括'\0'

3.  char a[ ]="hello"; sizeof(a)==6 strlen(a)==5

判断:

char s[10]="hello";

以下几种赋值方式:

1)  s[10]="hello";

//只有在定义数组时,[ ]里表示元素个数,其他情况下,[ ]里表示索引

2)  s="hello";

//数组名也是数组首地址,是一个地址常量,不能被修改

3)  strcpy(s,"world");

冒泡排序

//从小到大排  确保右边是大的值
int a[5]={6,5,4,3,2},temp;
    for(int i=0;i<5-1;i++)		//轮数 5个数比较4轮
    {
        for(int j=0;j<5-1-i;j++)	//每一轮比较的次数
        {
            if(a[j]>a[j+1])	//确定了最大或最小值之后,这个值被固定到最右边,之后不参与比较,所以随着循环的执行,参与比较的元素越来越少,它的索引越来越低
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
    }
    for(int i=0;i<5;i++)
        printf("%d ",a[i]);

 选择排序

6 5 4 3 2

int a[5]={6,5,4,3,2},m,temp;
    for(int i=0;i<5-1;i++)		//轮数
    {
        m=i;				//m:最小元素下标 ,默认是参与比较的元素中最左边位置
        for(int j=i+1;j<5;j++)	//获取剩下的所有元素
        {
            if(a[m]>a[j])		
            {
                m=j;		//在循环内部,暂存最小元素下标
            }
        }					//一轮循环结束,交换位置
        //交换	
        if(m!=i)				//当最小元素下标==要交换位置的下标,不需要交换
        {
            temp=a[m];
            a[m]=a[i];
            a[i]=temp;
        }
    }

    for(int i=0;i<5;i++)
        printf("%d ",a[i]);

二维数组

格式:

数据类型 数组名[行数][列数];

int a[2][3]={2,3,4,5,6,7};

访问: 数组名[行下标][列下标] 下标从0开始

a[0][0]

a[0][1]

a[0][2]

a[1][0]

a[1][1]

a[1][2]

int a[2][3]={2,3,4,5};

printf("%d %d\n",a[0][0],a[1][0]);

定义二维数组时,可以省略行数,不能省略列数

int a[2][ ]={2,3,4,5,6,7}; //错误 无法确定具体两行几列

int a[ ][3]={2,3,4,5,6,7};

D

数组名

是第一行的首地址,是个行地址

a: 第一行首地址

a+1:第二行首地址


int a[2][3]={2,3,4,5,6,7};

printf("%p %p\n",a,&a[0][0]);

printf("%p %p\n",a+1,&a[1][0]);

数组元素个数:行数*列数

数组大小:

行数*列数*数据类型大小

sizeof(数组名)

printf("%d\n",sizeof(a));

初始化

● 完全初始化

int a[2][3]={2,3,4,5,6,7};

int arr[2][3]={{2,3,4},{5,6,7}}; //按行赋值

● 部分初始化

未初始化部分,值为0

int a[2][3]={2,3}; // 2 3 0 0 0 0

int arr[2][3]={{2},{5,6,7}}; // 2 0 0 5 6 7

● 未初始化 值为随机值 需要单独赋值

int a[2][3];

内存分配

int a[2][3]={2,3,4,5,6,7};

a[0]:第一行第一列的地址

a[0]+1:第一行第二列的地址

地址

元素

a[0]

&a[0][0]

a

2

a[0][0]

a[0]+1

&a[0][1]

3

a[0][1]

a[0]+2

&a[0][2]

4

a[0][2]

a[1]

&a[1][0]

a+1

5

a[1][0]

a[1]+1

&a[1][1]

6

a[1][1]

a[1]+2

&a[1][2]

7

a[1][2]

int a[2][3]={2,3,4,5,6,7};
    printf("%p %p\n",a,&a[0][0]);
    printf("%p %p\n",a+1,&a[1][0]);
    printf("%d\n",sizeof(a));
    printf("%p\n",a[0]);
    printf("%p\n",a[0]+1);

遍历数组

int a[2][3]={};
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
            scanf("%d",&a[i][j]);
    }
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
            printf("%d\n",a[i][j]);
    }

 指针

一级指针存放普通变量的地址

格式:

存储类型    数据类型      * 指针变量名

                         int            *p;

定义指针

只有在定义指针时,* 表示定义指针的标志,其他情况下 * 表示取内容 

例:

int a=10;

int *p=&a;   // p 内储存变量 a 的地址

定义指针时,一定要对它初始化,否则就会产生野指针

1)int *p;            //  p为野指针,没有初始化,是个随机的地址;

2)int *p=NULL; // 指针初始化,可以赋值为NULL(空地址);后边可以再对p重新赋值

      int b=9;

      p=&b;

 操作符

*  :取内容符  取指针指向的地址内的内容

& :取地址符  取变量的地址

int a=10;

int *p=&a;

printf("%d\n",*p);   //输出10

=====================

地址:   &a   ==   p

内容:     a   ==   *p

 初始化

1.存放普通变量的地址 

1.int *p=&a;         定义的同时赋值;

2.int *p=NULL; 

         p=&a;         先定义p为空指针,再赋值;  

2.存放数组的首地址

int arr[5]={5,6,7,8,9};
    int *q=arr;             // q内存的是数组首地址
===============================
char s[33]="hello";	        //s:数组首地址
    char *p=s;		        // 数组首地址赋值
    printf("%p %p\n",s,p);  // s,p都是数组首地址
    printf("%s\n",p);	 	//"hello",p内存的数组首地址,打印字符串
    printf("%c\n",*p);		//'h',p内存的数组首地址,打印第一个字符

3.存放另一个指针变量的地址

int a=6;

int *p=&a;

int *q=p; //int *q=&a;

修改其中任意一个,另外几个的值会同步修改

运算符

算数运算

p++:向高地址方向移动一个数据单位(int:4 char:1);指针的指向发生改变

char c[6]={"hello"};
    char *p=c;
    p++;            //p++后,向高地址方向移动1个数据单位(char);
======================
int a[5]={5,6,7,8,9};
    int *q=a;
    q++;            //++后,向高地址方向移动1个数据单位(int);

p+n:向高地址方向(暂时)移动n个数据单位(int:4 char:1);指针的指向不改变

char c[6]={"hello"};
    char *p=c;
    p++;     //p++后,向高地址方向移动 n 个数据单位(char);即为数组下一元素的地址;
======================
int a[5]={5,6,7,8,9};
    int *q=a;
    q++;     //++后,向高地址方向移动 n 个数据单位(int);即为数组下一元素的地址

同一个数组中:两个地址的差值==相差元素个数

int a[5]={5,6,7,8,9};

int *p=a;

int *q=&a[2];

printf("%d\n",q-p); //2

关系运算 

<    >    ==

比较的是地址的高低(同一个数组中比较)

指针大小

    int a[5]={5,6,7,8,9};
    int *p=a;
    printf("%ld\n",sizeof(p));  //8
    
    int b=6;
    int *p1=&b;
    printf("%ld\n",sizeof(p1)); //8

    char c='q';
    char *p2=&c;
    printf("%ld\n",sizeof(p2)); //8

    float d=2.3;
    float *p3=&d;
    printf("%ld\n",sizeof(p3)); //8

64位操作系统:指针大小为8字节

32位操作系统:指针大小为4字节

指针修饰

const     

更改为只读,不可修改

修饰普通变量

const int a=1;     //  也可以: int const a=1;

int *p=&a;          //  修饰普通变量,普通变量无法通过变量名字更改

*p=2;                 //  只能通过指针间接更改

修饰指针 

const  *  p

int const *p=&a;   //修饰指针指向的内容,内容不可修改,指针指向可以修改;

*  const  p

int * const p=&a;  //修饰指针指向,指向不可修改,指针可以修改;

const  *  const  p

int const  *  const  p; //既修饰指针指向,也修饰指针指向的内容;

void

定义一个任意类型的指针,只能用于修饰指针,不可以修饰变量;

void * p=NULL;  //定义一个任意类型的指针;

实际运用时, 需要将指针类型进行强转:

(int * )p         //  取地址

*(int * )p       //  取内容

(char * )p     //  取地址

*(char * )p    //  取内容

大小端

 大端:低地址存放高字节数据,高地址存放低字节数据;

 小端:低地址存放低字节数据,高地址存放高字节数据;

例如: 

                             0x12345678     

           高字节    ←←←←←←←←    低字节

大端:12  34  56  78   

小端:78  56  34  12

二级指针

二级指针内存放一级指针的地址

int  a   = 1;   

int  *p =&a;  //  p中存放变量a的地址;

int **q =&p;  //  q中存放指针的地址;

变量a的:地址         内容                        

                  &a              a                                

                  p                *p      

                  *q             **q    

 指针和数组

指针和一维数组

直接访问

int a[5]={1,2,3,4,5};

地址

元素

a

&a[0]

1

a[0]

*a

a+1

&a[1]

2

a[1]

*(a+1)

a+2

&a[2]

3

a[2]

*(a+2)

a+3

&a[3]

4

a[3]

*(a+3)

a+4

&a[4]

5

a[4]

*(a+4)

间接访问

int a [5]={1,2,3,4,5};

int *p=a;

地址

元素

p

&p[0]

1

p[0]

*p

p+1

&p[1]

2

p[1]

*(p+1)

p+2

&p[2]

3

p[2]

*(p+2)

p+3

&p[3]

4

p[3]

*(p+3)

p+4

&p[4]

5

p[4]

*(p+4)

a 和 p 不完全一样

a:地址常量,不可修改

p:指针变量,可以修改

运算:

(单目运算符,从左往右计算)

++ * p       :  先 * p ,再 ++ *p;

* p ++       :  先 p++,再* p++;

* ++ p       : 先++p ,再 * ++p;

( * p ) ++   : 先*p, 再 *p ++;

* ( p ++ )   : 先p ++,再 * p++;

* ( ++ p )   : 先++ p ;再* ++p

指针和二维数组

int a[2][3]={2,3,4,5,6,7};

数组名是行地址 ,一行里边有多列,行>列,如果想访问到列,需要加   *   降级处理

  *a               第一行第一列

  *a+         第一行第二列

  *(a+1)       第二行第一列

  *(a+1)+1    第二行第二列

  a                第一行首地址

  a+          第二行首地址

  a[0]           第一行第一列

  a[0]+1        第一行第二列

地址

元素

*a

a[0]

a

&a[0][0]

2

a[0][0]

*a[0]

**a

*a+1

a[0]+1

&a[0][1]

3

a[0][1]

*(a[0]+1)

*(*a+1)

*a+2

a[0]+2

&a[0][2]

4

a[0][2]

*(a[0]+2)

*(*a+2)

*(a+1)

a[1]

a+1

&a[1][0]

5

a[1][0]

*a[1]

**(a+1)

*(a+1)+1

a[1]+1

&a[1][1]

6

a[1][1]

*(a[1]+1)

*(*(a+1)+1)

*(a+1)+2

a[1]+2

&a[1][2]

7

a[1][2]

*(a[1]+2)

*(*(a+1)+2)

数组指针

指向数组的指针

格式:(*指针变量名字)[列数]

例:int a[2][3]={1,2,3,4,5,6};

       int *p[4]=a; 

p+1:一次移动[n]位; (p+1,想当于下一行首地址)

地址

元素

p[0]

p

*p

2

**p

*p[0]

p[0]+1

*p+1

3

*(*p+1)

*(p[0]+1)

p[0]+2

*p+2

4

*(*p+2)

*(p[0]+2)

p[1]

p+1

*(p+1)

5

**(p+1)

*p[1]

p[1]+1

*(p+1)+1

6

*(*(p+1)+1)

*(p[1]+1)

p[1]+2

*(p+1)+2

7

*(*(p+1)+2)

*(p[1]+2)

数组指针的大小:相当于指针的大小,64位8个字节,32位4个字节

指针数组

储存指针的数组

格式:*指针变量名字 [元素个数]

例:int a=1,b=2,c=3;

       int *p[3]={&a,&b,&c}; 

变量abc的地址: p[0]=&a,      p[1]=&b,      p[2]=&c;

内容:a=*p[1]    b=*p[2]    c=*p[3]

指针数组的大小:指针数组内元素个数*8

命令行参数

argv :指针数组,存放命令行传递的字符串

argc :命令行传递的字符串的个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值