C语言常用面试题_2015.5.6(1)

1.用宏定义写swap(x,y)函数

#define  swap(x,y)   {x=x+y;y=x-y;x=x-y;} //不是特别严谨。


2.什么是预编译,何时需要预编译?

预编译是在函数执行前的预处理工作,以#号开始,不以分号结束,不是C语言的程序语句。何时需要:为了增加程序可读性,进行的名字替换;不需要经常改动的代码体;经常被使用的函数模块和文件。


3.char * const p;charconst *p;constchar *p 有什么区别?

char *const p是常量指针,指针p的值不可修改,指向char类型的数据;

charconst *p指向常量的指针,指针p的值可变,指向的数据为charconst类型,不可变。

const char *p charconst *p一样。


4.解释下列输出结果:

char str1[] ="abc";

char str2[] ="abc";

constchar str3[] ="abc";

constchar str4[] ="abc";

constchar *str5 ="abc";

constchar *str6 ="abc";

char *str7 ="abc";

char *str8 ="abc";

printf("%d,%d,%d,%d\n",str1==str2,str3==str4,str5==str6,str7==str8);

0011

str1,str2,str3,str4为数组变量,在内存空间中会独立的开辟存储空间,内存地址各不相同;

str5,str6,str7,str8为指向字符常量的指针,内存地址都指向同一个字符常量“abc”,内存地址相同;


5.sizeof()的用法,指针和数组名的使用?

#include<stdio.h>

void uppercase(char str[])

{

   printf("函数内%d\n",sizeof(str));

}

int main()

{

   char str[] ="ab";

   printf("函数外%d\n",sizeof(str));

    uppercase(str);

}

//函数外3,函数内str代表的是数组

//函数内8,函数外str代表的是指针,数组名作为函数参数使用时退化为指针。


6.指出下列代码的输出结果。

#include<stdio.h>

int main()

{

    int a[5]={1,2,3,4,5};

    int *p= (int *)(&a+1);

    printf("%d,%d\n",*(a+1),*(p-1));

    //printf("%d,%d,%d,%d,%d,%d\n",&a[0],&a[1],&a[2],&a[3],&a[4],&a+1);

}

输出2,5

//*(a+1)就是a[1]

//&a+1是地址偏移一个a数组的大小,这个概念至关重要。&a[0]+1是地址偏移一个a[0]大小的位置,&a+1是地址偏移一个a[]数组


7.下列代码存在什么问题

a.

#include<stdio.h>

int main()

{

   char a;

   char *str=&a;

   strcpy(str,"hello");

   printf(str);

   return0;

}

没有为str分配内存空间,可以正确显示结果,但是存在安全问题。会存在越界进行内存读写导致程序崩溃。

b.

#include<stdio.h>

int main()

{

   char *s="AAA";

   printf("%s\n",s);

    s[0]='B';

   printf("%s\n",s);

}

指针s指向字符常量,声明时应该用const char *来定义声明,而且字符常量是不可修改的。


8.写一个标准宏,输入两个参数,并输出较小的那个

#define min(x,y) ((x)>(y)?(y):(x))


9.C和C++中struct的区别是什么?

C中的struct不可以含有成员函数,C++中可以。

C++中struct和class的区别,在于默认的存取权限不同,struct默认为public,class默认为private


10.程序存在的问题?

#include <stdio.h> 

#include <stdlib.h>  

void getmemory(char *p)

{

    p=(char *) malloc(100);

}

int main()

{

    char *str=NULL;

    getmemory(str);  //不能修改实参str的值,str仍然为0

    strcpy(str,"hello world");

    printf("%s/n",str);

    free(str);

    return 0;

}


11.程序存在的问题

int main()

{

    char str[10];

    strcpy(str, "0123456789");

    printf("%s\n",str);

    return 0;

}

内存越界,字符串长度为11,超过了str的长度。可以正常显示,但是会覆盖掉其他的数据,很危险。


12.C语言指针

int *p[n] 指针数组,数组中每个元素都是指向int数据的指针;

int (*p)[n] 二级指针,p是指向一维数组的指针,这个一维数组有n个int数据变量;

int *p() 返回指针的函数;

int (*p)() 指向函数的指针;


13.数组内存越界

#define MAX 255 

int main()

{

   unsignedchar A[MAX],i;

   for (i=0;i<=MAX;i++) A=i;

}

内存越界,会导致无限循环


14.memset,memcpy,strcpy的区别?

memset 将一段内存中,填充给定的值,通常用于内存初始化,是对较大结构体和数组清零最快的一种方式;

memcpy 将内存中的一段数据拷贝到另一个位置;

strcpy 只适合拷贝字符串,遇到'\0’就结束;


15.不用库函数实现strcpy函数

#include <stdio.h>

#include <assert.h>


char *strcpy(char *strDest,constchar *strSrc)

{

   assert(strDest!=NULL && strSrc!=NULL);

   char *address = strDest;

   while ((*strDest++ = *strSrc++) !='\0')  {

        ;

    }

   return address;

}

int main()

{

   char str[10];

   strcpy(str,"012345678");

   printf("%s\n",str);

   return0;

}

几点说明:

1.注意编程风格,使用strDest, strSrc这样增强可读性的名字。

2.使用断言来检验输入参数的有效性,如果没有对传入参数strDeststrSrc进行检查,一但它们中有一个为NULL,立死!  assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回false,则终止程序执行。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。

3.使用const来约束strSrc,提高程序的健壮性。如果函数体内的语句试图改动strSrc的内容,编译器将指出错误。

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

这是为了实现链式表达。增加了函数的附加值。同样功能的函数,如果能合理地提高的可用性,自然就更加理想


16.ASSERT()是干什么用的?

:ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。例如,变量n在程序中不应该为0,如果为0可能导致错误,你可以这样写程序:  ......  ASSERT( n != 0); k = 10/ n; ......  ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。 assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。


17.Debug和Release版本的区别?

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。 

Debug 和 Release 的真正区别,在于一组编译选项。 
Debug 版本   
参数       含义   
/MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库)   
/Od 关闭优化开关   
/D "_DEBUG" 相当于 #define _DEBUG,打开编译调试代码开关(主要针对assert函数)   
/ZI   
创建 Edit and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译   
GZ 可以帮助捕获内存错误  

Release 版本 参数含义   
/MD /ML 或 /MT 使用发布版本的运行时刻函数库   
/O1 或 /O2 优化开关,使程序最小或最快   
/D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数)   
/GF 合并重复的字符串,并将字符串常量放到只读内存,防止被修改  

Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值