欢迎来到个人简历网!永久域名:gerenjianli.cn (个人简历全拼+cn)
当前位置:首页 > 范文大全 > 实用文>浅谈C的应用与常见error

浅谈C的应用与常见error

2023-07-29 08:27:32 收藏本文 下载本文

“阿北是江湖骗子”通过精心收集,向本站投稿了5篇浅谈C的应用与常见error,下面是小编为大家准备的浅谈C的应用与常见error,欢迎阅读借鉴。

浅谈C的应用与常见error

篇1:浅谈C的应用与常见error

我下面所写的都是用“.c”后缀的,“.c”后缀是c源文件的后缀,“.cpp”后缀是c++源文件的后缀。c++继承了c语言的一些特性,所以有些bug在“.cpp”里是可以通过的。

1、scanf你真的了解了么?;

scanf()是有返回值的,返回值类型是int,这个你知道么?它返回了成功读入输入信息的个数。

那么我们可以利用它来做什么呢?

非零即真,这句话你一定听说过,而且不止一次。那么我们看一下下面的代码。

int a;

while (scanf(“%d”, &a) == 0)

{

printf(“请输入合法字符:”);

}

这样写代码是不是好一点,再输入的同时判断了输入的是否正确。但这会使你进入一个死循环。为什么会这样呢?

我们在输入时,我们的键值需要一块缓冲区在存放键值,如果输入的键值不被scanf()接受,那么它会一直在缓冲区中,那么再仔细看一看上面的代码,你是不是明白了呢。

解决这个问题并不难,只要将输入的键值接受,他就不会在缓冲区中影响你的程序了。看看下面的代码,有没有豁然开朗,哇,scanf()还可以这么使用!

int a;

while (scanf(“%d”, &a) == 0)

{

getchar();

printf(“请输入合法字符:”);

}

2、你还在纠结while(),for();

初学者可能会纠结什么场合用while(),什么场合用for()。

在我看来,这根本不存不值得我去纠结,我们应该想的是使用哪个可以使程序更简单,别人更容易看懂。

while(),for()的本质都是循环,只是形式不一样而已。

int i = 0;int i;

while (i<10) for (i=0; i<10; i++)

{ {

i++;

} }

上面的代码当然是for()更简明一写,但1、中的例子却是使用while()。for()比while()在语句要多一些,这是你需要的么?

根据每个人的代码风格不同,不能统一要求使用for()或者while()。建议初学者可以两个都试一下,感觉他们之间的不同,写出漂亮的代码。

3、switch()你会使用么?

switch(n)

{

case 1:

break;

case 2:

break;

default:

}

你一直这么使用么?

我们都知道case 后面不加break,会一直执行下面的代码,直到代码全不执行完或者遇到break。

利用这个特性,我们是不是可以做一些其他的事,比如加法,一年有十二个月,我想算出4月6号是今年的第几天,你想到怎么使用了么?我们看一下下面的代码。

switch (month-1)

{

case 11: sumMonth += 30;

case 10: sumMonth += 31;

case 9: sumMonth += 30;

case 8: sumMonth += 31;

case 7: sumMonth += 31;

case 6: sumMonth += 30;

case 5: sumMonth += 31;

case 4: sumMonth += 30;

case 3: sumMonth += 31;

case 2:

if ((i%4==0 && i%100!=0) || i%400==0)

{

sumMonth += 29;

}

else

{

sumMonth += 28;

}

case 1: sumMonth += 31;

}

你看懂了么?只是提供一个思路,将我们思维打开,你会看见另一片天空。

你在case中定义过变量么?

case中为什么不能定义变量呢?

int a;

switch (a)

{

case 1:

int b;

break;

case 2:

b = 0;

break;

}

你这么任性,编译器怎么办!

那我们为什么不规定case 1定义的变量只能在case 1中使用呢?在6、变量作用域中你将会找到答案。

当然,我们不应该只局限于switch(),if() else也一样可以完成多重选择的任务,不过switch()内置3-999个标签,使用switch()的程序运行速度可能稍快一些,代码也更简洁。

4、if()的使用

我们都知道if()用于判断。那么当你判断两个字符相等时,你会怎么写?

int a;

if (a == 5)

如果是我,我会写成

int a;

if (5 == a)

功能是一样的,何必这么麻烦?我们在做一个项目时,不可能十行代码调试半个小时,当我们思维在键盘上飞舞时,我才体会到一个程序员的快乐。在我们正在体验这种快乐时,手误在所难免,如果写成if(a=5),这个错误够你找两天的。但是if(5=a),编译器就可以帮你找到。

当你想判断两个字符串是否相等时,你会不会这样写?

char c_c1[10] = “acdefg”;

char c_c2[10] = “qwerty”;

if (c_c1 == c_c2)或者if (c_c1[10] == c_c2[10])

总之都是不对的。字符串,数组,指针后面还会有所涉及,这里不做详谈。

比较两个字符串我们用到了C函数库中提供的strcmp()函数,它包含在头文件中,strcmp()返回了一个int类型的值,-1,0,1。0代表两个字符串相等,-1,1是由于字符之间的比较(ASCII)决定的。下面我看一个例子。

char c_ch[10] = “qwertyui” //最多可以存放9个字符,最后一位是”\0“

char *p_ch = “adfgf”

strcmp(c_ch, p_ch); //strcmp()中的两个参数是两个字符串的地址

strcmp(“qwertyui”, “adfgf”); //这样也是可以的,字符串存放的也是首字母的地址,后面会提到。

5、你知道头文件的作用么?

我们写代码都习惯把#include 最先写上,但你知道它的作用么?

#include :文件包含

当预处理器发现#include 指令后,就会寻找 中的文件名并把这个文件包含到你写的程序代码,替换源文件(就是你写的文件)中的#include。虽然你只写了一行代码,但是编译器却给你添加了很多代码。

包含了输入输出函数,所以在程序的调试阶段,他是不可少的。

#include “gaozy” 这类头文件你见过么?它与#include 又有哪些区别呢?包含的头文件,编译器会在系统目录中搜索。“”包含的头文件,编译器会先在当前工作目录中搜索,如果没有,再去系统目录中搜索。也可以简单的理解成C函数库里的函数在包含的头文件里,而我们自己写的函数则放在“”文件中。

6、变量作用域

int i;

while (1)

{

int i = 0;

printf(“%d”, i);

}

这样会报错么?当然不会,因为两个int i;并不在同一个作用域。

那么什么是作用域,怎么分辨作用域呢?

我们通常把一个{}内的代码看成在一个作用域。这也是为什么case里不可以定义变量的原因。

只有{}才可以分辨作用域么?

当然不是

while (1)

int i;

printf(“hellow world!”);

int i;自己单独在一个作用域中,printf()只会执行一次,当然这是一个死循环,不会执行到printf()。现在你有点略懂了么?跟while()相同的还有for(),if()

还有个问题你想过么?第一次循环定义一个 i,第二次循环又定义一个 i,这不重复定义了么?

当然不是,作用域内的变量是有生命周期的。也就是说,当第一次循环结束,你所定义的 i 的内存空间已经被释放。

7、伤脑筋的bug

你写过这样的程序么?

int i;

while (1)

{

int i = 0;

printf(“%d”, i);

int j;

}

编译器是这样报错的::\c\浅谈c.c(49) : error C2143: syntax error : missing ';' before 'type'

我英文不好,不理解这句话是什么意思,但是这段代码里根本不存在缺少;的情况。

我将代码粘到vs中,它是可以运行的。我一度怀疑是编译器出错了。但事实上编译器是很少出错的,纠结了很久,我突然想起来,c语言中规定,变量是必须在作用域的开始定义。vs210中,我用文件是后缀是.cpp的,就是是说c++允许在其他函数之后定义变量,而c对此则表示不支持。

你写的代码有没有之前运行正常,你只是修改了一点,语法上别没有出错。但编译器却报错了呢?

LINK : fatal error LNK1168: cannot open Debug/SMIS.exe for writing

之前遇见这个问题也是纠结很久,为什么一会儿可以编译,一会儿又让我等待呢?

这也不是编译器出错了。而是你执行了程序,没有关闭,对代码进行了修改,又要执行程序。

编译器如果会说话:“小子,你拿我开心呢吧,还能不能一起玩耍了。”

当你malloc时,要记得free啊,还有malloc之后跟上一个判断是有必要的。

p_head = (P_STUDENT)malloc(sizeof(STUDENT));

if (NULL == p_head)

{

printf(“动态内存分配失败,程序结束!”);

exit(-1);

}

如果没有if()判断的话,在内存分配失败时,运行程序会出错,而且很难找到错误原因。

8、字符串,数组,指针

谈到字符串、数组、指针,那么我们就不得不谈内存了。我们可以把内存理解成一排很长很长的房子,它是一个线性结构。房子里住着不同的人家,每个房子有不同编号。

人家对应的是计算机里定义的变量,房子编号对应的是变量所在地址。所以,我们每定义一个变量,都会占用一套房子,当房子被全部占用时,你的电脑就崩溃了。当然,我们电脑的内存还是很大的。下面来看看字符串、数组、指针之间的关系。

字符串以“/0”结束,所以字符串长度要在实际长度上+1

数组名就是数组首元素的地址

char ch[10] = “asdfg”; //ch[10]是定长数组

char ch[] = “asdfg”; //ch[]没有规定长度,但是在定义时必须初始化

char *p_ch = “asdfg”; //指针指向字符串的首地址

这三种定义字符串的方法差不多。ch和p_ch都是地址。

数组定义之后不可改变,指针还可以指向其他地址,但要注意内存泄露。

9、指针与地址

有些书上说指针就是地址,其实这种说法并不准确。

那么指针是什么,地址又是什么?

首先地址就是地址,物理内存的编号。

指针是一个变量,这个变量存放的内容是内存的物理地址。就像int i; i 是一个变量,存放一个 i 值。指针变量也存放一个指针值,这个值是一块物理内存的地址。

其实指针是地址还是变量并不影响我们对指针的使用。

10、你用过宏么?

#define MAX 60

就是MAX = 60;的意思,之后的代码中MAX都等于60。宏使我们的程序维护更简单,也更容易理解。

11、malloc与free

有人说new跟delete更强大,但我并这么认为,new和delete是c++中的运算符,提供了对对象的操作。而malloc和free是c语言中用来进行动态内存分配的,不具备可比性。

C语言是面向过程的程序设计,根本没有对象的概念。

篇2:商务英语常见词汇大――“C”

下面是给大家汇总的商务英语常见词汇“C”开头的部分。

categorization 分门别类

Caterpillar Tractor 卡特皮勒公司

Cathay Airlines 国泰航空公司

CBS Records 唱片公司

CBS 哥伦比亚广播公司

centralization 集中化

chameleons/followers 变色龙/跟随者

channel alternatives 可选择的营销渠道

channel conflicts 渠道冲突

channel decisions 渠道决策

channel functions 渠道功能

channel institutions 渠道组织结构

channel management 渠道管理

channel objectives 渠道目标

cable TV 有线电视

Cadillac 凯迪拉克

Campbell's Soup 金宝汤业公司

capital gains 资本收益

capital invested in product 产品投入资本

Carnival 嘉年华

cash cows 现金牛类

cash discounts 现金折扣

catalogue sales 目录销售

categorization of perception 感知分类

channel of distribution 分销渠道

channel power 渠道权力

channel-control strategies 渠道控制战略

channel-design decisions 渠道设计决策

channel-management decisions 渠道管理决策

channels of communication 传播渠道

Charles Snow 查尔斯・斯诺

Cherokee 切诺基

chevrolet 雪佛莱

choice criteria 选择标准

Christian Dior 克里斯汀・迪奥(世界著名时装品牌)

Chrysler 克莱斯勒

Citi Corp 花旗银行

closing a sale 结束销售

clothing retailers 服装零售商

CNN 美国有线新闻网

co-branding 联合品牌

code of ethics (职业)道德标准

coercive power 强制权

cognitive dissonance 认识的不协调

Colgate-Palmolive 高露洁

collection of data 数据收集

collection 收款

co-marketing alliances 联合营销联盟

combination compensation plan 结合式薪酬方案

Comdex 计算机展销会

commercialization 商业化

commitment 承诺

communication channels 传播渠道

communication process 传播过程

communication 信息交流/沟通

communications media 传播媒体

company personnel 公司员工

competitive parity promotion budgeting 竞争均势促销预算法

competitive strategy 竞争战略

competitive strength 竞争优势/能力

competitor analysis 竞争者分析

complaint handling 投诉处理

component materials and parts markets 组成材料和零部件市场

computerized ordering 计算机化的订购

conclusive research 确定性研究

conditions of demand 需求情况

conflict and resolution strategies 冲突和解决战略

conformance to specifications 与规格一致

conformance 一致性

confrontation strategy 对抗战略

conjoint measurement 联合测度法

conjunctive model 联合模型

consumer decision-making 消费者(购买)决策

consumer goods channels 消费品分销渠道

Consumer Goods Pricing Act, USA 美国消费品定价法案

consumer goods 消费品

consumer markets 消费品市场

consumer needs 消费者需求

consumer packaged-goods firms 消费者包装食品公司

consumer promotion 消费者促销

consumer tests 消费者测试

consumer/household market 消费者/家庭市场

consumers' perceptions 消费者感知

consumption 消费

contests 竞赛

contingency planning 权变计划

contract construction 契约建筑业

contract manufacturing 契约制造业

contraction/strategic withdrawal strategy 收缩/战略性撤退战略

contractual entry modes 契约式进入模式

corollary-data method 推定数据法

corporate HQ 公司总部

corporate scope 公司(经营)范围

corporate strategy 公司战略

corporate vertical marketing systems 公司式垂直营销系统

corporate/institutional advertising 团体/社会公共机构广告

corrective action 矫正行动

cost analysis 成本分析

cost effectiveness 成本有效性

contractual vertical marketing systems 合约式垂直营销系统

contribution margin analysis 边际贡献(贡献毛利)分析

contributrion margin 边际贡献

control strategies 控制战略

convenience food stores 便利食品商店

convenience goods 便利品

convenience 服务的便利性

Cool Whip 清凉维普

co-operative advertising 合作性广告

co-ordination and conflict resolution 协调与冲突解决

co-production 合作生产

core benefit proposition (CBP) 核心利益方案/提议

cost leadership strategy 成本领先战略

cost of capital 资本成本

cost of goods sold (COGS) 产品销售成本

cost reductions 降低成本产品

cost-and-volume relationship 成本-数量关系

Compaq 康柏

comparative advertisements 比较广告

comparison of brands 品牌比较

compensation deals 补偿处理

compensation plan 酬金方案

compensation/rewards 酬金/奖励

compensatory 补偿性的

competition and industry evolution 竞争和行业演变

competition-orientated pricing 竞争导向定价法

competitive advantage 竞争优势

competitive (supply-side) evolution 竞争(供方)演变

competitive factors 竞争因素

competitive intelligence 竞争情报/信息

cost-oriented pricing 成本导向定价法

cost-plus/mark-up pricing 成本加成/溢价定价法

costs and benefits of marketing functions 营销职能的成本和效益

costs of competitors 竞争者成本

costs of distribution 分销成本

countertrade 对等贸易

customer loyalty 顾客忠诚度

customer need 顾客需要

customer organization of sales force 按客户组织销售队伍

customer retention 顾客维系/保留

customer satisfaction 顾客满意度

customer segment pricing 顾客细分市场定价

customer service 顾客服务

customer-oriented pricing 顾客导向定价法

customers' perception 顾客感知

customers' preferences 顾客偏好

customers' price sensitivity 顾客的价格敏感度

customizing 定制

coupons 优惠券

courtesy 礼貌

coverage of geographic market 地域性市场的范围

coverage of relevant retailers 相关零售商的销售范围

credibility 信誉

credit terms 信贷条款

critical assumptions 关键假设

cross-elasticity 交叉弹性

customary pricing习惯性定价法

customer analysis 顾客分析

customer contact 顾客接触

customer demand 顾客需求

customer intimacy 顾客亲密度

篇3:机场常见的公共标志与说明(a b c)

(a b c)

“aa”film 十四岁以下禁看电影

admission free免费入场

bakery 面包店

bar 酒巴

beware of pickpocket 谨防扒手

bike park(ing) 自行车存车处

buses only 只准公共汽车通过

business hours 营业时间

cafe 咖啡馆、小餐馆

children and women first 妇女、儿童优先

closed 下班

commit no nuisance 禁止小便

complaint box 意见箱

篇4:C/C++程序员应聘常见面试题

1.引言

本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵,文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见。

许多面试题看似简单,却需要深厚的基本功才能给出完美的解答。企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分。读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次。此外,还有一些面试题考查面试者敏捷的思维能力。

分析这些面试题,本身包含很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。

2.找错题

试题1:

void test1

{

char string[10];

char* str1 = “0123456789”;

strcpy( string, str1 );

}

试题2:

void test2()

{

char string[10], str1[10];

int i;

for(i=0; i<10; i++)

{

str1[i] = “a”;

}

strcpy( string, str1 );

}

试题3:

void test3(char* str1)

{

char string[10];

if( strlen( str1 ) <= 10 )

{

strcpy( string, str1 );

}

}

解答:

试题1字符串str1需要11个字节才能存放下(包括末尾的’\0’),而string只有10个字节的空间,strcpy会导致数组越界;

对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;

对试题3,if(strlen(str1) <= 10)应改为if(strlen(str1) < 10),因为strlen的结果未统计’\0’所占用的1个字节。

剖析:

考查对基本功的掌握:

(1)字符串以’\0’结尾;

(2)对数组越界把握的敏感度;

(3)库函数strcpy的工作方式,如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案:

2分

void strcpy( char *strDest, char *strSrc )

{

while( (*strDest++ = * strSrc++) != ‘\0’ );

}

4分

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

//将源字符串加const,表明其为输入参数,加2分

{

while( (*strDest++ = * strSrc++) != ‘\0’ );

}

7分

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

{

//对源地址和目的地址加非0断言,加3分

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

while( (*strDest++ = * strSrc++) != ‘\0’ );

}

10分

//为了实现链式操作,将目的地址返回,加3分!

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

{

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

char *address = strDest;

while( (*strDest++ = * strSrc++) != ‘\0’ );

return address;

}

从2分到10分的几个答案我们可以清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功才能写一个完美的strcpy啊!

(4)对strlen的掌握,它没有包括字符串末尾的“\0”。

读者看了不同分值的strcpy版本,应该也可以写出一个10分的strlen函数了,完美的版本为: int strlen( const char *str ) //输入参数const

{

assert( strt != NULL ); //断言字符串地址非0

int len;

while( (*str++) != “\0” )

{

len++;

}

return len;

}

试题4:

void GetMemory( char *p )

{

p = (char *) malloc( 100 );

}

void Test( void )

{

char *str = NULL;

GetMemory( str );

strcpy( str, “hello world” );

printf( str );

}

试题5:

char *GetMemory( void )

{

char p[] = “hello world”;

return p;

}

void Test( void )

{

char *str = NULL;

str = GetMemory();

printf( str );

}

试题6:

void GetMemory( char **p, int num )

{

*p = (char *) malloc( num );

}

void Test( void )

{

char *str = NULL;

GetMemory( &str, 100 );

strcpy( str, “hello” );

printf( str );

}

试题7:

void Test( void )

{

char *str = (char *) malloc( 100 );

strcpy( str, “hello” );

free( str );

... //省略的其它语句

}

解答:

试题4传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完

char *str = NULL;

GetMemory( str );

后的str仍然为NULL;

试题5中

char p[] = “hello world”;

return p;

的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。

试题6的GetMemory避免了试题4的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句

*p = (char *) malloc( num );

后未判断内存是否申请成功,应加上:

if ( *p == NULL )

{

...//进行申请内存失败处理

}

试题7存在与试题6同样的问题,在执行

char *str = (char *) malloc(100);

后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:

str = NULL;

试题6的Test函数中也未对malloc的内存进行释放。

剖析:

试题4~7考查面试者对内存操作的理解程度,基本功扎实的面试者一般都能正确的回答其中50~60的错误。但是要完全解答正确,却也绝非易事。

对内存操作的考查主要集中在:

(1)指针的理解;

(2)变量的生存期及作用范围;

(3)良好的动态内存申请和释放习惯。

再看看下面的一段程序有什么错误:

swap( int* p1,int* p2 )

{

int *p;

*p = *p1;

*p1 = *p2;

*p2 = *p;

}

在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在VC++中DEBUG运行时提示错误“Access Violation”。该程序应该改为:

swap( int* p1,int* p2 )

{

int p;

p = *p1;

*p1 = *p2;

*p2 = p;

}

3.内功题

试题1:分别给出BOOL,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)

解答:

BOOL型变量:if(!var)

int型变量: if(var==0)

float型变量:

const float EPSINON = 0.00001;

if ((x >= - EPSINON) && (x <= EPSINON)

指针变量: if(var==NULL)

剖析:

考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。

一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。如果写成if (x == 0.0),则判为错,得0分。

试题2:以下为Windows NT下的32位C++程序,请计算sizeof的值

void Func ( char str[100] )

{

sizeof( str ) = ?

}

void *p = malloc( 100 );

sizeof ( p ) = ?

解答:

sizeof( str ) = 4

sizeof ( p ) = 4

剖析:

Func ( char str[100] )函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

数组名的本质如下:

(1)数组名指代一种数据结构,这种数据结构就是数组;

例如:

char str[10];

cout << sizeof(str) << endl;

输出结果为10,str指代数据结构char[10]。

(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;

char str[10];

str++; //编译出错,提示str不是左值

(3)数组名作为函数形参时,沦为普通指针。

Windows NT 32位平台下,指针的长度(占用内存的大小)为4字节,故sizeof( str ) 、sizeof ( p ) 都为4。

试题3:写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?

least = MIN(*p++, b);

解答:

#define MIN(A,B) ((A) <= (B) ? (A) : (B))

MIN(*p++, b)会产生宏的副作用

剖析:

这个面试题主要考查面试者对宏定义的使用,宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对“参数”进行的是一对一的替换。

程序员对宏定义的使用要非常小心,特别要注意两个问题:

(1)谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。所以,严格地讲,下述解答:

#define MIN(A,B) (A) <= (B) ? (A) : (B)

#define MIN(A,B) (A <= B ? A : B )

都应判0分;

(2)防止宏的副作用。

宏定义#define MIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:

((*p++) <= (b) ? (*p++) : (*p++))

这个表达式会产生副作用,指针p会作三次++自增操作。

除此之外,另一个应该判0分的解答是:

#define MIN(A,B) ((A) <= (B) ? (A) : (B));

这个解答在宏定义的后面加“;”,显示编写者对宏的概念模糊不清,只能被无情地判0分并被面试官淘汰。

试题4:为什么标准头文件都有类似以下的结构?

#ifndef __INCvxWorksh

#define __INCvxWorksh

#ifdef __cplusplus

extern “C” {

#endif

/*...*/

#ifdef __cplusplus

}

#endif

#endif /* __INCvxWorksh */

解答:

头文件中的编译宏

#ifndef __INCvxWorksh

#define __INCvxWorksh

#endif

的作用是防止被重复引用。

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在symbol库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo(int x, int y);

该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字,

_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。

为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern “C”来解决名字匹配问题,函数声明前加上extern “C”后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。

试题5:编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh”

函数头是这样的:

//pStr是指向以“\0”结尾的字符串的指针

//steps是要求移动的n

void LoopMove ( char * pStr, int steps )

{

//请填充...

}

解答:

正确解答1:

void LoopMove ( char *pStr, int steps )

{

int n = strlen( pStr ) - steps;

char tmp[MAX_LEN];

strcpy ( tmp, pStr + n );

strcpy ( tmp + steps, pStr);

*( tmp + strlen ( pStr ) ) = “\0”;

strcpy( pStr, tmp );

}

正确解答2:

void LoopMove ( char *pStr, int steps )

{

int n = strlen( pStr ) - steps;

char tmp[MAX_LEN];

memcpy( tmp, pStr + n, steps );

memcpy(pStr + steps, pStr, n );

memcpy(pStr, tmp, steps );

}

剖析:

这个试题主要考查面试者对标准库函数的熟练程度,在需要的时候引用库函数可以很大程度上简化程序编写的工作量。

最频繁被使用的库函数包括:

(1) strcpy

(2) memcpy

(3) memset

试题6:已知WAV文件格式如下表,打开一个WAV文件,以适当的数据结构组织WAV文件头并解析WAV格式的各项信息。

WAVE文件格式说明表

?

偏移地址

字节数

数据类型

内 容

文件头

00H

4

Char

“RIFF”标志

04H

4

int32

文件长度

08H

4

Char

“WAVE”标志

0CH

4

Char

“fmt”标志

10H

4

?

过渡字节(不定)

14H

2

int16

格式类别

16H

2

int16

通道数

18H

2

int16

采样率(每秒样本数),表示每个通道的播放速度

1CH

4

int32

波形音频数据传送速率

20H

2

int16

数据块的调整数(按字节算的)

22H

2

?

每样本的数据位数

24H

4

Char

数据标记符"data"

28H

4

int32

语音数据的长度

解答:

将WAV文件格式定义为结构体WAVEFORMAT:

typedef struct tagWaveFormat

{

char cRiffFlag[4];

UIN32 nFileLen;

char cWaveFlag[4];

char cFmtFlag[4];

char cTransition[4];

UIN16 nFormatTag ;

UIN16 nChannels;

UIN16 nSamplesPerSec;

UIN32 nAvgBytesperSec;

UIN16 nBlockAlign;

UIN16 nBitNumPerSample;

char cDataFlag[4];

UIN16 nAudioLength;

} WAVEFORMAT;

假设WAV文件内容读出后存放在指针buffer开始的内存单元内,则分析文件格式的代码很简单,为:

WAVEFORMAT waveFormat;

memcpy( &waveFormat, buffer,sizeof( WAVEFORMAT ) );

直接通过访问waveFormat的成员,就可以获得特定WAV文件的各项格式信息。

剖析:

试题6考查面试者组织数据结构的能力,有经验的程序设计者将属于一个整体的数据成员组织为一个结构体,利用指针类型转换,可以将memcpy、memset等函数直接用于结构体地址,进行结构体的整体操作。 透过这个题可以看出面试者的程序设计经验是否丰富。

试题7:编写类String的构造函数、析构函数和赋值函数,已知类String的原型为:

class String

{

public:

String(const char *str = NULL); // 普通构造函数

String(const String &other); // 拷贝构造函数

~ String(void); // 析构函数

String & perate =(const String &other); // 赋值函数

private:

char *m_data; // 用于保存字符串

};

解答:

//普通构造函数

String::String(const char *str)

{

if(str==NULL)

{

m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志“\0”的空

//加分点:对m_data加NULL 判断

*m_data = “\0”;

}

else

{

int length = strlen(str);

m_data = new char[length+1]; // 若能加 NULL 判断则更好

strcpy(m_data, str);

}

}

// String的析构函数

String::~String(void)

{

delete [] m_data; // 或delete m_data;

}

//拷贝构造函数

String::String(const String &other) // 得分点:输入参数为const型

{

int length = strlen(other.m_data);

m_data = new char[length+1]; //加分点:对m_data加NULL 判断

strcpy(m_data, other.m_data);

}

//赋值函数

String & String::operate =(const String &other) // 得分点:输入参数为const型

{

if(this == &other) //得分点:检查自赋值

return *this;

delete [] m_data; //得分点:释放原有的内存资源

int length = strlen( other.m_data );

m_data = new char[length+1]; //加分点:对m_data加NULL 判断

strcpy( m_data, other.m_data );

return *this; //得分点:返回本对象的引用

}

剖析:

能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上!

在这个类中包括了指针类成员变量m_data,当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数,这既是对C++程序员的基本要求,也是《Effective C++》中特别强调的条款。

仔细学习这个类,特别注意加注释的得分点和加分点的意义,这样就具备了60%以上的C++基本功!

试题8:请说出static和const关键字尽可能多的作用

解答:

static关键字至少有下列n个作用:

(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;

(2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

(3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

const关键字至少有下列n个作用:

(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;

(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。例如:

const classA operator*(const classA& a1,const classA& a2);

operator*的返回结果必须是一个const对象。如果不是,这样的变态代码也不会编译出错:

classA a, b, c;

(a * b) = c; // 对a*b的结果赋值

操作(a * b) = c显然不符合编程者的初衷,也没有任何意义。

剖析:

惊讶吗?小小的static和const居然有这么多功能,我们能回答几个?如果只能回答1~2个,那还真得闭关再好好修炼修炼。

这个题可以考查面试者对程序设计知识的掌握程度是初级、中级还是比较深入,没有一定的知识广度和深度,不可能对这个问题给出全面的解答。大多数人只能回答出static和const关键字的部分功能。

4.技巧题

试题1:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1

解答:

int checkCPU()

{

{

union w

{

int a;

char b;

} c;

c.a = 1;

return (c.b == 1);

}

}

剖析:

嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

存放内容

0x4000

0x34

0x4001

0x12

而在Big-endian模式CPU内存中的存放方式则为:

内存地址

存放内容

0x4000

0x12

0x4001

0x34

32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

存放内容

0x4000

0x78

0x4001

0x56

0x4002

0x34

0x4003

0x12

而在Big-endian模式CPU内存中的存放方式则为:

内存地址

存放内容

0x4000

0x12

0x4001

0x34

0x4002

0x56

0x4003

0x78

联合体union的存放顺序是所有成员都从低地址开始存放,面试者的解答利用该特性,轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。如果谁能当场给出这个解答,那简直就是一个天才的程序员。

试题2:写一个函数返回1+2+3+…+n的值(假定结果不会超过长整型变量的范围)

解答:

int Sum( int n )

{

return ( (long)1 + n) * n / 2; //或return (1l + n) * n / 2;

}

剖析:

对于这个题,只能说,也许最简单的答案就是最好的答案。下面的解答,或者基于下面的解答思路去优化,不管怎么“折腾”,其效率也不可能与直接return ( 1 l + n ) * n / 2相比!

int Sum( int n )

{

long sum = 0;

for( int i=1; i<=n; i++ )

{

sum += i;

}

return sum;

}

所以程序员们需要敏感地将数学等知识用在程序设计中。

篇5:C/C++程序员常见笔试题

C/C++程序员常见笔试题

试题1:分别给出BOOL,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)

解答:

BOOL型变量:if(!var)

int型变量: if(var==0)

float型变量:

const float EPSINON = 0.00001;

if ((x >= – EPSINON) && (x <= EPSINON)

指针变量: if(var==NULL)

剖析:

考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思,

一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量 (short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。如果写成if (x == 0.0),则判为错,得0分。

试题2:以下为Windows NT下的`32位C++程序,请计算sizeof的值

void Func ( char str[100] )

{

sizeof( str ) = ?

}

void *p = malloc( 100 );

sizeof ( p ) = ?

解答:

sizeof( str ) = 4

sizeof ( p ) = 4

剖析:

Func ( char str[100] )函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

数组名的本质如下:

(1)数组名指代一种数据结构,这种数据结构就是数组;

例如:

char str[10];

cout << sizeof(str) << endl;

输出结果为10,str指代数据结构char[10]。

(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;

char str[10];

str++; //编译出错,提示str不是左值

(3)数组名作为函数形参时,沦为普通指针。

Windows NT 32位平台下,指针的长度(占用内存的大小)为4字节,故sizeof( str ) 、sizeof ( p ) 都为4。

试题3:写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?

least = MIN(*p++, b);

解答:

#define MIN(A,B) ((A) <= (B) ? (A) : (B))

MIN(*p++, b)会产生宏的副作用

剖析:

这个面试题主要考查面试者对宏定义的使用,宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对“参数”进行的是一对一的替换,

程序员对宏定义的使用要非常小心,特别要注意两个问题:

(1)谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。所以,严格地讲,下述解答:

#define MIN(A,B) (A) <= (B) ? (A) : (B)

#define MIN(A,B) (A <= B ? A : B )

都应判0分;

(2)防止宏的副作用。

宏定义#define MIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:

((*p++) <= (b) ? (*p++) : (*p++))

这个表达式会产生副作用,指针p会作三次++自增操作。

除此之外,另一个应该判0分的解答是:

#define MIN(A,B) ((A) <= (B) ? (A) : (B));

这个解答在宏定义的后面加“;”,显示编写者对宏的概念模糊不清,只能被无情地判0分并被面试官淘汰。

试题4:为什么标准头文件都有类似以下的结构?

#ifndef __INCvxWorksh

#define __INCvxWorksh

#ifdef __cplusplus

extern “C” {

#endif

/*…*/

#ifdef __cplusplus

}

#endif

#endif /* __INCvxWorksh */

解答:

头文件中的编译宏

#ifndef __INCvxWorksh

#define __INCvxWorksh

#endif

的作用是防止被重复引用。

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在symbol库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo(int x, int y);

该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。

为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern “C”来解决名字匹配问题,函数声明前加上extern “C”后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。

试题5:编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh”

函数头是这样的:

//pStr是指向以’\0′结尾的字符串的指针

//steps是要求移动的n

void LoopMove ( char * pStr, int steps )

{

//请填充…

}

解答:

正确解答1:

void LoopMove ( char *pStr, int steps )

【浅谈C的应用与常见error】相关文章:

1.会计工作常见失误与对策

2.无人机遥感技术现状与应用

3.汽车应用与维修个人简历

4.数学与应用数学专业怎么样

5.汽车应用与维修简历

6.乒乓球教学方法的与应用

7.数学与应用数学专业描述

8.数学与应用数学专业自荐信

9.文秘管理与应用写作技巧与

10.c语言学习方法

下载word文档
《浅谈C的应用与常见error.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度: 评级1星 评级2星 评级3星 评级4星 评级5星
点击下载文档

文档为doc格式

  • 返回顶部