2021-09-04

嵌入式C语言面试题(二)

1.评价下面的代码

unsigned int zero = 0;
unsigned int compzero = 0xFFFF; 

unsigned int zero = 0; //OK
unsigned int compzero = 0xFFFF;//unsigned int 在16位OS中可以这样表示,在32位OS中表示错误.
应该是:
unsigned int compzero = ~0;

2.求c=a+++b;

int a = 5, b = 7, c;
c = a+++b;
c = a+++b = 12;
c = a+++b被编译器理解为a+++b

3.求值

typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;

则语句 printf("%d",sizeof(struct data)+sizeof(max));的执行结果是?
sizeof(struct date) 分析如下:DATE是一个union,long i可能是4 byte,也可能是8 byte,int k[5]=20 byte,char c1个字节,因此,如果long i是4 byte,则sizeof(DATE)=20.此时struct data的大小为:cat(4byte),cow(20byte),dog(8 byte)合计32个字节.So,总长度为52个字节;

如果long i是8个字节,则DATE是24个字节,则4,24,8=36,合计60个字节.

4.下出下面的输出

char str1[] = "abc";
char str2[] = "abc";

const char str3[] = "abc";
const char str4[] = "abc";

const char *str5 = "abc";
const char *str6 = "abc";

char *str7 = "abc";
char *str8 = "abc";


cout << ( str1 == str2 ) << endl;//str1!=str2,因为是两个不同的数组
cout << ( str3 == str4 ) << endl;//str3!=str4,因为i是两个不同的常量数组
cout << ( str5 == str6 ) << endl;//一样,同样的指针
cout << ( str7 == str8 ) << endl;//一样,同样的指针

5.写出输出结果

main()
{
	int a[5]={1,2,3,4,5};
	int *ptr=(int *)(&a+1);
	printf("%d,%d",*(a+1),*(ptr-1));
}
*(a+1)=a[1],因此,第一个输出是int数据2.
ptr = (int*)(&a+1);首先,a是数组的首地址,那么&a+1到底是表示a的地址加1还是其他意思?
我们必须记住一点:指针加减的数字是以指针指向的数据类型为量度的,由于&a是指向a[5]这个整型数组首地址的地址,也就说&a的数据类型为数组指针(int (*)[5]).这个数组指针指向的数据类型是int a[5],长度为20个字节.因此,&a+1(ptr)表示数组首地址+20int *ptr =&a+1. 因此,ptr-1其实就是指向数组a的第5个元素,也就是5.

6.请问以下代码有什么问题

int  main()
{
  char a='a';
  char *str=&a;//str的地址空间只有1个字符
  strcpy(str,"hello");//指针越界,segment fault.
  printf(str); 
  char* s="AAA";//字符串数组
  printf("%s",s);//.
  s[0]='B';//字符串常量,不能修改.
  printf("%s",s);//.
  return 0;
}

7.请问下列表达式哪些会被编译器禁止?为什么?

int a=248; //OK
b=4;//b没有定义类型,error!
int const c=21;//int常量OK
const int *d=&a;//常量指针,指针指向的数值不能修改,这里做初始化,OK
int *const e=&b;//指针常量,其值为指向b的地址,OK.后面不能修改此指针值.
int const *f =&a;//常量指针,指针指向的值不能修改,这里做初始化,OK
*c=32;//c不是指针,不能有取值运算.error!
d=&b;//常量指针,指针的值可以修改,但原来的地址对应的数值不会修改.OK
*d=43;//常量指针,指针指向的值不能修改,error!
e=34;//指针不能直接赋值,error!
e=&a;//指针常量,指针的值不能修改.error!
f=0x321f;//常量指针,指针指向的值不能修改,但建议指针不要直接赋值

8.交换两个变量的值,不使用第三个变量

1.a = a^b;
  a = a^b;
  b = a^b;
2.a = a+b
  b = a-b
  a = a-b

9.下面的程序会出现什么结果?

#include <stdio.h>
#include <stdlib.h>
void getmemory(char *p)    //
{
    p=(char *) malloc(100);
    strcpy(p,"hello world");
}

int main( )
{
    char *str=NULL;
    getmemory(str);
    //str=NULL,在getmemory函数里面,char*p ,p(指针值)作了修改,但是str(实参)没有修改,因此,调用后,str还是=NULL
    printf("%s/n",str);
    free(str);
    return 0;
}

10.分析以下代码的输出是什么?

int _tmain(int argc, _TCHAR* argv[])  
{  
    unsigned short A=10;  
    printf("~A=%u\n",~A);  
    printf("~A=%d\n",~A);  
    printf("~A=%x\n",~A);
    char c=128;
    printf("c=%d\n",c);  
    return 0;  
}  

第一个,将A作为%u,无符号整数,A=0x0A,则~A = 0xFF FF FF F5 ,则其值为2的32次方-11.
第二个,将A作为有符号整数,~A=0xFF FF FF F5,为负数,由于负数在计算机中用补码表示,其补码为0x0B=-11.
第三个,将A作为16进制数,~A = 0xFF FF FF F5, 故其值就是0xFFFFFFF5.
第四个,c=128=0b 1000 0000,如果解析为有符号整数,则输出为负数,其补码=-128.so 输出为-128.

11.绝对地址0x100000赋值且想让程序跳转到绝对地址是0x100000去执行,如何写代码?

void (* p)() =(unsigned int*)0x100000;
//一个函数指针,返回值为空,参数为空.
p();

12.求下面结构的sizeof(A)大小.

struct A
{
    char t:4;
    char k:4;
    unsigned short i:8;
    unsigned long m;
};

分析:假定编译器设置的对齐参数为#pragma pack(4);(4字节对齐),则:
若为32位OS,
t,k共占据1个字节,unsigned short 2 byte,unsigned long m 4 byte,则对齐单位为4 byte,故t和k占据1个字节,i偏移量从2开始,占据2个字节,m偏移量从4开始,占据4个字节,合计8个字节.
若为64位OS,
t,k共占据1个字节,unsigned short 2 byte, unsigned long m 8个字节,则对齐单位为4 byte,故t和k占据1个字节,i偏移量从2开始,长度为2,m偏移量从4开始,长度为8,共计12个字节.

13.给出下面程序的答案.

typedef struct  AA
{
        int b1:5;
        int b2:2;
}AA;

void main()
{
        AA aa;
        char cc[100];
        strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");//strcpy在最后补0了.
        memcpy(&aa,cc,sizeof(AA));
        cout << aa.b1 <<endl;
        cout << aa.b2 <<endl;
}   

//sizeof(AA)=4;拷贝4个字符“0123”其16进制内容为0x30,0x31,0x32,0x33即:00110000 00110001 00110010 00110011.
//b1和b2占据了这四个字节的前面字节的7位,即b1:0b10000,b2=0b01;int是有符号整数,b1=-16,b2=1

14.给出下面程序的输出.

struct bit
{   
    int a:3;
    int  b:2;
    int c:3;
};

int main()
{
  bit s;
  char *c=(char*)&s;
  cout<<sizeof(bit)<<endl;//sizeof(bit)=4
  *c=0x99;
  cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
  int a=-1;
  printf("%x",a);
  return 0;
}

分析:
sizeof(struct bit)=4.
*c = 0x99= 0b1001 1001,a是前3位,故a是001,b是11,c是100,由于均为int型,故s.a=1,s.b=-1,s.c=-4
a=-1, 1的原码是-0x00000001,-1的补码是0xFFFFFFFF.故a打印出来0xFFFFFFFF.

15.求以下几个结构的长度

struct name1{
   char  str; //1个字节;
   short x;//2个字节;
   int  num;//4个字节
}

struct name2{
   char str;//1个字节
   int num;//4个字节;
   short x;//2个字节
}

假设编译器对齐参数设置为# pragma pack(4),则:
struct name1:
此结构中长度最大的值为num(4),两者之间的较小值为4,第一个char str从0开始,第二个short的偏移量为其长度与4的较小值,故为2,第三个int num 长度为4,故其偏移量为4,因此,合计长度为8.
struct name2:
首先,其单位对齐长度为num的长度与pack(4)两者的最小值(4).
char str 1个字节,占据1个字节,num 占据4个字节,偏移量为4的倍数,故从4开始,占据4-7四个 byte,short x是两个字节,故偏移量为2的倍数,偏移量为8,占据2个字节,但总长度应该是4的整数倍,故最终的占据长度为4+4+4=12.

从上面可以看出,为了节约空间,数据类型占据字节长的结构成员,应该放在结构的后面.

struct s1
{
  int i: 8;//8位bit  
  int j: 4;//4位bit
  int a: 3;//3位bit
  double b;
};


struct s2
{
  int i: 8;//
  int j: 4;//两个int,共需要2个字节,//
  double b;//第三个,需要8,其偏移量从8开始,长度为8.
  int a:3;//第四个,偏移量从16开始,长度为4.因此,且总长度需要8的倍数,因此,此结构的总长度为8+8+8=24.
};

假设为#pragma pack(4),则:
struct s1:
i,j,a均为int型,合计占据15个字节,由于单位对齐长度为4,故这三个bit位共占据2个字节,double b始终占据8 byte,则其偏移量为4的倍数,本身占据8个字节,故struct s1的长度为12.

struct s2:
i,j,为int型,共占据2个字节;double b占据8个字节,故为4-11 8个字节,int a:3占据4个字节,故合计为4+8+4=16个字节.(关于结构体长度的判断,请参见笔者在csdn的相关其他文章)

16.填空

struct BBB
{
   long num;//4个字节  offset 0+4
   char *name;//4个字节 offset 4+4
   short int data;//2个字节 offset 8+2
   char ha;//1个字节      offset 10+2
   short ba[5];
}*p;
p=0x1000000;
p+0x200=____;
(unsigned long*)p+0x200=____;
(char*)p+0x200=____;

分析如下:

struct BBB
{  
   //单位对齐长度为4.
   long num;//4个字节  0+4(offset+占据字节,下同)
   char *name;//4个字节 4+4
   short int data;//2个字节 8+2
   char ha;//1个字节      10+2
   short ba[5];          12+10(12)
}*p;
p=0x1000000;
p+0x200=____;
(unsigned long*)p+0x200=____;
(char*)p+0x200=____;

由于long在32位OS和64位OS下面有不同的长度,故分开讨论:
假设为32位OS:根据笔者C语言结构体所占空间分析(https://blog.csdn.net/cdma_zte_c/article/details/119943850)可知,struct BBB占据22个字节,但应该为4的倍数,故占据空间为24 Byte.
所以p+0x200 = p+0x20024 = p + 0x2000x18
(unsigned long*)p+0x200= p + 0x200sizeof(unsigned long)=p+ 0x200 * 4
(char
)p + 0x200 = p + 0x200*sizeof(char)=p+0x200

假设为64位OS,则分析如下:
struct BBB
{
//单位对齐长度为4
long num;//8个字节 0+8(offset+占据字节,下同)
char *name;//8个字节 8+8
short int data;//2个字节 16+2
char ha;//1个字节 18+2
short ba[5]; 20+10(12)
}*p;
故合计占据长度为32 byte.
则后面就好计算了.

17.写出程序输出结果

void g(int**);
int main()
{
	int line[10],i;
	int *p=line; //p是一个指向int数据的指针,然后赋值给它line,
	//这样,p就指向了line的首地址.指针p的类型是 (int *)[10];
	for (i=0;i<10;i++)
	{
	    *p=i;// *p = i,将i赋值给line的第i个元素。
	    g(&p);//因为p是一个指针,把指针地址当作参数传递到函数.
	}

	for(i=0;i<10;i++)
	    printf("%d\n",line[i]);

       return 0;
} 

void g(int**p)
{
    (**p)++;//根据上面的分析,(**p)就是line数组当前位值的数值,后++,由于(**p)++操作的是实际的内存中的数值,故调用g函数的line数组中的值会相应修改.
    (*p)++;//*p是指针,指向line数组的相应位置,现在(*p)++,相当于指向line数组相关元素位置的指针的值++(指针的值是保存在指针p对应的内存中,指针的值++,就是p指向的内存中的值++),因此,就是line数组的当前元素位置后移.然后再次赋值,再次+1.故输出是1,2,3,4,5,6,7,8,9,10
}

分析情况参见源码部分.

18.写出程序输出结果

int arr[] = {6,7,8,9,10};
int *ptr = arr;//ptr指向数组头部
*(ptr++)+=123; // 首先*ptr = 123,然后ptr++.
printf(%d %d ”, *ptr, *(++ptr));//首先计算右边的*(++ptr),ptr+2 ,指向数据8,*ptr=8.故两者输出都是8.
typedef struct
{
  int a:2;
  int b:2;
  int c:1;
}test;

test t;
t.a = 1;//a=0x01,正数,因此,打印为1.
t.b = 3;//a=0x11,负数,求补码,因此,打印为-1
t.c = 1;//c=0x1,负数,求补码,打印为-1
printf("%d",t.a);
printf("%d",t.b);
printf("%d",t.c);

解答参见原文代码.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03
这里是使用 Python 的 PyMySQL 完成上述任务的代码: ```python import pymysql # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='test') # 创建游标 cur = conn.cursor() # 创建 users 表 cur.execute(''' CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(20), age INT ) ''') # 创建 orders 表 cur.execute(''' CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, amount INT, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) ) ''') # 插入数据 users_data = [ (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28) ] orders_data = [ (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4) ] for user in users_data: cur.execute('INSERT INTO users VALUES (%s, %s, %s)', user) for order in orders_data: cur.execute('INSERT INTO orders VALUES (%s, %s, %s, %s)', order) # 提交事务 conn.commit() # 查询语句 # 1. 查询订单总金额 cur.execute('SELECT SUM(amount) FROM orders') print(cur.fetchone()[0]) # 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 cur.execute('SELECT ROUND(AVG(age), 2) FROM users') print(cur.fetchone()[0]) # 3. 查询订单总数最多的用户的姓名和订单总数。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_orders DESC LIMIT 1 ''') print(cur.fetchone()) # 4. 查询所有不重复的年龄。 cur.execute('SELECT DISTINCT age FROM users') print([row[0] for row in cur.fetchall()]) # 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 cur.execute('SELECT SUM(amount) FROM orders WHERE order_date BETWEEN "2021-09-01" AND "2021-09-04"') print(cur.fetchone()[0]) # 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id WHERE age <= 25 GROUP BY users.id ORDER BY total_orders DESC ''') print(cur.fetchall()) # 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 3 ''') print(cur.fetchall()) # 8. 查询订单总金额最大的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 1 ''') print(cur.fetchone()) # 9. 查询订单总金额最小的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount ASC LIMIT 1 ''') print(cur.fetchone()) # 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 cur.execute('SELECT * FROM users WHERE name LIKE "%李%" ORDER BY name ASC') print(cur.fetchall()) # 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 cur.execute('SELECT * FROM users WHERE age > 20 ORDER BY age DESC LIMIT 5') print(cur.fetchall()) # 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC ''') print(cur.fetchall()) # 关闭游标和连接 cur.close() conn.close() ``` 注意:在运行代码之前,需要先安装 PyMySQL 模块,可以使用以下命令进行安装: ``` pip install pymysql ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值