嵌入式c语言面试题总结

指针定义

一个指向指针的的指针,它指向的指针是指向一个整型数
int **a;
一个有10个指针的数组,该指针是指向一个整型数的
int *a[10];
一个指向有10个整型数数组的指针
int (*a)[10]
一个指向函数的指针,该函数有一个整型参数并返回一个整型数
int *a( int ){}
一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
int (* a[10])( int ) //类似这种定义应该采用分解法来做。 先定义单个函数指针 int (*a)(int),然后再是有10个指针的数组 int (*a[10])(int)

关键字static的作用是什么?


1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变(该变量存放在静态变量区)。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用

关键字const


const int a;  常量a
int const a;  常量a
const int *a;  指针指向的内容不可以被修改   但是指针指向的地址可以修改。
int * const a; 指针指向的地方不可以被改,但是指向的地址的内容可以修改。
int const * const a;  指针指向地址的内容和指针指向的地址都不可以修改。

第一个设置a的bit 3,第二个清除a 的bit 3


a |= 1 << 3
a &= 0 << 3
或BIC a,a,#0x3

有符号数与无符号数


8.下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6)?puts("> 6") : puts("<= 6");
}
大于6.  有符号数转换为无符号数。
无符号数:不存在正负之分,所有位都用来表示数的本身。
有符号数:最高位用来表示数的正负,最高位为1则表示负数,最高位为0则表示正数。
1. 无符号数转换为有符号数:看无符号数的最高位是否为1,如果不为1(即为0),则有符号数就直接等于无符号数;
2.如果无符号数的最高位为1,则将无符号数取补码,得到的数就是有符号数。
3..有符号数转换为无符号数 :看有符号数的最高位是否为1,如果不为1(即为0),则无符号数就直接等于有符号数;
4.如果有符号数的最高位为1,则将有符号数取补码,得到的数就是无符号数
所以6 - 20 = -14,因为结果作为一个无符号数已经溢出了,所以又加了65536结果变成一个正数了,为65522
-5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)

\0问题

void test1()
{
char string[10];
char* str1 = "0123456789";
strcpy( string, str1 );
}
//溢出 还有\0

void test2()
{
char string[10], str1[10];
int i;
for(i=0; i<10; i++)
{
str1[i] = 'a';
}
strcpy( string, str1 );
}
str1没有\0结束符,程序崩溃。

void test3(char* str1)
{
char string[10];
if( strlen( str1 ) <= 10 )
{
strcpy( string, str1 );
}
}改为strlen( str1 ) < 10  这种方式不会报错,但是会造成隐藏的严重bug, 会修改内存里面的数据。

请计算sizeof的值和strlen的值。


void func ( char *str )
{
sizeof( str ) = ?
}
char str[10] = “hello”;
strlen(str);
10和5

宏定义问题

#include "stdafx.h"
#define SQR(X) X*X
int main(int argc, char* argv[])
{
    int a = 10;
    int k = 2;
    int m = 1;
    a /= SQR(k+m)/SQR(k+m);
    printf("%d\n",a);
    return 0;
}
a =a/ (k+m*k+m/k+m*k+m)

用C写个程序,如何判断一个操作系统是16 位还是32 位的?不能用sizeof()函数。


int a = ~0;//把位数全部设为1
if( a>65536 )  
{
  cout<<"32 bit"<<endl;
}
else
{
  cout<<"16 bit"<<endl;
}

在不用第三方参数的情况下,交换两个参数的值.


a=a+b;
b=a-b;
a=a-b;
或者
a = a^b;
b = a^b;
a= a^b;

指针操作

unsigned short array[]={1,2,3,4,5,6,7};
int i = 3;
*(array + i) = ?
结果是4。

main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);// (&a+1)指向下一个一维数组
printf("%d,%d",*(a+1),*(ptr-1));
}
解:
int *ptr=(int *)(&a+1);&a表示取得数组a存储区域的首地址,再加1表示数组a存储区域的后的地址,这就使得ptr指针指向数组的最后一个元素后面的那个存储单元的地址,
而ptr减1后,再进行数据访问,则访问的是ptr指针的前一个存储单元的值,所有最后的答案是2,5
(int *)(&a+1) 强制转化指针类型。

#include <filename.h>和 #include “filename.h” 有什么区别?


<>会直接去系统遍历
""会首先在当前项目遍历头文件,如果不存在才去系统遍历。
<>的可以改成"",但是""一定不能改成<>

不能做switch()的参数类型是:


只有整数可以做参数

局部变量能否和全局变量重名。


可以重名。 局部变量名会覆盖全局变量名。  C++中可以使用作用域来区分。
全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
不可以!但是可以声明。 这里涉及到强符号和弱符号的问题,具体的可以参考下面的blog。
在C语言中,函数和初始化的全局变量(包括初始化为0)是强符号,未初始化的全局变量是弱符号。
对于它们,下列三条规则使用:
① 同名的强符号只能有一个,否则编译器报"重复定义"错误。
② 允许一个强符号和多个弱符号,但定义会选择强符号的。
③ 当有多个弱符号相同时,链接器选择占用内存空间最大的那个。

一语句实现x是否为2的若干次幂的判断。


if ( x & ( x - 1 ) == 0 )
    printf("是2的幂");
  else printf("不是2的幂");

pow(x,y),计算x的y次幂
sqrt(x),求浮点数x的平方根
fabs(x),求浮点数x的绝对值

char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
有什么错?


常量区  不允许修改内容,结果不变。AAA

#define MAX 256
int main()
{
unsigned char A[MAX],i;
for (i=0;i<MAX;i++)
A[i]=i;
}


char是一字节,八位,最大可以表示的整数是255,所以这里死循环了

35.struct name1
{
char str;
short x;
int num;
}
struct name2
{
char str;
int num; 
short x; 
}
typedef struct 
{
    int a;
    char b[3];
    short d;
    int c;
 } node;
sizeof(struct name1)=8
sizeof(struct name2)=12
sizeof(node) = 16


字节对齐

int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}


没有为a分配内存,并且a是一个字符变量。  内存越界。

地址和变量大小操作

unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问p1+5= 0x801005; p2+5= 0x810014;
输出结果p1+5的值是801005,因为指针变量指向的值字符,加一表示指针向后移动一个字节,那么加5代表向后移动5个字节,所以输入801005
p5+5的值是801016,因为指针变量指向的长整形的,加一表示指针向后移动4个字节,那么加5代表向后移动20个字节,所以输入810014,(输出时十六进制)要是十进制就是810020了 

有数组定义int a[2][2]={ {1},{2,3}};则a[0][1]的值为0。 // 对
int (*ptr) (),则ptr 是一维数组的名字。  // 函数指针
指针在任何情况下都可进行>, <,>=, <=,==运算。 //不明所以
switch(c) 语句中c 可以是int ,long,char ,float ,unsigned int 类型。 //错。  只能是整数,float排除。
不使用库函数,编写函数int strcmp(char *source, char *dest) 相等返回0,不等返回-1;
写一函数int fun(char *p)判断一字符串是否为回文,是返回1,不是返回0,出错返回-1

静态变量操作

#include<stdio.h>
int sum(int a)
{
int c=0;
static int b = 3;//静态
c+=1;
b+=2;
return(a+b+c); 
}
int main()
{
int I;
int a=2;
for(I=0;I <5;I++)
{
printf("%d,", sum(a));
}
return 0;
}
8,10,12,14,16,

一定能打印出”hello”的是134,有错误的是2


char *GetHellostr(void);
int main(void)
{
char *ps;
ps= GetHellostr( );
if(ps != NULL)
{
printf(ps);
}
return 0;
}
(1)
char *GetHellostr(void)
{
char *ps=“hello”;
return ps;
}
(2)
char *GetHellostr(void)
{
char a[]=“hello”;
return (char *)a;  内存已经被释放了
}
(3)
char *GetHellostr(void)
{
static char a[]=“hello”;
return (char *)a;
}
(4)
char *GetHellostr(void)
{
char *ps;
ps = malloc(10);
if(NULL ==ps) return NULL;
strcpy(ps,”hello”);
return ps;
}

字符串函数

char* strcpy(char* strDest,const char* strSrc)
{
    assert(strDest!=NULL && strSrc!=NULL);
    char* strTmp = strDest;
    while(*strSrc!='\0')
    {
        *strDest++ = *strSrc++;
    }
    strDest = '\0';
    return strTmp;
}

int strlen(const char*strSrc)
{
    assert(strSrc!= NULL);
    int len = 0;
    while((*strSrc++)  != '\0')
        ++len;
    return len;
}

char* strcat(char* strDest,const char* strSrc)
{
    assert((strDest != NULL) && (strSrc != NULL));
    char* strTmp = strDest;
    while(*strDest != '\0')
        ++strDest;
    while(*strDest++ = *strSrc++);
    *strDest++ = '\0';
    return strDest;
}

双指针和指针的引用

void foo(char **p)//双指针
{
    *p = "after";
}
int main()
{
    int *p = "befor";
    foo(&p);
    cout << p << endl;//输出的为after
    return 0;
}

void foo(char *&p)//指针的引用
{
    p = "after";
}
int main()
{
    int *p = "befor";
    foo(p);
    cout << p << endl;//输出的为after
    return 0;
}

使用汇编语言的原因:


第一:汇编语言执行速率要高于c语言。
第二:启动代码,编写bootloader和内核使用时,主要对cpu和内存进行初始化时使用。因为这个时候还能没有c语言编写的环境(堆栈还没建立),所以不能用c语言。

#ifndef X
#define X
...
#endif


防止头文件被重复包含和编译。

指针与数组的区别。


第1个存储方式的不同数组是存储的成员内容的本身。而指针存储的是首地址。
第2个是运算方式的不同。数组名是一个常量不能进行自增自减的运算,而指针是一个变量,可以进行自增自减的运算。
第3个是赋值运算的操作。数组可以进行初始化操作,但不能通过赋值语句进行整体的赋值,而指针能指向另一条语句。

strcpy 为什么要返回char*


strcpy函数返回的值可以作另一个函数的实参,实现链式操作。

IIC介绍:


开始信号: SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
结束信号: SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号, CPU 接
收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为
受控单元出现故障。

//IIC 发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对 TEA5767 这三个延时都是必须的
IIC_SCL=1;delay_us(2);
IIC_SCL=0; delay_us(2);
}
}
//读 1 个字节, ack=1 时,发送 ACK, ack=0,发送 nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA 设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0; delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack) IIC_NAck();//发送 nACK
else IIC_Ack(); //发送 ACK
return receive;
}

猜你喜欢

转载自blog.csdn.net/qq_38531460/article/details/103326672