C语言错题整理2-2021-9.24

1-volatile关键字的使用场景


这个关键字一直困扰了我很久,今天必须搞透彻☺
volatile 关键字和const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

1-并行设备的硬件寄存器(状态寄存器)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义。
   假设要对一个设备进行初始化,此设备的某一个寄存器为0xff800000。for(i=0;i< 10;i++) *output = i;前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将output这个指针赋值为9,省略了对该硬件IO端口反复读的操作。

2-中断服务程序中修改的供其它程序检测的变量,需要加volatile; 一个中断服务子程序中会访问到的非自动变量
   当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。
注意:被范围外的中断服务程序修改的全局变量:例如,一个全局变量可以代表一个数据端口(通常是全局指针,称为内存映射IO),它会被动态更新。代码读取数据端口必须声明为易失性,以便获取端口上可用的最新数据。如果未将变量声明为 volatile,编译器将优化代码,使其仅读取端口一次并在临时寄存器中继续使用相同的值来加速程序(速度优化)。通常,当由于新数据可用而出现中断时,ISR 用于更新这些数据端口

3-多任务环境下各任务间共享的标志,应该加volatile;
   在本次线程内, 当读取一个变量时,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存 器中取值;当内存变量或寄存器变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。
注意:多线程应用程序中的全局变量:线程通信有多种方式,即消息传递、共享内存、邮箱等。全局变量是共享内存的弱形式。当两个线程通过全局变量共享信息时,需要使用 volatile 进行限定。由于线程是异步运行的,因此一个线程对全局变量的任何更新都应该由另一个消费者线程重新获取。编译器可以读取全局变量并将它们放置在当前线程上下文的临时变量中。为了消除编译器优化的影响,需要将此类全局变量限定为 volatile

如果我们不使用 volatile 限定符,可能会出现以下问题:
1)当优化打开时,代码可能无法按预期工作。
2) 启用和使用中断时,代码可能无法按预期工作。

https://www.cnblogs.com/hjh-666/p/11148119.html
https://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html

2-数组与指针的区别


数组:数组是用于储存多个相同类型数据的集合。
指针:指针相当于一个变量,但是它和不同变量不一样,它存放的是其它变量在内存中的地址。
• 赋值:同类型指针变量可以相互赋值,数组不行,只能一个一个元素的赋值或拷贝
• 存储方式:数组:数组在内存中是连续存放的,开辟一块连续的内存空间。数组是根据数组的下进行访问的,数组在内存中是按照一维数组存储的,只是在逻辑上是的。指针:指针很灵活,它可以指向任意类型的数据。指针的类型说明了它所指向地址空间的内存。
• 求sizeof:数组所占存储空间的内存:sizeof(数组名),数组的大小:sizeof(数组名)/sizeof(数据类型)。在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。
• 初始化方式不同。
• 传参方式:数组传参时,会退化为指针,C语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时,将数组名看做常量指针,传数组首元素的地址。一级指针传参可以接受的参数类型:(1)可以是一个整形指针 (2)可以是整型变量地址 (3)可以是一维整型数组数组名;当函数参数部分是二级指针时,可以接受的参数类型:(1)二级指针变量(2)一级指针变量地址(3)一维指针数组的数组名

3-以下程序统计给定输入中每个大写字母的出现次数(不需要检查输入合法性)

void AlphabetCounting(char a[],int n){
  int count[26]={},i,kind=0;
  for(i=0;i<n;++i) (1);
  for(i=0;i<26;++i){
    if(++kind>1) putchar(';');
    printf("%c=%d",(2));
   }
}

一、count[0;25]存储A-Z的个数,即count[0]存储A的个数,于是(1)++count[a[i]-‘A’];(2)‘A’+i,count[i];
二、count[0;25]存储Z-A的个数,即count[0]存储Z的个数,于是(1)++count[‘Z’-a[i]];(2)‘Z’-i,count[i]。

4-下列代码,循环了多少次

k = 2000 
while(k > 1) 
{ 
 	k = k >> 1; 
} 

'>>'是位移符号。可以理解为每次除以2. 从k=2000直到k=1,共需10次位移操作。没到2048,10次就好了

5-字符串处理strcpy/strcat函数的用法


1)strcat是用来连接两个字符串的,原型是char *strcat(char *dest,char *src),作用是把src所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’\0’
2) strcpy是用来把字符串拷贝到指定的地方的,原型是char *strcpy(char *dest,const char *src),作用是把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间注意strcat是从dest的结尾处开始操作的,而strcpy是直接覆盖dest指向的内容。
cpy 后面的复制到前面 cat 前面与后面连接

#include <stdio.h>
#include <string.h>
int main()
{
    char p1[15]="abcd",*p2="ABCD", str[50]="xyz";
    strcpy(str+2,strcat(p1+2,p2+1));
    printf("%s",str);
}

输出:xycdBCD

6-输出a[1][2]的值的语句是

int a[2][3];
int (*p)[3]=a; 
int *q=*a;

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值