阶段性测试-C语言与数据结构

苏嵌阶段性测试-C语言与数据结构

一、简答

1. 用预处理指令#define 声明一个常数,用以表明 1 年中有多少秒(忽略闰年 问题);写一个"标准"宏 MIN 函数 ,这个宏输入两个参数并返回较小的一个

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

2. 用变量 a 给出下面的定义

a) 一个整型数(An integer)

b)一个指向整型数的指针( A pointer to an integer)

c)一个指向指针的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an integer )

d)一个有 10 个整型数的数组( An array of 10 integers)

e) 一个有 10 个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)

f) 一个指向有 10 个整型数组的指针( A pointer to an array of 10 integers)

g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)

h)一个有 10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返 回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )

a) int a;
b) int* a;
c) int** a;
d) int a[10];
e) int* a[10];
f) int (*a)[10];
g) int (*a)(int);
h) int (*a[10])(int);

3. 关键字 volatile 有什么含意?并给出三个不同的例子。

含义:指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值,即不是从寄存器里取备份值,而是去该地址内存存储的值.

例1:

例2:

例3:

4. 结构与联合有和区别?

5. 求下面函数的返回值(微软)

int func(x)
{
    int countx = 0;
    while(x)
   {
        countx ++;
        x = x&(x-1);
   }
   return countx;
}

解:

返回值 = x转化为二进制后包含1的个数

6. 数组与指针的区别?

1)形态不同:指针表示C语言中某种数据类型的数据存储的内存地址,数组表示若干个相同C语言数据类型的元素在连续内存中储存的一种形态。

2)定义的时机不同:指针需要到运行的时候才知道自己指向哪块内存空间,数组则是在编译的时候便已经被确定下来

3)访问方式不同:指针需要间接才能知道自己的身份(通过读取其保存的地址),数组的数组名直接代表其身份(数组在内存中的地址)

数组与指针也有相同的时候,C语言标准对于数组和指针何时相同定义几条规则:

1)表达式中的数组名(与声明不同)被编译器当作一个指向数组第一个元素的指针。

2)下标总是与指针的偏移量相同。

3)在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。

7. 移位操作为何最好使用无符号数?

C标准没有规定有符号数的右移如何处理。那么对于有符号数的右移处理,就由编译器决定。这是不希望看到的

因此移位操作最好使用无符号数

8. 关键字 static 的作用是什么?

static关键字可以修饰变量也可以修饰函数,主要看修饰的是全局变量和函数还是修饰的是函数内部的局部变量。且被static修饰的变量位静态变量,需要保留上一次被调用结束时的值。

1)当static关键字修饰局部变量的时候可以延长变量的生命周期,在该函数被调用的过程中维持其值不变。

2)当static关键字修饰全局变量和函数的时候,该全局变量和函数只能在该文件被访问,即使其他文件使用extern关键字做声明也不能调用

9. #include 与 #include "file.h"的区别?

#include: 编译器会直接在标准的函数库(系统目录)中搜索,linux系统的库目录为lib和/usr/lib

#include “file.h”: 编译器从用户的工作路径开始搜索 file. h,然后再去标准函数库搜索

10. 下面 const 的含义如何?

const int *a; 
int const *a;
int * const a;
int const * const a;

第一种和第二种表示:指针可以保存不同的地址,但不能改变其地址所保存的值

第三种表示:指针所保存的地址一旦确定,不能改变,但可以改变其地址所保存的值

第四种表示:指针所保存的地址一旦确定,其保存的地址和值都不可改变

11. 什么是内存操作越界?

内存越界分两种:

  1. 读越界:读了不属于自己的数据,如果所读的内存地址是无效的,程序和立刻崩溃,如果所读内存地址是有效的,在读的时候不会马上出现问题,但由于读到的数据是随机的,因此它会造成不可预料的后果。(数组下标越界)
  2. 写越界:又称为缓冲区溢出,所写入的数据对别的程序来说是随机的

12. 什么是内存泄漏? 造成内存泄漏的原因有哪些?

**内存泄漏:**程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果

原因

1)指针重新赋值

2)错误的内存释放

3)返回值的不正确处理

4)在内存分配后忘记使用 free 进行释放

13. 请说出 const 与#define 相比,有何优点?

1)#define只是单纯的字符串替换,没有类型检查。const有对应的数据类型,需要做判断,可避免低级错误

2)#define有多少次使用就有多少次替换,内存中有若干备份,const在程序运行种只有一次备份,用const可提高效率

3)#define只能作用于预处理阶段,const在编译、运行时起作用

4)#define不能进行代码调试,const可以进行调试

14. 函数式宏定义和函数调用有什么不同?

  1. 函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查

  2. 调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同

15. C 语言中参数传递有什么特点? 我们应当注意些什么?

特点: C语言的参数传递有值传递址传递两种方式

值传递:只把变量的值传递给了函数的形参,函数内对形参的改变不会影响到函数外部变量的值

址传递:将变量的地址传递给函数的形参指针,其指针指向的是真实的外部变量地址,能对函数外变量的值做改变

16. 编写不使用中间变量完成两个数交换的函数,至少两种方法完成

//方法一
void swap1(int *left,int *right)
{
*left = *left + *right;
*right = *left - *right;
*left = *left - *right;
}
//方法二
void swap2(int *left,int *right)
{
*left = *left ^ *right;
*right = *left ^ *right;
*left = *left ^ *right;
}

17. goto 语句有什么特点? 在 C 语言中对 goto 的使用有什么注意事项?

特点:

1)goto语句的标签必须是一个合法的C言语标识符

2)goto语句的本质是无条件跳转指令

3)goto语句的优质是可以在代码段中的任意位置跳转。

注意事项:

需注意死循环的情况,保证不要出现死循环现象

18. 使用 swicth 的注意事项

  1. switch语句的表达式类型

    1)可以放一个整数的变量

    2)可以放一个整形常量

    3)可以放一个返回值是整形的表达式

    4)可以放可以转为int类型的表达式

  2. case语句可以有多个
    0) case语句格式: case 常量表达式: (空格和冒号不能省)

    1. 可以是常量 case 10:
    2. 如果放表达式,那么只可以是常量表达式 case 5+5:
    3. default语句的位置可以任意放
    4. case的穿透问题,同样适用于 default
    5. 如果default语句放到 switch语句的最后,可以不加break
      如果不是放到最后,是必须加上break的
    6. case 后面不能是实数 (单精度,双精度都不可以)
    7. case 语句之后,默认的第一句话不能定义定义变量
      如果第一句话非要定义,应该加上大括号

19. 嵌入式系统中经常要用到无限循环,你怎么样用 C 编写死循环呢?

//方法一
while(1)
{
	printf(“死循环”);
}
//方法二
for( ; ; )
{
	printf("死循环”);
}
//方法三
top:
…
goto top;

20. 哪个更好一些为什么?

typedef unsigned char BYTE;
#define STRING char *;

typedef 更好一些,以如上代码示范:

STRING a,b;

在预处理时,#define会进行宏替换,则会变成如下代码:

char *a,b;

这样a是char *类型,而b是char类型,这不是我们想看到的

21. C 语言对左值有什么限制?

  1. 一个左值中必定可以解析出对应对象的地址,除非该对象是位字段(bit-field)或者被声明为寄存器存储类。生成左值的运算符包括下标运算符(subscript operator)[]和间接运算符(indirection operator)*

  2. 赋值运算左边的操作数,以及任何自增或自减运算符(++ 和 --)的操作数,不仅应该是左值,还应该是可修改的左值。可修改的左值,其类型不可以被声明为限定符 const,并且可修改的左值不能是数组类型。如果可修改的左值所表示的对象是结构或联合类型,那么它的元素都不可以被声明(不管是直接地或间接地)为具有限定符 const 的类型

22. 程序调试中常见的错误有哪些?

  1. 引号、逗号、分号错误(中文英文逗号、引号等是不同的,注意切换输入法)

  2. 变量未定义

  3. 变量赋值、运算时显示类型不匹配

23. 已知函数 strcpy 的原型是:

char *strcpy(char *strDest, const char *strSrc);

a. 不调用 C 的字符串库函数,请编写函数 strcpy

#include <assert.h>
char *strcpy(char *strDest, const char *strSrc)
{
  assert(strDest != NULL);
  assert(strSrc != NULL);
  
  char *tempDest = strDest;
  
  while(strDest++ = *strSrc++)
  {
    ;
  }
  
  return tempDest;
}

b. strcpy 能把 strSrc 的内容复制到 strDest,为什么还要 char * 类型的返回 值?

其目的是为了让其返回值还能作为另一个函数的参数,形成链式操作

24. 什么是野指针?如何避免野指针?

野指针:定义了指针却没有初始化也没有赋值,既是指针没有指向一块明确的内存空间都属于野指针

避免野指针的方法:最根本的方法就是程序员具有良好的编码规范,再定义一个指针的时候记得初始化,在指针不用的时候记得赋值为NULL,在使用指针的时候需要先判空等等

25. 什么是函数指针?为什么能够使用函数指针,举出一个函数指针使用的例子

函数指针:在定义一个函数的时候,系统编译时会为函数分配一段内存空间,而这段内存空间的首地址称为这个函数的地址。而函数名就代表这个地址。而保存函数首地址的变量是一个指针,这个指针变量便是函数指针变量,也叫做函数指针。

为什么能够使用函数指针?

因为函数指针可以保存函数首地址,而函数名代表首地址,因此可以通过保存函数首地址的方式调用函数

一个简单的例子:

int func(int x,int y)
{
  return x + y;
}

int main()
{
  int (*p)(int,int); 		//定义函数指针变量
  p = func;			//将func函数首地址保存到函数指针p种
  printf("%d\n",(*p)(a,2));	//通过*取值运算访问函数,进行函数调用
}

26. 下列语句的作用是什么?

#ifndef HEADER_FILENAME
#define HEADER_FILENAME
/* body of header */
#endif

防止头文件被重复引用,头文件的重复引用会增加编译工作的工作量,降低编译效率,虽不会引起太大的问题,但对于比较大的工程来说,编译效率低下还是非常痛苦的

27. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

有区别。全局变量保存在内存的全局存储区中,占用静态的存储单元;局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。

28. 如何引用一个已经定义过的全局变量?

1)用extern关键字申明在其他地方定义的全局变量

2)用引用头文件的方式:

可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接才不会出错

29. 语句 for( ;1 ;)有什么问题?它是什么意思?

死循环。

在C/C++中,非0是true,0是false;
for循环中的初始化条件、循环条件和迭代语句都可以为空。
for(;1;)中,循环条件结果需要是boolean类型,但1为int类型,不能自动转为boolean类型,故编译报错

30. 设有以下说明和定义:

typedef union {long i; int k[5]; char c;} DATE; //24

struct data //40
{ 
  int cat;
	DATE cow;
	double dog;
}too;
DATE max;

则语句 printf(“%ld”,sizeof(struct data) + sizeof(max));的执行结果是多 少?

64

31. 队列和栈有什么区别?

32. 用两个栈实现一个队列的功能?要求给出算法和思路!

33. 堆和栈的区别?

34. 要对绝对地址 0x100000 赋值,我们可以用

(unsigned int*)0x100000 = 1234;

那么要是想让程序跳转到绝对地址是 0x100000 去执行,应该怎么做?

25. 嵌入式系统中动态分配内存可能发生的问题有哪些?

二、找错误并改正

指出下列程序中的问题,说明原因

试题 1:

void GetMemory( char *p )
{
	p = (char *) malloc( 100 );
}
void Test( void ) 
{
	char *str = NULL;
	GetMemory( str ); 
	strcpy( str, "hello world" );
	printf( str );
} 

试题 2:

char *GetMemory( void )
{ 
	char p[] = "hello world"; 
	return p; 
}
void Test( void )
{ 
	char *str = NULL; 
	str = GetMemory(); 
	printf(“%s”,str ); 
}

试题 3:

void GetMemory( char **p, int num )
{
	*p = (char *) malloc( num );
}
void Test( void )
{
	char *str = NULL;
	GetMemory( &str, 100 );
	strcpy( str, "hello" ); 
	printf( str ); 
}

三、编程题

1. 单连表的建立,把’a’–'z’26 个字母插入到链表中,并且逆序,还要打印!

2. 写一个函数,它的原形是

int continumax(char *outputstr,char *intputstr);

功能:在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最 长 数 字 串 付 给 其 中 一 个 函 数 参 数 outputstr 所指内存。

例如: "abcd12345ed125ss123456789"的首地址传给 intputstr 后,函数将返回 9,outputstr 所指的值为 123456789;

#include <stdio.h>
#include <string.h>
#define MAX_SIZE 100
int continumax(char *outputstr, char *intputstr)
{
	//记录最长字符串长度与首地址
int maxlen = 0;
char* maxstr = 0;

while (*intputstr != '\0')
{    
	//记录数字串个数与首地址
   int count = 0;
   char * tempstr = intputstr;

   while (*intputstr >= '0' && *intputstr <= '9')
   {  
      count++;
      intputstr++;
   }
	//判断数字串是否为最长串,并保存其长度与首地址
   if (count > maxlen)
   {    
      maxlen = count;
      maxstr = tempstr;
   }
   intputstr++;
}
	//将最长数字串拷贝到outputstr
for (int i=0; i<maxlen; i++)
{  
   outputstr[i] = maxstr[i];
}

return maxlen;
}

int main() {

char intputstr[MAX_SIZE];
char outputstr[MAX_SIZE];

printf("Please input intputstr:\n");
scanf("%s",intputstr);

int maxlen = continumax(outputstr,intputstr);

printf("ans = %d\n",maxlen);
printf("maxlen = %s\n",outputstr);

return 0;
}

测试结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值