*********************************************************************************************************************************** 编程区:
《《《《冒泡排序,二分查找,筛选法,的考察》》》》
100、
有两个磁盘文件A和B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C中.
#include
86.有一浮点型数组A,用C语言写一函数实现对浮点数组A进行降序排序,并输出结果,要求要以数组A作为函数的入口.(建议用冒泡排序法)
#include
#include
void BubbleSort(int arr[], int n)
{
int i,j;
int exchange = 1;//交换标志,提高算法效率;
int temp;
for(i=0;i
exchange=0;//本趟排序开始前,交换标志应为假
for(j=0;j
if(arr[j+1] > arr[j])
{
temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
exchange=1; //发生了交换,故将交换标志置为真
}
}
if(!exchange) //本趟排序未发生交换,提前终止算法
return;
}
}
int main(int argc,char* argv[])
{
int arr[5]={1,4,2,6,5};
int i;
BubbleSort(arr, 5);
printf("after sort,arr is :\n");
for(i=0;i<5;i++)
{
printf("%3d",arr[i]);
}
return 1;
}
77.写出二分查找的代码:
Int binary_search(int* arr,int key,int size)
{
Intmid;
Intlow=0;
Int high=size-1;
While(low<=high)
{
Mid=(low+high)/2;
If(arr[mid]>key)
High=mid-1;
ElseIf(arr[mid]
Low=mid+1;
Else
Return mid;
}
Return -1;
}
补充1:用帅选法查找100之内的质数
#include
using namespace std;
#define N 100
int main()
{
/*0~100共101个数*/
int sieve[N + 1];
int i;
//step 1:初始化(sieve[i] = 0 表示不在筛中,即不是质数;1表示在筛中)
sieve[0]=sieve[1]=0;
for(int i = 2; i <= N; i++)
{
sieve[i] = 1;
}
//step 2:偶数(2的倍数)肯定不是质数,所以应该先筛除
for(i = 2; i <= N / 2; i++)
{
sieve[i * 2] = 0;
}
int p = 2; //第一个质数是2
//step 3:从sieve中删去P的倍数
while(p * p <= N)
{
p = p + 1; //选下一个p
while(sieve[p] == 0)
{
p++;
}
int t = p * p;
int s = 2 * p;/*质数与质数之和包含合数,但质数于合数之和必为质数,提高算法效率*/
while(t <= N)
{
sieve[t] = 0; //删除
t = t + s;
}
}
//step 4: 输出结果
for(i = 2; i <= N; i++)
{
if(sieve[i] != 0)
{
cout< }
}
return 1;
}
87、实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。
//删除操作
StatusListDelete_DuL(DuLinkList& L,int i,ElemType& e)
{
if(!(p=GetElemP_DuL(L,i)))
return ERROR;//容错判断;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->pror;
free(p);
p=NULL;//勿忘,否则内存泄露
return OK;
}
//插入操作
StatusListInsert_DuL(DuLinkList&L,inti,ElemType&e)
{
if(!(p=GetElemP_DuL(L,i)))
return ERROR;
if(!(s=(DuLinkList)malloc(sizeof(DuLNode))))
return ERROR;
/*assert((s=(DuLinkList)malloc(sizeof(DuLNode)))!=NULL)*/
s->data=e;
s->prior=p;
p-> next -> prior =s;
p->next=s;
s->next=p->next->next;
return OK;}
88、把一个链表反向。//链表头插法;
intre_Link(Linklist H)
{
Linklist p=H->next,q;
H->next=NULL;
while(p!=NULL)
{
q=p;
p=p->next;
q->next=H->next;
H->next=q;
}
return 0;
}
《《《《strcpy 和memcpy》》》》76.已知strcpy函数的原型是char *strcpy(char*strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C 的字符串库函数,请编写函数strcpy。
char* stringcpy(char* Des,const char* Src)
{
assert((Des!=NULL) && (Src!=NULL));
char* address=Des;
while((*Des++=*Src++)!='\0');
return address;
}
断言assert是一个宏,该宏在<assert>中,
当使用assert时候,给他个参数,即一个判读为真的表达式。
预处理器产生测试该断言的代码,如果断言不为真,则发出一个错误信息告诉断言是什么以及它失败一会,程序会终止。我们一般可以用在判断某件操作是否成功上。
详见《高质量c&c++编程,林锐,6.5章》
(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
为了实现链式表达式:
int len= strlen(stringcpy(Des,"hello"));
内存复制:
void* memcpy(void* pvTo, constvoid* pvFrom, size_tsize)
{
assert((pvTo!= NULL) &&(pvFrom!= NULL));
byte* pbTo= pvTo;
byte* pbFrom= pbFrom;
while (size--> 0)
{
*pbTo++ = *pbFrom++;
}
return pvTo;
}
注意:内存拷贝时要避免内存空间重叠的问题,(即pvfrom与pvto所指向的内存不能重叠)
为了防止内存空间重叠,若是目标地址高于源地址,从后往前复制;
若是源地址高于目标地址,从前往后复制;
《《《《查找字符串中的子串》》》》
84、请编写一个C 函数,该函数在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成的。
#include
#include
#include
int ChildString(char*p)
{
char* q=p;
int stringlen=0, i=0,j=1,len=0,maxlen=1;
//stringlen=strlen(p);
while(*q!='\0') //不能用strlen,求得长stringlen
{
stringlen++;
q++;
}
while( i< stringlen)
{
if(*(p+i)==*(p+j)&&j< stringlen)
{
len++; //统计子串长度
i++;
j++;
}
else
{
if(len>=maxlen) //统计最大子串长度
{
maxlen=len+1;
len=0;
}
else
len=0;
i++;
j++;
}
}
return maxlen;
}
int main(int argc,char* argv[])
{
char arr[11];
int len;
printf("please input chararr(10):\n");
scanf("%s",arr);
len=ChildString(arr);
printf("the len of childarr is:%d\n",len);
return 1;
}
99. 计算字符串中子串出现的次数
方法1;
int main(int argc,char* argv[])90、输入一行字符,统计其中有多少个单词。
int main(int argc,char* argv[])
{
char string[81];
int i,num=0;//word=0;
char c;
gets(string); /*不能用scanf,视空格为终结*/
for(i=0;(c=string[i])!='\0';i++)
{
if(c==' ')
num++;
}
num++;
printf("Thereare %d words in theline\n",num);
return 1;
}
98某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。
#include97、809*??=800*??+9*??+1其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。
output(longb,long i)
{
printf("\n%ld/%ld=809*%ld+%ld",b,i,i,b%i);
}
int main()
{
long int a,b,i;
a=809;
for(i=10;i<100;i++)
{
b=i*a+1;
if(b>=1000&&b<=10000&&8*i<100&&9*i>=100)
output(b,i);
}
}
92、有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
#include "stdio.h"
Int main()
{
inti,j,k;
printf("\n");
for(i=1;i<5;i++) /*以下为三重循环*/
for(j=1;j<5;j++)
for (k=1;k<5;k++)
{
if (i!=k&&i!=j&&j!=k) /*确保i、j、k三位互不相同*/
printf("%d,%d,%d\n",i,j,k);
}
}
水仙花束问题:
#include
int main()
{
int i;
int num=0;
for(i=100;i<=999;i++)
{
int H,T,G,A;
H =i/100;
T=i/10%10;
G =i%10;
A =H*H*H +T*T*T + G*G*G;
if(A==i )
{
printf("%5d",i);
num++;
}
}
printf("thenum is %d\n",num);
return 1;
}
《《《《有关位操作的问题》》》》
93.取一个整数a从右端开始的4~7位。
Int main()
{
unsigned a,b,c,d;
scanf("%o",&a); /*scanf("%x",&a);16进制*/
b=a>>4;
c=~(~0<<4);// ~的优先级大于<<;
/*~0,11111111->11110000->括号外面00001111,保证低4位为1111*/
d=b&c;
printf("%o\n%o\n",a,d);
}
运行结果:输入:1234
输出:
1234
11(8进制)
78、请编写一个C 函数,该函数给出一个字节中被置1 的位的个数。
#include
#include
unsigned char CheckSetBitNum(unsigned char ucNumber)
{
unsigned char i;
unsigned char iResult=0;
for(i=0;i<8;i++)
{
iResult+= (ucNumber>>i) & 0x01; //第i位是1则加1,否则加0,位移动操作不改变原值
printf("ucNumber>>%d=%d\n",i,ucNumber>>i);
printf("iResult=%d\n",iResult);
}
return iResult;
}
int main(int argc,char* argv[])
{
unsigned char a;
int num;
scanf("%c",&a);
num=CheckSetBitNum(a);
printf("%d",num);
return 1;
}
方法2:
int count(int x)
{
int i,y,sum=0;
for (i=0;i<8;i++)
{
y=x%2; /*这是移出去的值*/
x=x/2; /*对于整数右移一次后x的值相当于右移前的值除以2*/
if (y==1) sum+=1;
}
return sum;
}
int main(int argc,char* argv[])
{
int x;
scanf("%d",&x);
printf("%d",count(x));
return 0;
}
字符串倒置
int main(int argc,char*argv[])
{
char* str="hello world";
char* des=NULL;
int len=strlen(str);
des=(char*)malloc(len+1);//结尾封口添0;
char* d=des;
char* s=&str[len-1];//指向最后一个字符;
while(len--!=0)
*d++=*s--;
*d='\0';//封口
printf("%s\n",des);
free(des);
return 1; 《《《《数组》》》》
94. 打印出杨辉三角形
int main()
{
int i,j,arr[11][11];
for(i=1;i<=10;i++)
for(j=1;j<=i;j++)
{
if(j==1||i==j)
arr[i][j]=1;
else
arr[i][j]=arr[i-1][j-1]+arr[i-1][j];
}
for(i=1;i<=10;i++)
for(j=1;j<=i;j++)
{
printf("%5d",arr[i][j]);
if(i==j)
printf("\n");
} return 1;
}
71.一语句实现x是否为2的若干次幂的判断。
void main()
{
int a;
scanf(“%d”,&a); printf(“%c”,(a)&(a-1)?’n’:’y’);
// 若是打印y,否则n
****************************************
2的n次幂用2进制表示一定是10,100,1000,10000......
对应的i-1就是1,11,111,1111.... i &(i-1)为false(也就是0)时就是返回true
******************************************************************************************************* ****************************
程序分析题
class A#include
#include
int main()
{
int a[4]={1,2,3,4};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
小端字节:*ptr2=0x2000000;
大端字节:*ptr2=0x100;
74、评价下面的代码片断:
unsigned intzero = 0;
unsigned intcompzero= 0xFFFF;
/*1‘s complement of zero */
【参考答案】对于一个int型不是16位的处理器为说,上面的代码是不正
确的。应编写如下:
unsigned intcompzero= ~0;
这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经
验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而
PC机程序往往把硬件作为一个无法避免的烦恼。
75.
char *ptr;
if ((ptr= (char *)malloc(0)) ==NULL)
puts("Gota nullpointer");
else
puts("Gota validpointer");
如果所请求的空间大小为0,其行为由库的实现者定义:可以返回空指针,也可以让效果跟申某个非0大小的空间一样,所不同的是返回的指针不可以被用来访问一个对象。
为什么 new T[0] 和 malloc(0) 不返回空指针
首先需要说明的是,按照C++标准,成功的 new T[0] 是不能返回空指针的。而 malloc(0),C 语言标准则指出,成功的时候可以返回空指针,也可以返回非空指针,多数库一般也选择了返回非空指针这种行为。
76.
int main(int argc,char* argv[])
{
char a='a',b='b';
int p,c,d;
p=a;
p=(p<<8)|b;
d=p&0xff;
c=(p&0xff00)>>8;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 1;
}
[运行结果]:97,98,97,98
77.
int main(int argc,char* argv[])
{
unsigned a,b;
printf("please input a number:");
scanf("%d",&a);
b=a>>5;
b=b&15;
printf("a=%d\tb=%d\n",a,b);
return 1;
}
【运行结果】:输入 64,输出2
指针数组:存放指针的数组;
Int* ptr[4]; (等同于二级指针 int** ptr)
一级指针是指向定义类型的内存地址,二级指针就是指向定义类型的内存地址所指向的新的内存地址
应用:指向若干字符串,整形数据等,使得元素处理更加方便;其中元素存放各对应地址;
此时,一级指针只能寻址到字符串所在的位置,并不能将其输出,因为没有其首地址,而**p则完成二级寻址,找到了位置,也找到了它的首地址,所以能输出
数组指针:指向一个数组的指针;
Int (*ptr)[4]
应用:可以应用在二维数组中;
指针函数:返回指针值得函数
Int* search(int num);
函数指针:指向函数的指针
Int (*ptr)(int num);/*申明一个函数指针*/
Ptr=fun();/*将fun函数地址付给指针ptr*/
Int a=fun(6).等价于,int a=(*ptr)(6);
函数指针数组: int(*s[10])(int) 函数指针数组
27、关键字volatile有什么含意?并给出三个不同的例子。
它是用来修饰被不同线程访问和修改的变量。
如果没有volatile,基本上会导致:要么无法编写多线程程序,要么编译器失去大量优化的机会。volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
中断服务程序中修改的供其它程序检测的变量需要加volatile;
3). 多线程应用中被几个任务共享的变量
多任务环境下各任务间共享的标志应该加volatile
3个关联的问题:37、Heap与stack的差别。
【标准答案】Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/放。
Stack空间有限,Heap是很大的自由存储区
C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行
40、带参宏与带参函数的区别(至少说出5点)?
带参宏 带参函数
处理时间: 编译时 运行时
参数类型: 无 定义类型
程序长度: 变长 不变
占用存储空间:否 是
运行时间: 不占用 调用和返回占用时间
38.用宏定义写出swap(x,y),即交换两数
#define swap(x, y) (x)=(x)+(y);(y)=(x)–(y);(x)=(x)–(y);
39. 写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
#define Min(X, Y) ((X)>(Y)?(Y):(X)) //结尾没有;
43、已知一个数组table,用一个宏定义,求出数据的元素个数。
【标准答案】#define NTBL(table) (sizeof(table)/sizeof(table[0]))
1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24* 365)UL
总结:有关宏定义#define 的基本语法
1#define的概念
#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。
该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。
(1) 简单的宏定义:
#define <宏名> <字符串>
例: #define PI 3.1415926
(2) 带参数的宏定义
#define <宏名>(<参数表>) <宏体>
例: #defineA(x) x
一个标识符被宏定义后,该标识符便是一个宏名。
这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。
2.宏定义的缺点
在简单宏定义的使用中,当替换文本所表示的字符串为一个表达式时,容易引起误解和误用。如下例:
例1 #define N 2+2
void main()
{
int a=N*N;
printf(“%d”,a);
}
(1) 出现问题:在此程序中存在着宏定义命令,宏N代表的字符串是2+2,该题的结果为8,
(2) 问题解析:宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8,这就是宏替换的实质,如何写程序才 能完成结果为16的运算呢?
(3)解决办法:将宏定义写成如下形式
#define N (2+2)
这样就可替换成(2+2)*(2+2)=16
在带参数的宏定义的使用中,极易引起误解。例如我们需要做个宏替换能求任何数的平方,这就需要使用参数,以便在程序中用实际参数来替换宏定义中的参数。一般学生容易写成如下形式:
#define area(x) x*x
这在使用中是很容易出现问题的,看如下的程序
void main()
{
int y=area(2+2);
printf(“%d”,y);
}
按 理说给的参数是2+2,所得的结果应该为4*4=16,但是错了,因为该程序的实际结果为8,仍然是没能遵循纯粹的简单替换的规则,又是先计算再替换了,在这道程序里,2+2即为area宏中的参数,应该由它来替换宏定义中的x,即替换成2+2*2+2=8了。那如果遵循(1)中的解决办法,把2+2 括起来,即把宏体中的x括起来,是否可以呢?#define area(x) (x)*(x),对于area(2+2),替换为(2+2)*(2+2)=16,可以解决,但是对于area(2+2)/area(2+2)又会怎么样 呢,这道题替换后会变为 (2+2)*(2+2)/(2+2)*(2+2)即4*4/4*4按照乘除运算规则,结果为16/4*4=4*4=16,那应该怎么呢?解决方法是在整个宏体上再加一个括号,即
#define area(x) ((x)*(x)),不要觉得这没必要,没有它,是不行的。
要想能够真正使用好宏 定义,
一定要记住先将程序中对宏的使用全部替换成它所代表的字符串,不要自作主张地添加任何其他符号,完全展开后再进行相应的计算,就不会写错运行结果。
如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中不只一个符号时,加上括号表现出优先级,如果是 带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号。
宏定义的优点:
(1) 方便程序的修改
使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时, 我们可以用较短的有意义的标识符来写程序,这样更方便一些。
(2) 提高程序的运行效率
使用带参数的宏定义可完成函数调用的功能,又能 减少系统开 销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。
49、什么是预编译,何时需要预编译:
【标准答案】1、总是使用不经常改动的大型代码体
2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
53、Typedef在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。
如,思考一下下面的例子:
#define dPSstructs *
typedefstructs * tPS;
以上两种情况的意图都是要定义dPS和tPS作为一个指向结构s指针。哪种方法更好呢?
答案是:typedef更好。思考下面的例子:
dPSp1,p2;
tPSp3,p4;
第一个扩展为
structs * p1, p2;
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许
不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
54.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?