嵌入式C语言实战开发详解(二)

时间:2021-12-04 19:12:09

一、运算符与表达式

嵌入式C语言实战开发详解(二)

1、算数运算符

自增、自减运算符详解:

#include<stdio.h>

int main()

{

int i = 2;

num = (i++)  + (i++) +(i++)+ (i++)


printf("%d%d\n"i,num); 


return 0;

}

输出 num = 8; i = 6

i++使用结束之后再自加

++i先自加再使用

结束标志:; , ()(函数括号)


i = 2

num = (++i) + (++i) + (++i) + (++i)

num = 4 + 4 + 5 + 6 = 19  


i = 2

num = i * ((i++) + (++i))

num = 3*(3 + 3) +1 = 19


i = 2

num = (i++) + (++i) + (i++) + (++i)

num = 3+3+3+4+2 = 15


<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">#include<stdio.h>

int func(int a,int b,int c,int d,int e)
{
printf("%d %d %d %d %d\n",a,b,c,d,e);
}

int main()
{
int i = 2;

func(++i,++i,i,i++,++i);

return 0;
}</span></span></span></span>
输出结果 6 6 6 3 6

函数从最右边开始传参


i++:被替换成数值

++i:被替换成变量名


2、关系运算符

未防止出错,一般将常量写左边,如:if(6 == num)

下面用代码示例:

嵌入式C语言实战开发详解(二)

明显有错,但是下面来看编译运行结果

嵌入式C语言实战开发详解(二)

没有报错!

这样的错误一旦犯在做项目中,一步步排错将非常痛苦

嵌入式C语言实战开发详解(二)

这样能有效的解决这种问题

嵌入式C语言实战开发详解(二)

编译器会报错


用于比较运算,包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)、和不等于(!=)


3、逻辑运算符


用于逻辑运算,包括与(&&)、或(||)、非(!)

代码代码示例说明短路与、短路或:


嵌入式C语言实战开发详解(二)

嵌入式C语言实战开发详解(二)

与是短路与,只执行++i;


4、位操作运算符


参与运算的量,按二进制位进行运算,包括位与(&)、位或(|)、取反(~)、位异或(^)、左移(<<)、右移(>>)


位操作是对无符号数!(敲黑板!)


用位操作将十进制转换成二进制:

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">#include<stdio.h>

int int2bin(int num)
{
int i;

unsigned int mask = 0x80000000;

for(i = 0; i < 32; i++)
{
if((mask & num) == mask)
{
printf("1");
}
else
{
printf("0");
}

num = num << 1;

if((i + 1) % 4 == 0)
{
printf(" ");
}
}

printf("\n");
}
int main()
{
int num;


printf("please input a number:");
scanf("%d",&num);


int2bin(num);

return 0;
}</span></span></span>

其中:mask = 0x8000000 就是掩码

在位操作中,掩码的作用是十分重要的,使用掩码将十分方便的进行位操作


(1)位与

应用:

1、清0特定位:(mask 特定位置0,其他位为1,s = s & mask);

2、取某数中指定位:(mask 特定位置1,其他位为0,s= s & mask);

代码示例

题目:输入一个整数num,再输入两个整数m,n(m,n<32),输出该整数的二进制表示方法中从右端开始的mn.
#include<stdio.h>

#define MAX_SIZE 200

int m_n(int num,int m,int n)
{
int temp;
int i;
int j;

unsigned int mask = (unsigned int)(((~(unsigned int)0) >> (32 - (n - m +1))) << m);

num = num & mask;

num = num >> n;

for(i = n - m; i >=0; i--)
{
temp = (num >> i) & 1;
printf("%d",temp);
}

printf("\n");
}

int main()
{
int num;
int m;
int n;

printf("please input a number:");
scanf("%d",&num);

printf("please input m:");
scanf("%d",&m);

printf("please input n:");
scanf("%d",&n);

m_n(num,m,n);


return 0;
}





有符号数:

右移拿符号位补位;  

左移拿0补位。

所以,要对无符号数进行位操作。


(2)位或

应用:

常用来将源操作数某些位置1,其他位不变(mask中特定位置1,其他位为0,s = s & mask)


(3)位异或

作用:

(1)使特定位的值取反(mask中特定位置1,其他位为0,s = s ^ mask);

(2)不引入第三变量交换两个变量的值


  a、b互换值,不会出现数据溢出的情况


  a = a ^ b;

  b = a ^ b;

  c = a ^ b;


5、赋值运算符


用于赋值运算

简单赋值:(=)

复合算术赋值:(+=、-=、*=、/=、%=)

复合位运算赋值:(&=、|=、^=、>>=、<<=)


6、条件运算符


?=:


7、指针运算符

* 是取内容

&是取地址


二、指针与数组


1、指针是一个变量,保存的值是地址。

2、地址长度都是固定的,原因是地址长度都是由操作系统决定的,如果操作系统是32位的,则地址长度是4字节,如果操作系统是64位的,则地址长度是8字节。


嵌入式C语言实战开发详解(二)

地址是有划分的,原因是步长不一样的。

3、嵌入式C语言实战开发详解(二)

  num == *p  ==  **pp  ==  ***ppp == *&num

  &num == p == *pp == **ppp

  指向的内存空间

   对应的内存空间

  num++:num对应的内存空间的值加1

  p++:p对应的内存空间的值加1(步长)(0x1000   0x1004);

  pp++:pp对应的内存空间的值加1(步长)(0x2000    0x2004;

  (*p)++:根据p对应的内存空间里保存的地址找到其对应的内存空间的值加1

  (*pp)++:根据pp对应的内存空间里保存的地址找到其对应的内存空间的值加10x1000    0x1004;

  (**pp)++:根据pp对应的内存空间的地址找到对应的内存空间的地址找到其对应的内存空间的值加15+1=6)。

4、远指针:超过二维指针的指针

5、定义指针的几种规范

  int  *p;

  int * p;

6、指针的类型和指针所指向的类型

  指针的类型:

(1)int  *ptr:       //指针的类型是int*;

(2)char  *ptr:     //指针的类型是char*;

(3)int  **ptr:     //指针的类型是int**;

(4)int  (*ptr)[3]:   //指针的类型是int(*)[3];

(5)int  *(*ptr)[4]:  //指针的类型是int*(*)[4].

   指针所指向的类型:

1int  *ptr:       //指针所指向的类型是int;

2char  *ptr:     //指针所指向的类型是char;

3int  **ptr:     //指针所指向的类型是int*;

4int  (*ptr)[3]:   //指针所指向的类型是int()[3];

5int  *(*ptr)[4]:  //指针所指向的类型是int*()[4].

 

7、指针的赋值运算

(1)空指针(NULL

(2)野指针:

<span style="font-size:18px;">#include<stdio.h>
int main()
{
int *p;
scanf(“%d”,p);
printf(“%d\n”,p);
return 0;
}</span>


这个代码会出现段错误:系统随机后给地址,该地址不一定能用。

野指针:随机指向内存中的一块内存(已经被释放的内存或者没有访问权限的内存)的指针为野指针。

野指针会导致内存泄漏:野指针访问已经释放的内存或者是访问没有访问权限的内存。

有哪些操作可以避免野指针?

1.定义一个指针,没有指向赋值的时候,赋值为NULL;

优点:(1)看到NULL,就知道零地址是无法进行操作和访问的;

          (2)发生段错误时,NULL比较醒目,容易检错。

2.给指针指向地址进行赋值操作时,要检查指针是否有合理的空间,如果没有,用malloc分配空间;

嵌入式C语言实战开发详解(二)

注:使用malloc要检查有没有分配成功

malloc返回void *

void * 是万能指针,能够接受任何指针的值,缺点是,不能取值操作

在C语言中,指针之间的赋值必须是相同类型的赋值,从不兼容的指针类型赋值,不同的数据类型步长不一样,会有两种结果:

(1)取值取不完整

(2)发生越界

所以使用malloc一般要进行强制类型转换,比如说:

char *ptr;

ptr = (char *)malloc(MAX_SIZE * sizeof(char )) 给指针分配100个字节

3.使用memset、bzero来清空原来内存中的数据

4.指针使用结束后,要释放(free);

5.再次将指针置为空;

原因:free操作只释放了地址,没有释放掉数值;

memset(ptr,0,sizeof(char)*MAX_SIZE) 

三、字符串

1、字符串就是首字符地址

2、字符串函数:Linux C函数库手册

下面为自编代码实现字符串函数功能:

(1)字符串比较函数-strcmpstrncmp

   my_strcmp

int my_strcmp(char *dest,char *src)
{
while(*src != '\0' && *dest != '\0')
{
if(*(dest++) > *(src++))
{
return 1;
}
else if(*(dest++) < *(src++))
{
return -1;
}
}

if(*src == '\0'&& *dest == '\0')
{
return 0;
}
if(*src != '\0' && *dest == '\0')
{
return -1;
}
if(*src == '\0' && *dest != '\0')
{
return 1;
}
}


   my_strncmp

int my_strncmp(char *dest,char *src,int len)
{
int i;
for(i = 0; i < len;i++)
{
if(*(dest + i) != *(src + i))
{
return -1;
}
}

return 0;

}


(2)字符串拷贝函数-strcpystrncpy

   my_strcpy  

char *my_strcpy(char *dest,char *src)
{
char *temp = dest;

while(*src != '\0')
{
*dest = *src;
dest++;
src++;

}
*dest = '\0';

return temp;

}


   my_strncpy

char *my_strncpy(char *dest,char *src,int len)
{
int i;

char *temp = dest;

for(i = 0; i < len; i++)
{
*(temp + i) = *(src + i);
}

*(temp + i) = '\0';

return dest;

}


(3)字符串长度函数-strlen

   my_strlen

int my_strlen(char *src)
{
int len = 0;

while(*src != '\0')
{
src++;
len++;
}

return len;
}


(4)字符串连接函数-strcatstrncat

   my_strcat

char * my_strcat(char *dest,char *src)
{
char *temp = dest;

while(*temp != '\0')
{
temp++;
}

while(*src != '\0')
{
*temp = *src;
temp++;
src++;
}

*temp = '\0';

return dest;

}


  my_strncat

char *my_strncat(char *dest,char *src,int len)
{
char *temp = dest;
int i;


while(*temp != '\0')
{
temp++;
}

for(i = 0; i < len;i++)
{
*temp = *src;
temp++;
src++;
}

*temp = '\0';

return dest;


}


(5)字符串清空函数-memset、bzero

   未完待续