您的位置:首页 > 职场人生

程序员面试常见问题-整理-1

2016-02-19 16:41 369 查看
程序员面试常见问题-整理-1
2016.2.19 by Huangtao

以下是海康威视应用软件开发工程师笔试题涉及到的一些知识:
=====================================================================
Sizeof(结构体):
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

一个类能够实例化,编译器就需给它分配内存空间,来指示类实例的地址。这里编译器默认分配了一个字节(如:char,编译器相关),以便标记可能初始化的类实例,同时使空类占用的空间也最少(即1字节)。
对于结构体和空类大小是1这个问题,首先这是一个C++问题,在C语言下空结构体大小为0(当然这是编译器相关的)。这里的空类和空结构体是指类或结构体中没有任何成员。
在C++下,空类和空结构体的大小是1(编译器相关),这是为什么呢?为什么不是0?
这是因为,C++标准中规定,“no object shall have the same address in memory as any other variable” ,就是任何不同的对象不能拥有相同的内存地址。 如果空类大小为0,若我们声明一个这个类的对象数组,那么数组中的每个对象都拥有了相同的地址,这显然是违背标准的。



int *a; int &a; int & *a; int * &a
int i;
int *a = &i;//这里a是一个指针,它指向变量i
int &b = i;//这里b是一个引用,它是变量i的引用,引用是什么?它的本质是什么?下面会具体讲述
int * &c = a;//这里c是一个引用,它是指针a的引用
int & *d;//这里d是一个指针,它指向引用,但引用不是实体,所以这是错误的

数组指针和指针数组的区别:
数组指针(也称行指针)
定义 int (*p)
;
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
如要将二维数组赋给一指针,应这样赋值:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组
定义 int *p
;
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
优先级:()>[]>*

指针函数与函数指针的区别:
1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针
类型标识符 *函数名(参数表)
int *f(x,y);
首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。

2、函数指针是指向函数的指针变量,即本质是一个指针变量。
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
类型说明符 (*函数名)(参数)
其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
例如:
void (*fptr)();
把函数的地址赋值给函数指针,可以采用下面两种形式:
fptr=&Function;
fptr=Function;
取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
可以采用如下两种方式来通过指针调用函数:
x=(*fptr)();
x=fptr();
第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。

Const
修饰指针:
(位于星号左侧,用来修饰指针所指的变量,即指针指向为常量;位于星号右侧,用来修饰指针本身,即指针本身是常量)
const int *A; 或 int const *A;
//const修饰指向的对象,A可变,A指向的对象不可变
int *const A;
//const修饰指针A, A不可变,A指向的对象可变
const int *const A;
//指针A和A指向的对象都不可变

指针和引用区别:(都是地址的概念)
非空区别;
合法性区别;
可修改性区别;
应用区别。

C++中为什么用模板类?
(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此具有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型
模板就是实现代码重用机制的一种工具。它实现了将类型参数化,就是将类型定义为参数,实现了真正的代码可重用性。模板分为两大类:函数模板和类模板。由于类模板包含类型参数,所以类模板又称作参数化的类。如果说类是对象的抽象,抽象是类的实例;那么可以说类模板是类的抽象,而类是类模板的实例。利用类模板可以建立各种数据类型的类。

构造函数与析构函数的调用顺序
http://blog.csdn.net/bresponse/article/details/6914155

编写strcpy函数(10分)
已知strcpy函数的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C的字符串库函数,请编写函数 strcpy
char *strcpy(char *strDest, const char *strSrc);
{
assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
char *address = strDest; // 2分
while( (*strDest++ = * strSrc++) != ‘/0’ ) // 2分
NULL ;
return address ; // 2分
}

(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
答:为了实现链式表达式。 // 2分
例如 int length = strlen( strcpy( strDest, “hello world”) );

//===================================================================
// 利用栈来解决一个字符串之中使用的括号是否匹配的问题
//===================================================================

#include <iostream>
using namespace std;

#define stacksize 100   // 定义栈的空间大小

// 定义栈的结构体
struct stack
{
char strstack[stacksize];
int top;
};

// 定义一个新栈s,初始化栈顶为-1
void InitStack(stack &s)
{
s.top = -1;
}

char Push(stack &s, char a)
{
if (s.top == stacksize - 1)
return 0;
s.top++;
s.strstack[s.top] = a;
return a;
}

char Pop(stack &s)
{
if (s.top == -1)
return 0;
char a = s.strstack[s.top];
s.top--;
return a;
}

// 栈为空时返回值为1
int Empty(stack &s)
{
if (s.top == -1)
return 1;
else
return 0;
}

// 检查括号是否匹配的函数
int Check(char * str)
{
stack s;
InitStack(s);
int strn = strlen(str);
for (int i = 0; i < strn; i++)
{
char a = str[i];
switch (a)
{
case '{':
case '[':
case '(':
Push(s, a);        //若是左括号,则进行入栈操作
break;
case ')':            //若是右括号,则进行出栈操作,若出栈元素不是与输入相对应的左括号,则字符串括号中不匹配
if (Pop(s) != '(')
return 0;
break;
case ']':
if (Pop(s) != '[')
return 0;
break;
case '}':
if (Pop(s) != '{')
return 0;
break;
default:break;
}
}
int re = Empty(s);
if (re == 1)
return 1;    //栈为空
else
return 0;    //栈不为空,有左括号,即存在‘(’或'['或'{'未匹配
}

int main()
{
char str[100];
cout << "请您输入一个长度小于100的字符串:" << endl;
cin >> str;
int re = Check(str);
if (re == 1)
cout << "您输入的字符串中的括号完全匹配!" << endl;
else if (re == 0)
cout << "您输入的字符串中的括号不匹配!" << endl;

return 0;
}


//===================================================================
// 用户输入M,N值,从1至N开始顺序
// 循环数数,每数到M输出该数值,
// 直至全部输出
//===================================================================

#include <stdio.h>

// 节点
typedef struct node
{
int data;
node* next;
}node;

// 创建循环链表
void createList(node*& head, node*& tail, int n)
{
if (n<1)
{
head = NULL;
return;
}
head = new node();
head->data = 1;
head->next = NULL;

node* p = head;
for (int i = 2; i<n + 1; i++)
{
p->next = new node();
p = p->next;
p->data = i;
p->next = NULL;
}

tail = p;
p->next = head;
}

// 打印循环链表
void Print(node*& head)
{
node* p = head;

while (p && p->next != head)
{
printf("%d ", p->data);
p = p->next;
}
if (p)
{
printf("%d\n", p->data);
}
}

void CountPrint(node*& head, node*& tail, int m)
{
node* cur = head;
node* pre = tail;

int cnt = m - 1;
while (cur && cur != cur->next)
{
if (cnt)
{
cnt--;
pre = cur;
cur = cur->next;
}
else
{
pre->next = cur->next;
printf("%d ", cur->data);
delete cur;
cur = pre->next;
cnt = m - 1;
}
}

if (cur)
{
printf("%d ", cur->data);
delete cur;
head = tail = NULL;
}
printf("\n");
}

int main()
{
node* head;
node* tail;
int m;
int n;
scanf("%d", &n);
scanf("%d", &m);
createList(head, tail, n);
Print(head);
CountPrint(head, tail, m);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: