1.写出程序打印结果
#include
int main(void)
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d\n",*(a+1),*(ptr-1));
return 0;
}
程序结果2,5,原因:数组名a可以做数组的首地址,而&a是数组的指针
(即(&a+1)是由a[0][m]移动到a[1][m],此例中m为5)
2.编码实现变量某位清0或置1 (位逻辑操作)
注:移位操作指对某变量的二进制进行移位,无论该变量是何种进制格式表示的。
eg:
#define BIT3 (0x1<<3)
int a;
a|=BIT3; //将a的第三位置1
a&=~BIT3; //将a的第三位置0
3.不用临时变量对a,b的值交换
方法一:
a=a+b; b=a-b; a=a-b;
方法二:
a^=b; b^=a; a^=b;
4. string 原理及实现
#pragma once
#include
class String{
private:
char* data; //字符串内容
size_t length; //字符串长度
public:
String(const char* str = nullptr); //通用构造函数
String(const String& str); //拷贝构造函数
~String(); //析构函数
String operator+(const String &str) const; //重载+
String& operator=(const String &str); //重载=
String& operator+=(const String &str); //重载+=
bool operator==(const String &str) const; //重载==
friend std::istream& operator>>(std::istream &is, String &str);//重载>>
friend std::ostream& operator<<(std::ostream &os, String &str);//重载<<
char& operator[](int n)const; //重载[]
size_t size() const; //获取长度
const char* c_str() const; //获取C字符串
};
#include"String.h"
//通用构造函数
String::String(const char *str){
if (!str){
length = 0;
data = new char[1]; //一定要用new分配内存,否则就变成了浅拷贝;
*data = '\0';
}else{
length = strlen(str); //
data = new char[length + 1];
strcpy(data,str);
}
}
//拷贝构造函数
String::String(const String& str){
length = str.size();
data = new char[length + 1]; //一定要用new,否则变成了浅拷贝
strcpy(data,str.c_str());
}
String::~String(){
delete[]data;
length = 0;
}
//重载+
String String::operator+(const String &str) const {
String StringNew;
StringNew.length = length + str.size();
StringNew = new char[length + 1];
strcpy(StringNew.data, data);
//字符串拼接函数,即将str内容复制到StringNew内容后面
strcat(StringNew.data, str.data);
return StringNew;
}
//重载=
String& String::operator=(const String &str){
if (this == &str){
return *this;
}
delete []data; //释放内存
length = str.length;
data = new char[length + 1];
strcpy(data,str.c_str());
return *this;
}
//重载+=
String& String::operator+=(const String &str){
length += str.size();
char *dataNew = new char[length + 1];
strcpy(dataNew, data);
delete[]data;
strcat(dataNew, str.c_str());
data = dataNew;
return *this;
}
//重载==
bool String::operator==(const String &str) const {
if (length != str.length) {
return false;
}
return strcmp(data, str.data) ? false : true;
}
//重载[]
char& String::operator[](int n) const //str[n]表示第n+1个元素
{
if (n >= length){
return data[length - 1]; //错误处理
}else{
return data[n];
}
}
//获取长度
size_t String::size() const {
return this->length;
}
//获取C字符串
const char* String::c_str() const {
return data;
}
//重载>>
std::istream& operator>>(std::istream &is, String &str){
char tem[1000];
is >> tem;
str.length = strlen(tem);
str.data = new char[str.length + 1];
strcpy(str.data, tem);
return is;
}
//重载<<
std::ostream& operator<<(std::ostream &os, String &str){
os << str.c_str();
return os;
}
关于operator>>和operator<<运算符重载,我们是设计成友元函数(非成员函数),
并没有设计成成员函数,原因如下:
对于一般的运算符重载都设计为类的成员函数,而>>和<<却不这样设计,
因为作为一个成员函数,其左侧操作数必须是隶属同一个类之下的对象,
如果设计成员函数,输出为对象>>cout >> endl;(Essential C++)不符合习惯。
一般情况下:
将双目运算符重载为友元函数,这样就可以使用交换律,比较方便
单目运算符一般重载为成员函数,因为直接对类对象本身进行操作
运算符重载函数可以作为成员函数,友元函数,普通函数。
普通函数:一般不用,通过类的公共接口间接访问私有成员。
成员函数:可通过this指针访问本类的成员,可以少写一个参数,
但是表达式左边的第一个参数必须是类对象,通过该类对象来调用成员函数。
友元函数:左边一般不是对象。<< >>运算符一般都要申明为友元重载函数
5.编码辨别系统是16位或32位,大端或小端模式
32位处理器一次只能处理32位,也就是4个字节的数据,虚拟地址空间的最大值是4G。
64位处理器一次能处理64位,也就是8个字节的数据,虚拟地址空间的最大值是16T。
32位处理器:系统指针(32位 ),long(32位),int(32位),short(16位)
64位处理器:系统指针(64位 ),long(64位),int(32位),short(16位)
(1)辨别系统是16位或32位
方法一:
sizeof(指针)。结果为2、4、8时系统分别对应16、32、64位。
方法二:
int i=65536,j=65535;
cout<65536){
cout<<" 32 bit"<
int main()
{
#ifdef __x86_64__
printf("__x86_64__\n");
#elif __i386__
printf("__i386__\n");
#endif
return 0;
}
(2)判断大端模式或小端模式
大端模式:字数据的高字节存储在低地址中,字数据的低字节存放在高地址中。
小端模式:.................高.........................低.....。
方法一:直接判断内存存储情况
int isLittleEndian(void)
{
int i=0x12345678;
char *c=(char *)&i;
return ((c[0] == 0x78) && (c[1] == 0x56) && (c[2] == 0x34) && (c[3] == 0x12));
}
方法二:用union判断
typedef union {
int i;
char c;
} myUnion;
// 1: Little Endian; 0: Big Endian.
int isLittleEndian02(void)
{
myUnion u;
u.i = 1;
return (u.i == u.c);
}
读取成员c就相当于读取成员a的低位的第一个字节值(联合体union的存放顺序是所有成员都从低地址开始存放)。
6. 设计一个只能在堆上或栈上实例化的类
只能在堆上实例化的类:将析构函数定义为private,在栈上不能自动调用析构函数,
只能手动调用,也可将构造函数定义为private但需要手动写个函数实现独享的构造。
class CHeapOnly//只能在堆上实例化的类
{
public:
CHeapOnly(){
cout<<"Constructor of CHeapOnly!"<
7. C库函数的实现
memcpy:
void *memcpy(void *dest, const void *src, size_t count) {
char *tmp = dest;
const char *s = src;
while (count--){
*tmp++ = *s++;
}
return dest;
}
strcpy:
char *strcpy(char *dst,const char *src) {
assert(dst != NULL && src != NULL);
char *ret = dst;
while((* dst++ = * src++) != '\0') ;
return ret;
}
strcat:
char *strcat(char *strDes, const char *strSrc){
assert((strDes != NULL) && (strSrc != NULL));
char *address = strDes;
while (*strDes != ‘\0′){
++ strDes;
}
while ((*strDes ++ = *strSrc ++) != ‘\0′)
return address;
}
strncat:
char *strncat(char *strDes, const char *strSrc, int count){
assert((strDes != NULL) && (strSrc != NULL));
char *address = strDes;
while (*strDes != ‘\0′){
++ strDes;
}
while (count -- && *strSrc != ‘\0′ ){
*strDes ++ = *strSrc ++;
}
*strDes = ‘\0′;
return address;
}
strcmp:
int strcmp(const char *str1,const char *str2){
/*不可用while(*str1++==*str2++)来比较,当不相等时仍会执行一次++,
return返回的比较值实际上是下一个字符。应将++放到循环体中进行。*/
while(*str1 == *str2){
if(*str1 == '\0')
return0;
++str1;
++str2;
}
return *str1 - *str2;
}
strncmp:
int strncmp(const char *s, const char *t, int count){
assert((s != NULL) && (t != NULL));
while (*s && *t && *s == *t && count --) {
++ s;
++ t;
}
return (*s – *t);
}
strlen:
int strlen(const char *str){
assert(str != NULL);
int len = 0;
while (*str ++ != ‘\0′)
++ len;
return len;
}
strpbrk:
char * strpbrk(const char * cs,const char * ct){
const char *sc1,*sc2;
for( sc1 = cs; *sc1 != '\0'; ++sc1){
for( sc2 = ct; *sc2 != '\0'; ++sc2){
if (*sc1 == *sc2){
return (char *) sc1;
}
}
}
return NULL;
}
strstr:
char *strstr(const char *s1,const char *s2){
int len2;
if(!(len2=strlen(s2)))
//此种情况下s2不能指向空,否则strlen无法测出长度,这条语句错误
return(char*)s1;
for(;*s1;++s1){
if(*s1==*s2 && strncmp(s1,s2,len2)==0)
return(char*)s1;
}
return NULL;
}