Archive for the 'C/C++' Category

C/C++笔试、面试题目汇总

1.求下面函数的返回值(微软)
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
假定x = 9999。 答案:8
思路:将x转化为2进制,看含有的1的个数。
2. 什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
3. 将“引用”作为函数参数有哪些特点?
(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
4. 在什么时候需要使用“常引用”? 
如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;
例1
int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确
例2
string foo( );
void bar(string & s);
那么下面的表达式将是非法的:
bar(foo( ));
bar(”hello world”);
原因在于foo( )和”hello world”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
引用型参数应该在能被定义为const的情况下,尽量定义为const 。
5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!
注意事项:
(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了”无所指”的引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
(3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
(4)流操作符重载返回值申明为“引用”的作用:
流操作符,这两个操作符常常希望被连续使用,例如:cout

Popularity: 29% [?]

C语言复习2

实数(real number)又称浮点数(floating-point number)。实数有两种表达形式:十进制小数形式;指数形式。规范化的指数形式。实型变量的分类:单精度(float),双精度(double),长双精度(long double)三类。实型数据存在舍入误差,所以应当避免将一个很大的数和一个很小的数直接相加减计算。许多编译系统会将实型常量作为双精度来处理,这样可以保证计算计算结果更精确,但是运算的速度也就降低了。可以在数的后面加字母 f 或 F,这样编译系统就会按单精度来处理。另外还要注意float型变量只能接收7位有效数字。字符型数据单引号刮起来的一个字符,如’A’,’a’。
关于转义字符含义:
字符形式 含义 ASCII码
\n 换行,将当前位置移到下一行 10
\t 水平制表(跳到下一个tab位置) 9
\b 退格,将当前位置移到前一列 8
\r 回车,将当前位置移到本行开头 13
\f 换页,将当前位置移到下页开头 12
\\ 反斜杠字符\ 92
\’ 单引号字符 39
\” 双引号字符 34
\ddd 1到3位8进制数所代表的字符
\xhh 1到2位16进制数所代表的字符
将一个字符常量放到一个字符变量中,实际上并不是把该字符本身放到内存单元中去,而是将该字符的相应的ASCII代码放到存储单元中。
字符型数据和整型数据是通用的,既可以用字符形式输出,也可以用整数形式输出,但是字符型数据只占一个字节,只能存放0-255范围内的数。
从ASCII码表可以看出,每个小写字母比它对应的大写字母ASCII码大32。
字符串常量
Popularity: 28% [?]SHARETHIS.addEntry({ title: “C语言复习2″, url: “http://blog.manboo.info/356.htm” });

Popularity: 28% [?]

C语言复习

C语言的数据结构:
基本类型:整型,字符型,实型(浮点型,包括单精度型和双精度型),枚举类型
构造类型:数组类型,结构体类型,共用体类型
指针类型
空类型
常量如定义:
#define PRICE 30
这种用一个标识符代表一个常量的,称为符号常量,即标识符形式的常量。
通常,符号常量名用大写,变量名用小写,以示区别。
变量
变量名和变量值。在程序中重变量中取值,实际上是通过变量名找到相应的内存地址,从其存储单元中读取数据。
C语言规定标识符(identifier)只能由字母、数字和下划线三种字符来组成,而且第一个字符必须为字母或下划线。
数值是以补码(complement)形式表示的,一个正数的补码和其原码相同,而一个负数则不相同了。方法是:将这个数的绝对值的二进制形式,按位取反再加1。
比如-10,10的二进制是1010,取反位0101,再加1得0110。
10的原码:0000 0000 0000 1010
取反: 1111 1111 1111 0101
加1: 1111 1111 1111 0110
所以说,在整数的16位中,最左面的一位是表示符号的,0为正,1为负。
整型变量的分类
在int前可加修饰符 short, long
一个int型变量的值的范围:-32768~32767
如果将变量定义为unsigned,即无符号数,则为0~65535
而修饰符signed可以不写,默认就是有符号数的。
这样就有6种整型变量:
类型 最小取值范围
[signed] int -32768~32767
unsigned int 0~65535
[signed] short [int] -32768~32767
unsigned short [int] 0~65535
long [int] -2147483648~2147483647
unsigned long [int] 0~4294967295
[]内的部分可以省略不写。上面是ANSI标准定义的整数类型和有关数据,最小取值范围是指不能低于此值,但可以高于此值。
C标准没有规定这些数据所占的字节数,只是要求long型数据长度不低于int型,short型不长于int型。
一个整常量后面加字母u,认为是unsigned int 型,如12345u,
若加字母l或L,则认为是long int 常量,例如123l, 432L, 这些常常用于函数调用中。

Popularity: 14% [?]SHARETHIS.addEntry({ title: “C语言复习”, url: “http://blog.manboo.info/351.htm” });

Popularity: 14% [?]

关于 sizeof() 的思考

来源:http://www.blogjava.net/majianan/archive/2006/08/20/64664.html
1. 定义: sizeof 乃 C/C++ 中的一个操作符(operator)是也。简单说其作用就是返回一个对象或者类型所占的内存字节数。MSDN上的解释为:
The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types).This keyword returns a value of type size_t.
其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一般定义为 typedef unsigned int size_t;
世上编译器林林总总,但作为一个规范,它们都会保证char、signed char和unsigned char的sizeof值为1,毕竟char是我们编程能用的最小数据类型。2. 语法:sizeof有三种语法形式,如下:1) sizeof( object ); // sizeof( 对象 );2) sizeof( type_name ); // sizeof( 类型 );3) sizeof object; [...]

Popularity: 29% [?]

C语言中String库函数

以下内容摘自《C程序设计教程》(美)H.M.Deitel P.J.Deitel著,薛万鹏等译,机械工业出版社。
void *memccpy (void *dest, const void *src, int c, size_t n);
从src所指向的对象复制n个字符到dest所指向的对象中。如果复制过程中遇到了字符c则停止复制,返回指针指向dest中字符c的下一个位置;否则返回NULL。
void *memcpy (void *dest, const void *src, size_t n);
从src所指向的对象复制n个字符到dest所指向的对象中。返回指针为dest的值。
void *memchr (const void *s, int [...]

Popularity: 29% [?]

VC中定时器的使用

1.1 用WM_TIMER来设置定时器
先请看SetTimer这个API函数的原型
UINT_PTR SetTimer(
HWND hWnd, // 窗口句柄
UINT_PTR nIDEvent, // 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器
UINT uElapse, // 时间间隔,单位为毫秒
TIMERPROC lpTimerFunc // 回调函数
);
例如
SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器
在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了,例如:
UINT SetTimer(1,100,NULL);
函数反回值就是第一个参数值1,表示此定时器的ID号。
第二个参数表示要等待100毫秒时间再重新处理一次。第三个参数在这种方法中一般用NULL。
注意:设置第二个参数时要注意,如果设置的等待时间比处理时间短,程序就会出问题了。
1.2 调用回调函数
此方法首先写一个如下格式的回调函数
void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);
然后再用SetTimer(1,100,TimerProc)函数来建一个定时器,第三个参数就是回调函数地址。
二、多个定时器的实现与应用
Popularity: 35% [?]SHARETHIS.addEntry({ title: “VC中定时器的使用”, url: “http://blog.manboo.info/259.htm” });

Popularity: 35% [?]

CString 操作指南

1、CString 对象的连接  能体现出 CString 类型方便性特点的一个方面就字符串的连接,使用 CString 类型,你能很方便地连接两个字符串,正如下面的例子:

CString gray(”Gray”);
CString cat(”Cat”);
CString graycat = gray + cat;

要比用下面的方法好得多:

char gray[] = “Gray”;
char cat[] = “Cat”;
char * graycat = malloc(strlen(gray) + strlen(cat) + 1);
strcpy(graycat, gray);
strcat(graycat, cat);

2、格式化字符串  与其用 sprintf() 函数或 wsprintf() 函数来格式化一个字符串,还不如用 CString 对象的Format()方法:

CString s;
s.Format(_T(”The total is %d”), total);

  用这种方法的好处是你不用担心用来存放格式化后数据的缓冲区是否足够大,这些工作由CString类替你完成。  格式化是一种把其它不是字符串类型的数据转化为CString类型的最常用技巧,比如,把一个整数转化成CString类型,可用如下方法:

CString s;
s.Format(_T(”%d”), total);

  我总是对我的字符串使用_T()宏,这是为了让我的代码至少有Unicode的意识,当然,关于Unicode的话题不在这篇文章的讨论范围。_T()宏在8位字符环境下是如下定义的:

#define _T(x) x // 非Unicode版本(non-Unicode version)

而在Unicode环境下是如下定义的:

#define _T(x) L##x // Unicode版本(Unicode version)

所以在Unicode环境下,它的效果就相当于:

s.Format(L”%d”, total);

  如果你认为你的程序可能在Unicode的环境下运行,那么开始在意用 Unicode 编码。比如说,不要用 [...]

Popularity: 17% [?]

CString类的使用

CString类功能强大,比STL的string类有过之无不及.新手使用CString时,都会被它强大的功能所吸引.然而由于对它内部机制的不了解,新手在将CString向C的字符数组转换时容易出现很多问题.因为CString已经重载了LPCTSTR运算符,所以CString类向 const char *转换时没有什么麻烦,如下所示:
  char a[100];  CString str(”aaaaaa”);  strncpy(a,(LPCTSTR)str,sizeof(a));
  或者如下:
  strncpy(a,str,sizeof(a));
  以上两种用法都是正确地.因为strncpy的第二个参数类型为const char *.所以编译器会自动将CString类转换成const char *.很多人对LPCTSTR是什么东西迷惑不解,让我们来看看:  1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别的,都是32位.所以这里的LP和P是等价的.  2.C表示const
Popularity: 24% [?]SHARETHIS.addEntry({ title: “CString类的使用”, url: “http://blog.manboo.info/257.htm” });

Popularity: 24% [?]

CString实现原理简单介绍

转自:http://www.01hr.com/article.jsp?id=10177
Cstring是对于原来标准c中字符串类型的一种的包装。因为,通过很长时间的编程,我们发现,很多程序的 bug多和字符串有关,典型的有:缓冲溢出、内存泄漏等。而且这些bug都是致命的,会造成系统的瘫痪。因此c++里就专门的做了一个类用来维护字符串指针。标准c++里的字符串类是string,在microsoft MFC类库中使用的是Cstring类。通过字符串类,可以大大的避免c中的关于字符串指针的那些问题。
这里我们简单的看看Microsoft MFC中的Cstring是如何实现的。当然,要看原理,直接把它的代码拿过来分析是最好的。MFC里的关于Cstring的类的实现大部分在strcore.cpp中。
Cstring就是对一个用来存放字符串的缓冲区和对施加于这个字符串的操作封装。也就是说,Cstring里需要有一个用来存放字符串的缓冲区,并且有一个指针指向该缓冲区,该指针就是LPTSTR m_pchData。但是有些字符串操作会增建或减少字符串的长度,因此为了减少频繁的申请内存或者释放内存,Cstring会先申请一个大的内存块用来存放字符串。这样,以后当字符串长度增长时,如果增加的总长度不超过预先申请的内存块的长度,就不用再申请内存。当增加后的字符串长度超过预先申请的内存时,Cstring先释放原先的内存,然后再重新申请一个更大的内存块。同样的,当字符串长度减少时,也不释放多出来的内存空间。而是等到积累到一定程度时,才一次性将多余的内存释放。
还有,当使用一个Cstring对象a来初始化另一个Cstring对象b时,为了节省空间,新对象b并不分配空间,它所要做的只是将自己的指针指向对象a的那块内存空间,只有当需要修改对象a或者b中的字符串时,才会为新对象b申请内存空间,这叫做写入复制技术 (CopyBeforeWrite)。
这样,仅仅通过一个指针就不能完整的描述这块内存的具体情况,需要更多的信息来描述。
首先,需要有一个变量来描述当前内存块的总的大小。
其次,需要一个变量来描述当前内存块已经使用的情况。也就是当前字符串的长度
另外,还需要一个变量来描述该内存块被其他Cstring引用的情况。有一个对象引用该内存块,就将该数值加一。

Cstring中专门定义了一个结构体来描述这些信息:
struct CStringData{long nRefs; // reference countint nDataLength; // length of data (including terminator)int nAllocLength; // length of allocation// TCHAR data[nAllocLength]TCHAR* data() // TCHAR* to managed data{ return (TCHAR*)(this+1); }};
实际使用时,该结构体的所占用的内存块大小是不固定的,在Cstring内部的内存块头部,放置的是该结构体。从该内存块头部开始的sizeof(CstringData)个BYTE后才是真正的用于存放字符串的内存空间。这种结构的数据结构的申请方法是这样实现的:
pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;
其中nLen是用于说明需要一次性申请的内存空间的大小的。
从代码中可以很容易的看出,如果想申请一个256个TCHAR的内存块用于存放字符串,实际申请的大小是:
sizeof(CstringData)个BYTE + (nLen+1)个TCHAR
其中前面sizeof(CstringData)个BYTE是用来存放CstringData信息的。后面的nLen+1个TCHAR才是真正用来存放字符串的,多出来的一个用来存放’\0′。
Cstring中所有的operations的都是针对这个缓冲区的。比如LPTSTR CString::GetBuffer(int nMinBufLength),它的实现方法是:
首先通过Cstring::GetData()取得CstringData对象的指针。该指针是通过存放字符串的指针m_pchData先后偏移sizeof(CstringData),从而得到了CstringData的地址。
然后根据参数nMinBufLength给定的值重新实例化一个CstringData对象,使得新的对象里的字符串缓冲长度能够满足nMinBufLength。
然后再重新设置一下新的CstringData中的一些描述值。
最后将新CstringData对象里的字符串缓冲直接返回给调用者。

这些过程用C++代码描述就是:
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)   {     [...]

Popularity: 23% [?]

Protected: 串口通信相关资源

There is no excerpt because this is a protected post.

Popularity: 43% [?]