[C语言]每日一题

背景介绍

在野火论坛刷题。
网址:http://www.firebbs.cn/forum.php?mod=forumdisplay&fid=89

1. 考验阅读代码的分析能力

2019.9.14 晴 YSU
【每日一思】考验阅读代码的分析能力
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1278&fromuid=32424
(出处: 野火电子论坛)

char *func(char *dest, const char *src, int count)
{
	char *tmp = dest;
	
	while(count){
		if((*tmp = *src) != 0)
			src++;
		tmp++;
		const--;
	}
	
	return dest;
}

回答:
总体功能描述:
字符串复制,返回复制后的字符串地址。

  1. 传递两个 char* 指针与一个 int 型变量(src 指向内容为常量)
  2. 将 dest 指针指向的地址复制拷贝给 tmp 指针(两者指向同一地址或者说同一块内存)
  3. count 不为 0 则 while
  4. 取 src 指向字符串中的字符一个个赋值给 tmp,并判断如果src指向字符不为 0 则 src 自增,即指向下一个字符
  5. tmp自增,指向下一个地址
  6. const 自减
  7. 循环结束,返回 dest 指针

解析:


直接上源代码
/*   
 * strncpy - Copy a length-limited, %NUL-terminated string   
 * @dest: Where to copy the string to   
 * @src: Where to copy the string from   
 * @count: The maximum number of bytes to copy   
 *   
 * The result is not %NUL-terminated if the source exceeds   
 * @count bytes.   
 *   
 * In the case where the length of @src is less than that of   
 * count, the remainder of @dest will be padded with %NUL.   
 */   
char *strncpy(char *dest, const char *src, size_t count)    //从 src 复制count个字符 到 dest 
{    
    char *tmp = dest;    
        
    while (count) {    
        if ((*tmp = *src) != 0)    //把 src 的值 复制到 dest ,如果 src 的值 非空,那么指针自加。
                                   //否则 指针不加,src 后续都是指向 0 ,即字符串结束,后续的 dest值都为 0
            src++;    
        tmp++;                     // dest 的指针 自加
        count--;                   //最大计数值 减 1
    }    
        
    return dest;    
}   

2. 数据声明 [嵌入式校园招聘笔试题]

【每日一题】数据声明 [嵌入式校园招聘笔试题]
http://www.firebbs.cn/forum.php?mod=viewthread&tid=6425&fromuid=32424
(出处: 野火电子论坛)
知识点:数据声明(Data declarations) 的应用

题目:用变量a给出下面的定义
1、一个整型数(An integer)
2、一个指向整型数的指针( A pointer to an integer)
3、一个指向指针的的指针,它指向的指针是指向一个整数( A pointer to a pointer to an intege)
4、一个有10个整型数的数组( An array of 10 integers)
5、一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
6、 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
7、 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
8、一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )

回答:

  1. int a;
  2. int *a;
  3. int **a;
  4. int a[10];
  5. int *a[10];
  6. int (*a)[10];
  7. int (*fun)(int a);
  8. int *a[10](int a);

解析:


1、[code=c]int a; // An integer[/code]
2、[code=c]int *a; // A pointer to an integer[/code]
3、[code=c]int **a; // A pointer to a pointer to an integer [/code]
4、[code=c]int a[10]; // An array of 10 integers[/code]
5、[code=c]int *a[10]; // An array of 10 pointers to integers[/code]
   [code=c] 等价于int *(a[10]);[/code]
6、[code=c]int (*a)[10]; // A pointer to an array of 10 integers [/code]
7、[code=c]int (*max_function)(int a); // A pointer to a function a that takes an integer ar    gument and returns an integer[/code]
8、[code=c]int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer[/code]

反思:
对函数的定义,有一丝的不明确。
扩充:

  1. 指针数据:char *a[10]; // 指针的数组=>指针组成的数组。
  2. 数组指针:char (*a)[10]; // 数组指针=>数组组成的指针?(这样不对),即指向数组的指针。
  3. int *fun(int); // 函数,该函数返回 int *
  4. int (*fun)(int ); // 指向函数的指针,返回 int

3. 指针加法操作

【每日一题】指针加法操作
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1889&fromuid=32424
(出处: 野火电子论坛)
分析下面代码的运行结果

int main()
{
    int * p = 0;        //sizeof(int ) = 4
    p++;
    printf("p=%d\n",p);
    return 0;
}

回答:乱码。
答案:

由于sizeof(int)的值为4,因此指针的偏移值就为4。指针加1,等效于指针值加4。
运算结果为 p=4

反思:
int *p = 0;p++; => p = 4;
char*p = 0;p++; => p = 1;
double *p = NULL;p++; => p = 8;
double*p = NULL;p++;p++; => p = 16;

3.计算运算式子的结果

【每日一题讲解】计算运算式子的结果
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1101&fromuid=32424
(出处: 野火电子论坛)

//题目
printf("%d",0x01<<2+3*2 ); 
//运算结果为多少?

//A.8
//B.10
//C.128
//D.256

回答:0000 0001 0000 0000 2^8
解析:

此题是 优先级 问题
* 乘号 的 优先级 比 + 加号 高

+ 加号 的优先级 又比 << 左移号 高


因此题目就变为求:0x01<<(2+3*2)   等效于  1<< 8 ,即 256 ,答案为 D

4. sizeof的用法

【每日一题讲解】sizeof的用法
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1164&fromuid=32424
(出处: 野火电子论坛)

已知int i,以下那种写法是错误的?
A.sizeof( int );
B.sizeof( i );
C.sizeof int;
D.sizeof i;

回答:C,推理:如果有CD 这种用法,则 int 没有被定义。

语法格式 sizeof 有三种语法形式  
1) 用于数据类型  sizeof( type_name ); // sizeof( 类型 );  
2) 用于变量      sizeof ( object );       // sizeof( 对象 );  
                sizeof object;           // sizeof 对象;  

所以,C.sizeof int; 是错的

5. 结构体的内存大小问题

【每日一题讲解】结构体的内存大小问题
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1111&fromuid=32424
(出处: 野火电子论坛)

//若 int 占 2 个字节,char 占 1 个字节,float 占 4 个字节,则定义如下: 
struct stu 
{ 
  union{ 
    char bj[5];
    int bh[2];
  }class; 
  char xm[8];
  float cj;
}xc; 
//则 sizeof(xc)的值为? 

答案:8+8+4=20.

今天这题目,考的是 结构体的内存对齐问题,如果之前没看过结构体内存对齐这问题的同学,基本上都答错的

自然对界(natural   alignment)即默认对齐方式,是指按结构体的成员中 size 最大的成员对齐。

为了提高 CPU 的存储速度,编译器会对一些变量的起始地址做了“对齐”处理。
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)  
char       偏移量必须为 sizeof(char)   即 1 的倍数  
int         偏移量必须为 sizeof(int)     即 4 的倍数    (跟编译器有关,有可能是 2)
float    偏移量必须为 sizeof(float)  即 4 的倍数  
double   偏移量必须为 sizeof(double)  即 8 的倍数  
short   偏移量必须为 sizeof(short)  即 2 的倍数

为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。

例如:
struct   MyStruct      
{    
    double  a;  //偏移量为  0 ,占用 8 字节    
    char    b;  //偏移量为  8 ,占用 1 字节    
                //后面的 int 型偏移量必为 4 的倍数,故编译器自动填充 3 个空缺的字节    
    int     c;  //偏移量为 12 ,占用 4 字节    
};              //sizeof(MyStruct)=8+1+3+4=16 
注意:交换一下结构体的成员变量的位置,其占用空间大小可能是不一样的
回到题目:
  union{  
    char bj[5];   //5
    int bh[2];    //8
  }class; 
  这联合体的 最大类型 是 int ,占用8个字节,因此这个联合体是8个字节对齐。

struct stu 
{ 
  union{          //6
    char bj[5];
    int bh[2];
  }class; 
  char xm[8];     //8 
  float cj;       //4
}xc; 
这个结构体,首先放下 6个字节 给 联合体,然后 后续的 8个字节给了 数组。共14个字节
float 类型,是 4字节对齐 ,因此 前面还得补充 2个字节。14 + 2 + 4 = 20.
本题的答案为 20

参考链接:关于C语言中联合体union占用内存的情况

6. 结构体的元素偏移问题

【每日一题讲解】结构体的元素偏移问题
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1113&fromuid=32424
(出处: 野火电子论坛)

//若 int 占 2 个字节,char 占 1 个字节,float 占 4 个字节,则定义如下:
struct stu
{
  union{
    char bj[5];
    int bh[2];
  }class;<br>
  char xm[8];
  float cj;
}xc;
//若 xc 地址为0x1000 则求 &xm[0] 的值?

//A.0x1005
//B.0x1006
//C.0x1008
//D.0x100A

回答:C,要考虑到内存对齐的问题。union占用8个字节。
解析:

今天的题目,其实就是昨天的题目稍微改一下,如果昨天好好看过解答,今天就不会答错了。
【每日一题讲解】结构体的内存大小问题 - 软件设计区 - 野火初学123论坛 http://www.firebbs.cn/forum.php?mod=viewthread&tid=1111

大家从上面那帖子里看答案即可,关键的一点是 算出 联合体的 大小为 6,即 XM[0] 的位置 偏移为 6,从而得到
XM[0] 的地址 = 0x1000  + 6 = 0x1006

反思:题目开头注明了 int为2字节,则union中应该为1,2的倍数,故union为6.

7. 指针操作的问题

【每日一题讲解】指针操作的问题
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1134&fromuid=32424
(出处: 野火电子论坛)


long  *s = (long *)"chuxue123.com";
s++;
printf("%c",*(char *)s);

//运行结果是多少?
//A:h
//B:u
//C:x
//D:随机值,不确定

回答:C

解析:
long  *s = (long *)"chuxue123.com";
s++;
printf("%c",*(char *)s);
首先是 s 是 long 指针,指向 字符串 "chuxue123.com" 的 首地址。

s++ 后,s 是 long 指针(long 是 4个字节的),地址值就是 加 4 ,即 *(char *)s 就指向  "chuxue123.com"  的 u ,因此答案就是 B.u

反思:
sizeof(s)为4;但是s++或者s–,是根据typeof s来决定的。

8. -1和1的数值比较

【每日一题】-1和1的数值比较
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1932&fromuid=32424
(出处: 野火电子论坛)

int main()
{
    if(-1L > 1UL)
        printf("1\n");
    else
        printf("0\n");
    return 0;
}

回答:
-1为 1000 0000 0000 0000 0000 0000 0000 0001(原码)
反码为 1111 1111 1111 1111 1111 1111 1111 1110
补码为 1111 1111 1111 1111 1111 1111 1111 1111
即0xFFFFFFFF
而1为 0000 0000 0000 0000 0000 0000 0000 0001
反码为0000 0000 0000 0000 0000 0000 0000 0001
补码为:0000 0000 0000 0000 0000 0000 0000 0001
即0x00000001
故 -1L > 1UL

解析:
常量后面接L表示long型存储,U表示unsigned,F表示float

此题的关键是 -1L > 1UL

一个是long型,一个是unsigned long型,无符号和有符号的比较,那么编译器会把有符号的转换为无符号。
-1L = 0xFFFFFFFF
1UL = 0x00000001

因为 0xFFFFFFFF > 0x00000001 ,所以 -1L > 1UL

运行结果为:打印1

9. -1和1的数值比较2

【每日一题】-1和1的数值比较2
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1956&fromuid=32424
(出处: 野火电子论坛)

int main()
{
    if(-1 > 1)
        printf("1\n");
    else
        printf("0\n");
    return 0;
}

回答:
输出为1

解析:
跟昨天的题目不同:http://www.firebbs.cn/forum.php?mod=viewthread&tid=1932
-1和1都没声明存储类型,编译器默认按int型来存储。
int型 -1 小于 1,因此if条件不成立,执行else里的语句。

运行结果为:打印0

10. 指针的用法

【每日一题讲解】指针的用法
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1206&fromuid=32424
(出处: 野火电子论坛)

int *p;
int  a = 10;
*p = a;
printf("%d",*p);
运行结果是什么?

A.10
B.a 的 地址值
C.编译错误
D.运行异常
``

回答:应该是 10 。

解析:
今天的题目,考的是 野指针

野指针的成因主要有三种:
一、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。
二、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
三、指针操作超越了变量的作用范围。比如不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。


此题就是 指针 还没初始化,因此为 野指针,执行 *p = a; 这步时,运行 会异常。

反思:啊啊啊啊,指针的初始化啊啊啊

11. 数组名加减的问题

【每日一题讲解】数组名加减的问题
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1143&fromuid=32424
(出处: 野火电子论坛)


//运行以下程序,求运算结果

int a[4]={1,2,3,4};
int *ptr=(int*)(&a+1);
printf("%d",*(ptr-1));

//可供选择的答案:
//A.1
//B.2
//C.4
//D.随机值

回答:蒙一个 A。

这题目的关键地方在于这句话:
&a+1
复制代码
大家能不能区分下面这语句和上面那语句的区别:
a+1
复制代码
两者之前的意思是完全不同的,大家看下面代码注释把
int a[4]={1,2,3,4};  // a:数组首元素的首地址,即 a[0];    &a:数组的首地址  
int *ptr=(int*)(&a+1); // a+1:数组的下一元素的首地址,即 a[1];
                       // &a+1:下一数组的首地址,即(int)&a+4*sizeof(int) ,ptr 等效于  &a[4]
printf("%d",*(ptr-1));//ptr-1 就  等效于   &a[3]  ,加上* 取内容,那么结果就是 4
复制代码

参考链接:c语言那些细节之a+1和&a+1的区别

12. %

【每日一题讲解】设有以下语句:int x=10;x+=3+x%(-3),则x的值是: 
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1075&fromuid=32424
(出处: 野火电子论坛)

题目:
设有以下语句:int x=10;x+=3+x%(-3),则x的值是:
A.11
B.12
C.14
D.15

回答:14

x+=3+x%(-3)
首先是 求得 x%(-3) 的值 , x = 10 ,是正数,因此 %(-3 )后 结果为1
很多同学理解有误,以为是 -1.

求余运算,除数和被除数都可以是负的,求余后的值 与 被除数 的符号相同,比如 -10 % -3 = -1, 10 % -3 = 1.

知道这个 结果后,后面的运算就简单了:
x += 3 + 1 ,即 x = x + (3 + 1) = 14

答案为 C

13. 函数的实参个数

【每日一思】函数的实参个数
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1325&fromuid=32424
(出处: 野火电子论坛)

fun((exp1,exp2),(exp3,exp4,exp5));  //一共有几个 实参?

回答:不知道。。。

2个,这题目考的是 逗号表达式。
真正有效的是 :fun(exp2,exp5); 

14. 逗号表达式的使用

【每日一题讲解】逗号表达式的使用
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1224&fromuid=32424
(出处: 野火电子论坛)

int a,b;
a=b=1;
b=a++,b++,++a;
求b的结果是多少?

回答:2

关于逗号表达式的使用,可参考之前的帖子:

【每日一题讲解】计算式子的结果 - 软件设计区 - 野火初学123论坛 http://firebbs.cn/forum.php?mod=viewthread&tid=1214

大家注意一点,就是 逗号 的优先级是最低的,因此,本题的结果就是 先执行 b=a++ ,此时 b 为 1 。 然后 b++ ,所以 b 的值 最终为 2

本题答案就是 2

15. 计算式子的结果

【每日一题讲解】计算式子的结果
http://firebbs.cn/forum.php?mod=viewthread&tid=1214&fromuid=32424
(出处: 野火电子论坛)

char a=8;
printf("%d",(a=3*5,a*4));

//计算式子的结果
//A.15
//B.32
//C.60
//D.编译出错

回答:不知道

c语言提供一种特殊的运算符,逗号运算符,优先级别最低,它将两式联接起来,如:(3+5,6+8)称为逗号表达式,其求解过程先表达式1,后表达式2,整个表达式值是表达式2的值,如:(3+5,6+8)的值是14。(a=3*5,a*4)的值是60。

表达式说明
表达式1,表达式2,表达式3,...... ,表达式n
逗号表达式的要领:
(1) 逗号表达式的运算过程为:从左往右逐个计算表达式。
(2) 逗号表达式作为一个整体,它的值为最后一个表达式(也即表达式n)的值。
(3) 逗号运算符的优先级别在所有运算符中最低。

16. 如何输出源文件的文件名和当前执行的行数

【每日一思】如何输出源文件的文件名和当前执行的行数
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1314&fromuid=32424
(出处: 野火电子论坛)

如何输出源文件的文件名和当前执行的行数

解析:

C语言 有 几个 宏定义是 大家需要掌握的:
__FILE__ 包含当前程序文件名的字符串
__LINE__  表示当前行号的整数
__DATE__ 包含当前日期的字符串
__STDC__  如果编译器遵循ANSI C标准,它就是个非零值
__TIME__ 包含当前时间的字符串


这题目考的就是 __FILE__  和 __LINE__  。(注意,是两边各两个下划线)

17. 逗号表达式的用法

【每日一题讲解】逗号表达式的用法
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1168&fromuid=32424
(出处: 野火电子论坛)

int a [3][2]={(0,1),(2,3),(4,5)};
int *p;
p=a [0];
printf("%d",p[0]);
注意,这题目很容易错的哦

A.0
B.1
C.2
D.编译出错

回答:
不知道。。。

这是一个逗号表达式,逗号表达式的值=最后一个值,因此数组真正的值为:
int a [3][2]={(1,3,5};
复制代码
而 a[0] 的地址 值就是 a[0][0]地址 值

因此结果为 1 。

很多同学误以为是 0,注意,这里是 括号 () ,而不是 花括号 {}
很多初学者都把 花括号写成 括号,导致 计算结果与想象的不一样

18.指针的数组形式

【每日一题】指针的数组形式
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1890&fromuid=32424
(出处: 野火电子论坛)

int main()
{
    int * p = 0;        //sizeof(int) = 4
    printf("&(p[9])=%d\n",&(p[9]));
    return 0;
}

回答:0+4*9=36

p[9] 等效于 *(p+9)
&(p[9]) 等效于 (p+9)

由于sizeof(int)的值为4,因此指针的偏移值就为4。指针加1,等效于指针值加4。

(p+9) 后的值为 0 + 4*9 = 36
所以运算结果为 &(p[9])=36

19. ++的用法及入栈顺序

【每日一题讲解】++的用法及入栈顺序
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1230&fromuid=32424
(出处: 野火电子论坛)

int a=0,b=0;
printf("%d,%d,%d",a++,++b,a+b);
求打印结果

A.0,1,0
B.0,1,2
C.1,0,0
D.1,0,2

回答:B

解析:
这题其实 主要 考 的是 printf 函数 的入栈顺序。
可变参数的 函数,入栈顺序都是 从 右 往 左 。
因此题目,先 运行 a+b ,即 第三个 值为 0.
再执行 ++b ,先自加 ,再 赋值,因此 第二个 值为 1。
然后执行 a++ ,先赋值再自加,因此第一个值为 0
本题答案就是 A
提示一下, printf 函数 运行的时候,出栈顺序是 从 左往右

20. 预处理器- Preprocessor

【每日一题】 预处理器- Preprocessor [嵌入式校园招聘笔试题]
http://www.firebbs.cn/forum.php?mod=viewthread&tid=6398&fromuid=32424
(出处: 野火电子论坛)

知识点:预处理器(Preprocessor)
题目:用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

回答:
#define SECOND_PER_YEAR (3652460*60)

解析:
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
1、#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
2、懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒
   而不是计算出实际的值,是更清晰而没有代价的。
3、意识到这个表达式将使一个16位机的整型数溢出,因此要用到长整型符号L,
   告诉编译器这个常数是的长整型数。
4、如果你在你的表达式中用到UL(表示无符号长整型)。

20. 类型转换的用法

【每日一题讲解】类型转换的用法
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1172&fromuid=32424
(出处: 野火电子论坛)

int8 i = -1;
uint16 t = i;
printf("%d",t);

A.0
B.1
C.255
D.65535

回答:
1000 0001
1111 1110
1111 1111
0000 0000 1111 1111

解析:
这题目考的是类型转换
i 是 int8 类型的,赋值为 -1;

把此值给 uint16 类型的 变量 t ,结果就等于 (uint16)(-1) = 0xFFFF,即65535,答案为D

反思:
1000 0000 0000 0001
1111 1111 1111 1110
1111 1111 1111 1111

21.

【每日一题讲解】数组指针的大小问题
http://www.firebbs.cn/forum.php?mod=viewthread&tid=1260&fromuid=32424
(出处: 野火电子论坛)

int a[5]; 
sizeof(&a) 的值是多少?

A.4
B.5
C.20
D.不同编译器和平台下,结果不一样

回答:
4

解析:
在 linux 下,对数组取地址,会当作指针来求大小,即 4
在 window下,对数组取地址,会当作整个数组来求大小,即20
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值