字符串题目

声明:所有整理的题目均来自网路博文。原作者不一一列出,对原作者表示感谢。
为什么n &= (n – 1)能清除最右边的1呢?
因为从二进制的角度讲,n相当于在n - 1的最低位加上1。举个例子,8(1000)= 7(0111)+ 1(0001),所以8 & 7 = (1000)&(0111)= 0(0000),清除了8最右边的1(其实就是最高位的1,因为8的二进制中只有一个1)。再比如7(0111)= 6(0110)+ 1(0001),所以7 & 6 = (0111)&(0110)= 6(0110),清除了7的二进制表示中最右边的1(也就是最低位的1)。
 
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

/*求二进制数中1的个数*/
int BitCount2(unsigned int n)
{
    unsigned int i =0 ;
    for(i = 0; i < n; i++)
    {   
        n &= (n - 1) ; // 清除最低位的1
    }   
    return i ; 
}

int main(int argc, char *argv[])
{
    printf("%d\n", BitCount2(9));
    return 0;
}
------------------------------------
Linux某文件的权限为:drw-r--r-x,用数值形式表示该权限,则该八进制数为什么,该文件属性是什么?
drwxrwxr-x 3 ljq ljq 4096 Dec 14 12:24 .
drwxrwxr-x 3 ljq ljq 4096 Dec 14 10:19 ..
drwxrwxr-x 8 ljq ljq 4096 Dec 14 11:14 .git
-rwxrwxr-x 1 ljq ljq 7408 Dec 14 11:29 main
-rw-rw-r-- 1 ljq ljq  621 Dec 14 11:29 main.c
-rw-rw-r-- 1 ljq ljq 2450 Dec 14 10:23 main.tar.gz
其中,
d表示目录,-表示普通文件.
后面9位分为3组,每3组作为1组,从左到右分别表示 文件属主, 文件属组,和 其他所有用户的权限。
d:此文件是个实实在在的文件而非一个目录(目录也被认为是文件)
rw-:文件拥有者对此文件有读、写,没有执行的权限。
r--:同群组用户对此文件有读权限,没有用写、执行的权限。
r-x:其它用户对此文件有读、执行的权限,没有写权限。
八进制的语法使用数字表示各个权限分别是r(4)、w(2)、x(1)、-(0)。在本问题中属主权限位是rw-,转换为八进制为4+2+0=6,属组权限位r--转换为八进制为4+0+0=4。其他人权限位r--转换为八进制为4+0+0=4。将三个权限位表示起来是644。
修改文件权限。
chmod 775 filename

ps是linux下最常用的也是非常强大的进程查看命令。
ps -ef
-e 显示所有进程。
-f 全格式。
------------------------------------
20141209 xx笔试题回忆
选择题记不起了,记得一些不确定的的题目是:
1、一道题,将一个整数 10002 存到磁盘上,以ASCII码形式存储和以二进制形式存储,占用的字节数分别是 [C]。
A.2和2  B.2和5  C.5和2  D.5和5
这道题,二进制形式肯定是2,所以排除 BD 。
2、描述uboot流程。

u-boot系统启动流程 大多数bootloader都分为stage1和stage2两部分,u-boot也不例外。
依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
  1、Stage1 start.S代码结构 u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下
(1) 定义入口。: 
该工作通过修改连接器脚本来完成。
(2)设置异常向量(Exception Vector)。 
(3)设置CPU的速度、时钟频率及终端控制寄存器。 
(4)初始化内存控制器。 
(5)将ROM中的程序复制到RAM中。 
(6)初始化堆栈。 
(7)转到RAM中执行,该工作可使用指令ldr pc来完成。
2、Stage2
 C语言代码部分 lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作: 
(1)调用一系列的初始化函数。 
(2)初始化Flash设备。 
(3)初始化系统内存分配函数。 
(4)如果目标系统拥有NAND设备,则初始化NAND设备。 
(5)如果目标系统有显示设备,则初始化该类设备。 
(6)初始化相关网络设备,填写IP、MAC地址等。 
(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

3、strcpy题目(超高频率,理解也就没什么)
4、关键字volatile有什么含义?并给出三个不同的例子。
高频题,特别是嵌入式。
精确的说,优化器在用到这个变量时必须每次都小心的重新读取这个变量的值,而不是使用保存在寄存器里的备份。
volatile变量的几个例子:
并行设备的硬件寄存器(如状态寄存器);
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables);
多线程应用中被几个任务共享的变量。
4、嵌入式系统中经常要求程序去访问某特定内存的特点,在某工程中,要求设定一个绝对地址0x6799的整型变量的值为0xaa66。
也是嵌入式,很简单。
      int *p;
      p=(int*)0x67a9;
      *p=0xaa66
5、chmod 权限的相关,记不得了,我就记得chmod777权限很大。
6、实时操作系统的了解。
我只知道vxworks,风河公司的。
7、 请计算sizeof的值:
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
sizeof (str ) = ____
sizeof ( p ) = _____
sizeof ( n ) = _____
6,4,4
8、 请计算sizeof的值:
void Func ( char str[100])
{
// 请计算
sizeof( str ) = _____
}
4
9、 请计算sizeof的值:
void *p = malloc( 100 );
// 请计算
sizeof ( p ) = ______
4
10、#include “stdio.h”与#include <stdio.h>有什么区别?
用双引号表示先在用户目前查找。
用尖括号表示先在系统目录查找。
11、并发性的问题,我选的是一定时间间隔内。
在操作系统中,并发性是指若干事件( )发生。
A 在同一时刻    B 一定在不同时刻    C 在某一时间间隔     D 依次在不同时间间隔内
c
12、多道程序设计技术选择题
能充分发挥 CPU 和 外部设备并行工作的能力。
13、编写子函数:
(1)用冒泡法将一个数组排成升序的函数---SUB1;
(2)在升序数组中插入一个数,并且保持该数组仍为升序数组的函数---SUB2。
主函数:①输入任意10个正整数给数组;②调用SUB1对数组进行排序;③从键盘输入一个正整数,调用SUB2将其插入该数组。
题目很简单。
  1 #include <stdlib.h>
  2 #include <stdio.h>
  3 
  4 void bubble_sort(int inputPara[], int len)
  5 {
  6     int i, j;
  7     for (i = 0; i < len; i++)
  8     {
  9         for (j = len -1; j >= i; j--)
 10         {
 11             if (inputPara[j-1] > inputPara[j])
 12             {
 13                 inputPara[j-1] ^= inputPara[j];
 14                 inputPara[j] ^= inputPara[j-1];
 15                 inputPara[j-1] ^= inputPara[j];
 16             }
 17         }
 18     }
 19 }
 20 
 21 int main()
 22 {
 23     int iarray[1024] = {9, 5, 4 ,7, 8, 2, 1, 1};
 24     bubble_sort(iarray, 8);
 25     int i = 0;
 26     for (i = 0; i < 8; i++)
 27     {
 28         printf("%d ", *(iarray + i));
 29     }
 30     return 0;
 31 }
还有一些记不得了。
------------------------------------
为什么要进行进程间的通讯(IPC (Inter-process communication)) --数共通资进。
数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间
共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
linux常用的进程间的通讯方式
(1)、管道(pipe):管道可用于具有亲缘关系的进程间的通信,是一种半双工的方式,数据只能单向流动,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
(2)、命名管道(named pipe):命名管道克服了管道没有名字的限制,同时除了具有管道的功能外(也是半双工),它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3)、信号(signal):信号是比较复杂的通信方式,用于通知接收进程有某种事件发生了,除了进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
(4)、消息队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺。
(5)、共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6)、内存映射:内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
(7)、信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
(8)、套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
------------------------------------
进程和线程的理解之来龙去脉
抛开各种技术细节,从应用程序角度讲:
1、在单核计算机里,有一个资源是无法被多个程序并行使用的:cpu。
没有操作系统的情况下,一个程序一直独占着全都cpu。
如果要有两个任务来共享同一个CPU,程序员就需要仔细地为程序安排好运行计划--某时刻cpu和由程序A来独享,下一时刻cpu由程序B来独享。
而这种安排计划后来成为OS的核心组件,被单独名命为“scheduler”,即“ 调度器”,它关心的只是怎样把单个cpu的运行拆分成一段一段的“运行片”,轮流分给不同的程序去使用,而在宏观上,因为分配切换的速度极快,就制造出多程序并行在一个cpu上的假象。
2、在单核计算机里,有一个资源可以被多个程序共用,然而会引出麻烦:内存。
在一个只有调度器,没有内存管理组件的操作系统上,程序员需要手工为每个程序安排运行的空间 -- 程序A使用物理地址0x00-0xff,程序B使用物理地址0x100-0x1ff,等等。
然而这样做有个很大的问题:每个程序都要协调商量好怎样使用同一个内存上的不同空间,软件系统和硬件系统千差万别,使这种定制的方案没有可行性。
为了解决这个麻烦,计算机系统引入了“虚拟地址”的概念,从三方面入手来做:
2.1、 硬件上,CPU增加了一个专门的模块叫 MMU,负责转换虚拟地址和物理地址
2.2、 操作系统上,操作系统增加了另一个核心组件: memory management,即内存管理模块,它管理物理内存、虚拟内存相关的一系列事务。
2.3、 应用程序上,发明了一个叫做【进程】的模型,(注意)每个进程都用【完全一样的】虚拟地址空间,然而经由操作系统和硬件MMU协作,映射到不同的物理地址空间上。 不同的【进程】,都有各自独立的物理内存空间,不用一些特殊手段,是无法访问别的进程的物理内存的
3、现在,不同的应用程序,可以不关心底层的物理内存分配,也不关心CPU的协调共享了。然而还有一个问题存在:有一些程序,想要共享CPU,【并且还要共享同样的物理内存】,这时候,一个叫【线程】的模型就出现了,它们 被包裹在进程里面,在调度器的管理下共享CPU,拥有同样的虚拟地址空间,同时也共享同一个物理地址空间,然而,它们无法越过包裹自己的进程,去访问别一个进程的物理地址空间
4、进程之间怎样共享同一个物理地址空间呢?不同的系统方法各异,符合posix规范的操作系统都提供了一个接口,叫 mmap,可以把一个物理地址空间映射到不同的进程中,由不同的进程来共享。
5、PS:在有的操作系统里, 进程不是调度单位(即不能被调度器使用),线程是最基本的调度单位,调度器只调度线程,不调度进程,比如VxWorks
------------------------------------
关于socket和TCP/IP协议关系的理解
“TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”
------------------------------------
二分查找
int binSearch(int key,int array[], int length)
{
        int mid=0;
        int start = 0;
        int end = length - 1;
        while (start <= end) {
              mid = (end - start) / 2 + start;
              if (key == array[mid]) {
                     return mid;
              }
              if (key < array[mid]) {
                     end = mid - 1;
               } else if (key > array[mid]) {
                     start = mid + 1;
               } else {
                     return mid;
               }
        }
        return -1;
}
实现链表的逆置
node *inverselinklist(node *head)

{
        node *p1,*p2,*p3;
        if(NULL==head||NULL==head->next) {
               return head;
        }
        p1=head;
        p2=p1->next;
        while (p2) {
               p3=p2->next;
               p2->next=p1;
               p1=p2;
               p2=p3;
        }
        head->next=NULL;
        head=p1;
        return head;
}
判断链表是否有环?
#include <stdio.h>
void main(){
    int arr[]={6,7,8,9,10};
    int *ptr=arr;
    *(ptr++)+=123;
    printf("%d,%d",*ptr,*(++ptr));
}

输出(8,8)

注意区分:ptr++和++ptr
------------------------------------
修改字符串,则形式:
char string[] = “Hello,world!”;
进行声明并初始化。
char *ptr = “Hello,world!”; //Hello,world!存储在静态常量区,constdata段是常量数据段,ptr指向该Hello,world!”,即:ptr保存的是Hello,world!”在常量区的地址,注意生命周期
char * strcpy(char *dst,const char *src)
{
    assert(dst != NULL && src != NULL);
    char *ret = dst;
    while ((*(dst++) = *(src++)) != '\0') NULL;
    return (char *)ret;
}
char *strcat(char *strDest, const char *strSrc)
{
    char *address = strDest;
    assert((strDest != NULL) && (strSrc != NULL));
    while(*strDest != '\0' )
        strDest++;
    while((*strDest++ = *strSrc++) != '\0');
    return address;//为了实现链式操作,将目的地址返回
}
int strlen(const char *str)
{
    int len = 0;
    assert(str != NULL);
    while(*str++ != '\0')
        len++;
    return len;
}
int strcmp(const char *src, const char *dst)
{
    int ret = 0 ;
    assert((dst != NULL) && (src != NULL));
    while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
    {
        ++src;
        ++dst;
    }
    if(ret < 0)
        ret = -1;
    else if(ret > 0)
        ret = 1;
    return(ret);
}
------------------------------------
20141202面试题目(回忆大意)
1、关于指针的理解char *const *(*next)();
(*next) 指针
(*next)() 指向函数的指针
所以,next是个函数指针。
该函数的参数为空(任意),返回值类型是个二级指针char *const *,即:指向char型的指针的const指针。
/*关于指针的理解char *const *(*next)();
 *next是个函数指针。
 *该函数的参数为空(任意),返回值类型是个二级指针char *const *,即:指向char型的指针的const指针。
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
char * const *func(char * const *x)
{
    return x;
}
void main()
{
    char * const*(*f)(char * const *x);/* 声明f一个函数指针,函数的参数为指向char类型的指针的const指针*/
    f = func;
}
总结指针函数与函数指针最简单的辨别方式:
变量前的*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。
2、找出错误。
void GetMemory(char *p)
{
    p = (char *)malloc(100);
}
void Test( void )
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "hello world" );
    printf(str);
}
这段代码问题不少:
1、使用了malloc,却没有进行配对释放free,引发内存泄漏;
2、GetMemory(char *p)函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,str一直是是NULL。
3、(char *)malloc(100);修改为malloc(100 * sizeof(char));更加规范。
修改后:
#include <stdio.h>  
#include <stdlib.h>
#include <windows.h>
void GetMemory(char **p)
{
    //新开辟的100个字节的内存空间首地址赋给*p,*p即str,
    *p = (char *)malloc(100 * sizeof(char));
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str);
    strcpy(str, "hello world" );
    printf(str);
    if(str != NULL)
    {
        free(str);
        str = NULL;
    }
}
void main()  
{
    Test();
    system("pause");
}
拓展: 博客园
3、strcat函数C实现
#include <stdio.h>  
#include <stdlib.h>
#include <windows.h>
#include <assert.h>
//将源字符串加const,表明其为输入参数
char *MyStrcat(char *strDest, const char *strSrc)
{
    char *address = strDest;
    assert((strDest != NULL) && (strSrc != NULL));//对源地址和目的地址加非0断言
    while(*strDest != '\0' )
        //*strDest最后指向该字符串的结束标志’\0’。
        strDest++;
    while((*strDest++ = *strSrc++) != '\0');
    return address;//为了实现链式操作,将目的地址返回
}
void Test()
{
    char a[1024]= "markyuan";
    char b[6]= "yyyyy";
    char *cat = MyStrcat(a,b);
    printf("%s\n",cat);
}
void main()  
{
    Test();
    system("pause");
}
4、题目:小于99999的正整数中找符合下列条件的数,它既是完全平方数,又有两位数字相同,如:144,676。用c语言编写(不能用数字转换成字符串)。
笔试题每日几练 1-yuweixian4230-ChinaUnix博客
5、找错误。一个字符串逆序,abc变成cba。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>
char *my_strrev(char *str)
{
    char *end = str;
    char *start = str;
    while(*end != '\0')
        end++;
    end--;;
    while (start < end)
    {
        *start ^= *end;
        *end ^= *start;
        *start ^= *end;
        start++;
        end--;
    }
    return(str);
}
void main(){
    char a[] = "aBcDeF";
    printf("%s\n", my_strrev(a));
}
------------------------------------
题目:通过键盘输入一串小写字母(a~z)组成的字符串。请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串。
压缩规则:
1. 仅压缩连续重复出现的字符。比如字符串"abcbc"由于无连续重复字符,压缩后的字符串还是"abcbc".
2. 压缩字段的格式为"字符重复的次数+字符"。例如:字符串"xxxyyyyyyz"压缩后就成为"3x6yz"
要求实现函数: 
void stringZip(const char *pInputStr, long lInputLen, char *pOutputStr);
【输入】 pInputStr:  输入字符串
         lInputLen:  输入字符串长度         
【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长;
【注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出
#include <stdio.h>  
#include <stdlib.h>
#include <windows.h>
int stringZip(const char *strSrc, long len, char *strDest)  
{
    if(strSrc == NULL || len == 0 || strDest == NULL || len > 99)
        return 1;

    int countOfPerChar=0;
    for(int i = 0; i < len; i++)
    {
        if(strSrc[i] == strSrc[i+1])
            countOfPerChar++;
        else
        {
            countOfPerChar++;
            if(countOfPerChar == 1)
            {
                *strDest++ = strSrc[i];
            }
            else if(countOfPerChar <= 9)
            {
                *strDest++ = strSrc[i];
                *strDest++ = (char)(countOfPerChar + '0');//把数字1转换成字符‘1’
            }
            else if(countOfPerChar <= 99)
            {
                *strDest++ = strSrc[i];
                *strDest++ = (char)(countOfPerChar/10 + '0');
                *strDest++ = (char)(countOfPerChar%10 + '0');
            }
            countOfPerChar = 0;//统计完同一字符置为0
        }
    }
    *strDest++='\0';
    return 0;
}
void main()  
{  
    char *str = "111AAKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    int len = strlen(str);  
    char * outstr = (char *)malloc((len + 1) * sizeof(char));
    stringZip(str,len,outstr);  
    printf("%s\n",outstr);  
    free(outstr);  
    outstr = NULL;  
    system("pause");
}
------------------------------------
逆序字符串,如“this is a string”变成“string a is this”。
------------------------------------
复习:
在c中分为这4个存储区:
1.栈-有编译器自动分配释放
2.堆-一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,data段,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,bss段。-程序结束释放
4.另外还有一个专门放常量的地方。-程序结束释放
二.在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区、常量存储区。
1.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程>序结束后,操作系统会自动回收。
3.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
4.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
5.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)
所以静态变量和全局变量放在全局/静态存储区,而常量存放在常量存储区,程序代码当然放在代码区了
----------------------
    内核虚拟存储器
----------------------
    用户栈(Statk)
---------------------
    堆(Heap)
----------------------
    未初始化(BSS)
----------------------
    初始化(Data)
----------------------
    正文段(Text) 
----------------------
其中,
.text段是代码段。它用来放程序代码(code)。它通常是只读的。
.data段是数据段。它用来存放初始化了的(initailized)全局变量(global)和初始化了的静态变量(static)。它是可读可写的。
.bss段是全局变量数据段。它用来存放未初始化的(uninitailized)全局变量(global)和未初始化的静态变量(static)。它也是可读可写的。bss是英文BlockStartedbySymbol的缩写。之所以把bss跟data分开来,是因为系统会为这些bss段的变量的初值清零。
.constdata段是常量数据段。它用来存放常量(const)。它也是只读的。
源程序中使用malloc分配的内存就是bss这一块,它的大小不是根据data的大小确定的,主要是由程序中同时分配内存最大值所确定的,不过如果超出了范围,也就是分配失败,可以等空间释放之后再分配。
在ARM的集成开发环境中,
1、只读的代码段称为Code段,即上述的.text段。
2、只读的常量数据段,被称作RO Data段,即上述的.constdata段。
以上两个段统称为RO段(Read Only),放在ROM或FLASH等非易失性器件中。
3、可读可写的初始化了的全局变量和静态变量段,被称作RW Data段(ReadWrite),即上述的.bss段。
4、可读可写的未初始化的全局变量和静态变量段,被称作ZI Data段(Zero Init),即上述的.data段。因为这个段里的变量要被初始化为零,所以叫ZI段。
以上两个段统称为RW段,而在运行时,它必须重新装载到可读可写的RAM中。
------------------------------------
//在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。
#include <stdio.h>
#include <iostream>
using namespace std;
char firstNotRepeatingChar(char* pString, int lenth)
{
      if(pString == NULL ||lenth == 0 )
            return 1;
      const int tableSize = 256;
      int hashTable[tableSize];
      for(int i = 0; i < tableSize; i++)
            hashTable[i] = 0;

      char *pHashKey = pString;
      //for(int i = 0; i < lenth; i++)
      while(*(pHashKey) != '\0')
            hashTable[*(pHashKey++)]++;

      pHashKey = pString;
      //for(int i = 0; i < lenth; i++)
      while(*pHashKey != '\0')
      {
            if(hashTable[*pHashKey] == 1)//首次仅有一次,返回该字符
                  return *pHashKey;
            pHashKey++;
      }
      return 0;
} 
int main()
{
    char * strSrc = "abaccdeff";//"b";
    cout<<strSrc<<endl;
    char output = firstNotRepeatingChar(strSrc,strlen(strSrc));
    cout<<output<<endl;
    system("pause");
    return 0;
}
------------------------------------
/* 字符串中完成过滤重复字符的功能,
【输入】:1.常字符串;2.字符串长度;3.【out】用于输出过滤后的字符串.
【输出】:过滤后的字符串。
*/
#include <stdio.h>
#include <iostream>
using namespace std;
int stringFilterFast(const char *pInputStr, long lInputLen, char *pOutputStr)
{
    //边界处理
    if(pInputStr == NULL || pOutputStr ==NULL || lInputLen ==0)
        return 1;
    //变量初始化
    char rstChar = '\0';
    bool bNotRepeatFound = false;
    const unsigned int size = 256;
    unsigned int hashTable[size];//用于作为哈希表的数组
    const char* pHashKey = pInputStr;
    int outPutCnt = 0;
    //初始化哈希表
    for(unsigned int i = 0; i < size; i++)
        hashTable[i] = 0;
    //将pString读入到哈希表中
    while(*pHashKey != '\0')
    {
        cout<<*pHashKey;
        hashTable[*pHashKey++]++;//统计计数
        //hashTable[*pHashKey]++;/
        //pHashKey++;
    }
    cout<<endl;
    //读取哈希表,对只出现1次的进行存储,对出现多次的进行1次存储。
    pHashKey = pInputStr;
    while(*pHashKey != '\0')
    {
        if(1 == (hashTable[*(pHashKey)]))//仅有一次
        {
            pOutputStr[outPutCnt++] = *pHashKey;
        }
        else if((hashTable[*(pHashKey)]) > 1) //若大于一次,统计第一次,然后对应的哈希统计值置为0
        {
            pOutputStr[outPutCnt++] = *pHashKey;
            hashTable[*(pHashKey)] = 0;
        }
        pHashKey++;
    }
    pOutputStr[outPutCnt]= '\0';
    return 0;
}
int main()
{
    const char* strSrc = "desdefedeffdsswwwwwwwwwwdd";//"desfw";
    char *strRst = new char[strlen(strSrc)+1];
    int result = stringFilterFast(strSrc,strlen(strSrc), strRst);
    cout<<strRst<<endl;
    if(strRst != NULL)
    {
        delete []strRst;
        strRst = NULL;
    }
    system("pause");
    return 0;
}
------------------------------------
20141127mtk面试题目(回忆大意)
1、什么是预编译?为什么要预编译?
答:预编译又称为预处理,是做些代码文本的替换工作。
处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等。
2、预编译、编译、链接的过程是怎么样的?
参考:http://blog.csdn.net/eastonwoo/article/details/8655243
gcc的编译流程分为了四个步骤:
第一步,预编译,将程序中的宏定义等预编译;
第二步,编译,将*.h,*.c等文件编译成为*.o文件;
第三步,汇编;
第四步,连接,将*.o文件连接库,生成可执行文件。
3、查找如下代码有什么问题?有什么值得改进的地方?
int a[60][250][1000],i,j,k,total;
for(i=0;i<=1000;i++)
for(j=0;j<=250;j++)
for(k=0;k<=60;k++)
total +=a[i][j][k];
答:
    1、最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数;
    2、各种变量应初始化;
    3、total为int类型,长度可能不够;
    4、三重for循环改为一个for如循环,实现累加功能。
扩展:
在32位的系统上short 的内存大小是2 个byte;
int 的内存大小是4 个byte;
long 的内存大小是4 个byte;
float 的内存大小是4 个byte;
double 的内存大小是8 个byte;
char 的内存大小是1 个byte。
可能不同的平台还会有所不同,具体平台可以用sizeof关键字测试一下。
4、查找错误。实现fun1函数去3次或3以上调用func2函数?
int a=0;
void fun1()
{
    const int b =0
    while(a<10);
    b++;
    while(b>2)
        func2();
}
void func2()
{
    ...
}
void interrupt()
{
    a++;
}
答:并掉关键字const,改为volatile;a加上static、volatile修饰最好。
程序的本意是希望interrupt中断超过20次,fun1函数去调用func2函数。但是,由于编译器判断在fun1函数里面没有修改过i,因此可能只执行一次对从a到某寄存器的读操作,然后每次while判断都只使用这个寄存器里面的“a副本”,导致后边永远也不会被调用。如果变量加上static(全局)和volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。
5、下列代码的输出?
void main()
{
  int a[5]={1,2,3,4,5};
  int *ptr=(int *)(&a+1);
  printf("%d,%d",*(a+1),*(ptr-1));
}
答案:2,5
解析:*(a+1)其实很简单就是指a[1],输出为2.
&a+1如何理解?它不是首地址+1,系统会认为加了一个a类型相同数组,偏移了整个数组a的大小(也就是5个int的大小)。所以int *ptr=(int *)(&a+1);其实ptr实际是&(a[5]),也就是a+5.
&a是数组指针,其类型为int(*)[5];
而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同,a是长度为5的int数组指针,所以要加5*sizeof(int),所以ptr实际是a[5],但是ptr与(&a+1)类型是不一样的,这点非常重要,所以ptr-1只会减去sizeof(int*),a,&a的地址是一样的,但意思就不一样了,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]。
例子:
#include <stdio.h>
int a[4] = {1,2,3,4};
int main(){
    printf("a = %p\n", a); // I
    printf("&a = %p\n", &a); // II
    printf("a + 1 = %p\n", a + 1);// III
    printf("&a + 1 = %p\n", &a + 1);// IV
    int *ptr= (int *)(&a + 1);
    printf("*(ptr-1) = %p\n", *(ptr-1));// V
    return 0;
}
vs2008输出:

6、在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
解决名字匹配问题,实现C++与C的混合编程。
C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern"C"来解决名字匹配问题。
------------------------------------
冒泡排序Bubble sort
#include<iostream>
#include<stdlib.h>
#include<string>
using namespace std;
void bubble_sort(int inputPara[], int len)
{
    int temp;
    for (int i = 0; i < len -1; i++)
    {
        for (int j = i + 1; j < len; j++)
        {
            if (inputPara[i] > inputPara[j])
            {
                temp = inputPara[i];
                inputPara[i] = inputPara[j];
                inputPara[j] = temp;
            }
        }
    }
}
void main(int argc,char * argv[])
{
    int x[] = { 6, 2, 4, 1, 5, 9 };
    bubble_sort(x,6);
    return;
}
严格意义上说,不算是标准的冒泡排序算法,因为它不满足“ 两两比较相邻记录”的冒泡排序思想,它更应该是最最简单的交换排序而已。它的思路就是让每一个关键字,都和它后面的每一个关键字比较,如果大则交换,这样第一位置的关键字在一次循环后一定变成最小值。
void bubble_sort(int inputPara[], int len)
{
    for (int i = 0; i < len; i++)
    {
        for (int j = len -1; j >= i; j--)
        {
            if (inputPara[j-1] > inputPara[j])
            {
                inputPara[j-1] ^= inputPara[j];
                inputPara[j] ^= inputPara[j-1];
                inputPara[j-1] ^= inputPara[j];
            }
        }
    }
}
void bubble_sort(int inputPara[], int len)
{
    bool flag = true;
    for (int i = 0; i < len && true; i++)
    {
        for (int j = len -1; j >= i; j--)
        {
            flag = false;
            if (inputPara[j-1] > inputPara[j])
            {
                inputPara[j-1] ^= inputPara[j];
                inputPara[j] ^= inputPara[j-1];
                inputPara[j-1] ^= inputPara[j];
                flag = true;
            }
        }
    }
}
------------------------------------
20141120一道字符串排序机考题目。
题目大意是:输入字符串,按照ascii值到字符‘U’的绝对值大小进行升序排列,如果绝对值相等,则按照原序排列。
输入:Ae1
输出:eA1
//输入字符串,按照ascii值到字符‘U’的绝对值大小进行升序排列,如果绝对值相等,则按照原序排列。
#include<iostream>
#include "stdlib.h"
using namespace std;
int upSort(char *in, int len, char *out)
{
    if(in == NULL) return 1;
    if(out == NULL) return 2;
    if(len == 0) return 3;
    if(len > 1024) return 4;
    char temp, tempCount;
    char count[1024] = {0};
    for(int i = 0; i < len; i++)
    {
        if(in[i] < 'U')
        {
            count[i] = 'U' - in[i];
        }
        else
        {
            count[i] = in[i] - 'U';
        }
    }
    count[len] = '\0';
    for(int i = 0; i < len -1; i++)
        for(int j = i + 1; j < len; j++)
        {
            if(count[i] > count[j])
            {
                tempCount = count[i];
                count[i] = count[j];
                count[j] = tempCount;

                temp = in[i];
                in[i] = in[j];
                in[j] = temp;
            }
        }
    strcpy(out, in);
    return 0; 
}
int main(int argc, char* argv[])
{
    int flag = 0;
    int length;
    char s[1024];
    char t[1024];
    cin>>s;
    length = strlen(s);
    flag = upSort(s, length, t);
    if(0 == flag)
        cout<<t<<endl;
    else
        cout<<"请检查输入的正确性!"<<endl;
    system("pause");
    return 0;
}
------------------------------------
输入一串字符,只包含“0-10”和“,”,找出其中最小的数字和最大的数字(可能不止一个),输出最后剩余数字个数。
如:输入 "3,3,4,5,6,7,7"
输出 3 
------------------------------------
通过键盘输入一串小写字母(a~z)组成的字符串。请编写一个字符串过滤程序,若字符串中出现多个相同的字符,将非首次出现的字符过滤掉。
比如字符串“abacacde”过滤结果为“abcde”。
要求实现函数: 
void stringFilter(const char *pInputStr, long lInputLen, char *pOutputStr);
输入】 pInputStr:  输入字符串                lInputLen:  输入字符串长度         
输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长;
注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出。
示例: 
输入:“deefd”        输出:“def”
输入:“afafafaf”     输出:“af”
输入:“pppppppp”     输出:“p”
/* main函数已经隐藏,这里保留给用户的测试入口,在这里测试你的实现函数,可以调用printf打印输出*/
/* 当前你可以使用其他方法测试,只要保证最终程序能正确执行即可 */
/* 该函数实现可以任意修改,但是不要改变函数原型。一定要保证编译运行不受影响*/
#include <stdio.h>  
#include<stdlib.h>
#include<windows.h>
#include<iostream>
using namespace std;
void stringFilter(const char *p_str, long len, char *p_outstr)
{
    if(p_str == NULL || p_outstr == NULL)//输入参数有效性判断
    {
        p_outstr = NULL;
        return;
    }

    int count[26] = {0};//计数器
    char tmp;
    int j = 0;
    for(int i = 0;i < len; i++)
    {
        tmp = p_str[i] - 'a';
        if(count[tmp] == 0)
        {
            count[tmp]++;
            //p_outstr[j++] = p_str[i];
            p_outstr[j] = p_str[i];
            j++;
        }
    }
    p_outstr[j] = '\0';
}
void main()
{
    char inputStr[1024];
    int len;
    cout<<"请输入小写字母a-z,字符串长度限定在1024范围内"<<endl;
    cin>>inputStr;
    len = strlen(inputStr);
    if(len > 1024)
    cout<<"输入字符串太长,请限定在1024范围内"<<endl;
    //分配内存
    char *outStr = (char *)malloc(len * sizeof(char));//分配内存
    stringFilter(inputStr, len, outStr);
    printf("%s", outStr);  
    //释放申请的内存,并将指针置为空。
    free(outStr);
    outStr = NULL;
    system("pause");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值