6916|37

6366

帖子

4917

TA的资源

版主

楼主
 

我解C语言面试题系列 [复制链接]

声明:本内容来自CSDN博客,原作者ammana_babi

本系列文章我已整理成WORD文档,在下载中心可以直接下载,下载地址如下:
https://download.eeworld.com.cn/detail/tiankai001/12768


【我解C语言面试题系列】001 static有什么用途?
【题目】static有什么用途?
在网上流传很广的一个答案是:
1、限制变量的作用域
2、设置变量的存储域
    我觉得这样答题是不妥当的,有点文不对题的感觉。
下面是我给出的答案:
static 类型声明符在C语言里面主要有三个用途:
1、声明静态局部变量。
2、声明静态外部全局变量。
3、声明静态外部函数。
下面是我整理的有关上面三个用法的解释说明。另外网友xiaocai0001的《static用法小结》一文有更详细的解释,请参考。
静态局部变量(与auto对比)
1、  存储空间分配、作用域和生存期
static分配在静态存储区,作用域仅仅限于声明该变量的函数内部。在程序
整个运行期间都不释放,生存期贯穿于程序运行的整个过程。
auto类型分配在栈上,属于动态存储类别,占动态存储区空间,作用域仅仅限于声明该变量的函数内部。函数调用结束后自动释放,生存期不过是在声明该变量的函数内部。
2、赋初值时的处理方式
static静态局部变量在编译时赋初值,即只赋初值一次;
auto自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
3、未赋初值时的处理方式
如果在定义局部变量时不赋初值的话:
static静态局部变量,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。
auto自动变量,如果不赋初值则它的值是一个不确定的值。
静态外部全局变量
在C语言中static还用来声明静态外部全局变量,那么这个全局变量的作用域就被限制在本文件内部。
外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。
而如果我们声明的全局变量不想被其他文件访问和使用又该怎么办?
那就是在声明的时候前面加上关键字static。
静态外部函数
在C语言中我们的函数默认都是全局的,也就是说你可以调用其他文件中的函数。在使用的时候,我们象前面一样在头文件中加上extern就可以了。但是有时候我们写的函数并不想让别的文件访问和调用,那么我们在声明函数的时候前面加上static就可以了。
使用内部函数的好处有二:
1、可以让某些内部函数不为人所能使用,而仅仅让调用者使用他能使用的东西,有利于保护代码。
2、不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同


[ 本帖最后由 tiankai001 于 2013-4-18 18:15 编辑 ]

最新回复

我也顶顶顶呀  详情 回复 发表于 2013-4-20 12:59
点赞 关注
 
 

回复
举报

6366

帖子

4917

TA的资源

版主

沙发
 
【我解C语言面试题系列】002 局部变量和全局变量小结


局部变量和全局变量小结
局部变量
局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内部,离开该函数后再使用这种变量是非法的。
局部变量从存储方式上可分为动态(auto)存储类型和静态(static)存储类型。
动态存储类型的局部变量都是动态的分配存储空间,数据存储在动态存储区(栈)中。函数调用结束后自动释放,生存期是在声明该变量的函数执行过程。
静态存储类型的局部变量则是静态的分配存储空间,数据存储在静态存储区中。在程序整个运行期间都不释放,生存期贯穿于程序运行的整个过程。
函数中的局部变量,如不专门声明为static存储类别,默认都是动态地分配存储空间的,我们在平时的声明变量的过程中auto都是默认省略的。
全局变量
全局变量也称为外部变量,是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不动态地进行分配和释放;
如果外部变量不在文件的开头定义,其有效作用域只限于定义处到文件终
如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。其有效作用域就被拓展到从这个文件extern声明处到文件结束
如果在全局变量声明的时候,前面加上关键字static,那么其他文件就不能再访问和使用该变量,其有效作用域只限于定义处到文件终
局部变量能否和全局变量重名
       局部变量能和全局变量重名,但是局部变量会屏蔽全局变量。在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。
PS:这对extern声明的全局变量也一样
 
 
 

回复

6366

帖子

4917

TA的资源

版主

板凳
 
【我解C语言面试题系列】003 死循环格式问题小结

死循环格式问题小结
下面是几个"著名"的死循环:
(1)操作系统死循环;
(2)WIN32程序死循环;
(3)嵌入式系统软件死循环;
(4)多线程程序的线程处理函数死循环。
而有的时候我们在程序中也要使用死循环,只有当条件满足的时候,才可以break 退出死循环,继续下面的代码的执行。死循环的方案有两个:
while (1)
{
       ……
}
for ( ; ; )
{
       ……
}
第一种格式往往是我们的首选方案。
第二种格式则由于这个语法没有确切表达代码的含义,我们从for ( ; ; ) 看不出什么,只有弄明白for ( ; ; ) 在C语言中意味着无条件循环才明白其意。有的程序员更是把第二种格式写成了 for ( ;1 ; ),更是迷惑人。我们不要求所有人的所有代码格式都统一,但是象这种情况,还是统一一点的比较好,因为这样读你代码的人会更舒服一些,可以增强程序员间的代码交流。死揪语法,狠钻牛角尖,代码写的乱七八糟,各有各的一套,那对于代码维护来说是要付出很大代价的。
在C程序中,特别是嵌入式程序中除主程序的死循环外,一般的人都建议不要使用死循环,因为一旦你的代码稍微出现小的失误,就会造成当机,这是做嵌入式的人最不愿意看到的,因为QA(质量测试部门)是绝对不允许这种程序通过测试走货的。但是,在有的时候我们又不可避免的要使用死循环,所以要视具体情况而定。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

4
 
【我解C语言面试题系列】004 数组的循环右移问题

数组的循环右移
【题目】有一个整数数组,现要求实现这个整数数组的循环右移。如:1,2,3,4,5 则循环右移两位后结果是:4,5,1,2,3。
方法一:(最最容易想到的办法)
void RightCircleShift_00(int buffer[],int shift)
{
    int i,j,tt;
   
    for(i=0;i
    {
       tt = buffer[ARRSIZE-1];
       for(j=ARRSIZE-1;j>0;j--)
           buffer[j] = buffer[j-1];
       buffer[0] = tt;
    }
}
这个办法是用两个循环来控制,内循环每次向右移动一位,外循环则用来限制移动的位数。算法需要执行 ARRSIZE * ShiftValue次,时间复杂度是O( N2 )。
方法二:(由方法一得到的递归程序)
void RightCircleShift_01(int buffer[],int shift)
{
    int *p,tt;
   
    tt = *(buffer+ARRSIZE-1);
    for(p = buffer+ARRSIZE-1;p > buffer;p--)
       *p = *(p-1);
   
    *buffer = tt;
    shift--;
    if(shift > 0)
        RightCircleShift_00(buffer,shift);
}
这个程序跟方法一类似,区别就是它是用递归来实现的。同样需要执行ARRSIZE * ShiftValue次,时间复杂度也是O( N2 )。
方法三
void RightCircleShift_02(int buffer[],int shift)
{
    int *title,*r,*p;
   
    if(shift == 0)
       return;
   
    shift = shift % ARRSIZE;
   
    title = (int *)malloc(sizeof(int)*shift);
    if( title == NULL )
       return;
   
    r = buffer + (ARRSIZE - shift);
    memcpy(title, r, shift * sizeof(int));
    p = buffer + shift;
    memmove(p, buffer, (ARRSIZE - shift) * sizeof(int));
    memcpy(buffer, title, shift * sizeof(int));
   
    free(title);
}
这个算法需要移动位数大小的临时辅助空间。如需移动两位,则申请两个的空间,然后把从右边起的两个元素拷贝的临时辅助空间,然后前面的元素向后移动两位,最后再把临时空间里面的两个元素拷贝到前面的两位即可完成循环右移。需要执行 ARRSIZE次,时间复杂度是O( N )。
方法四:
void RightCircleShift_03(int buffer[],int shift)
{  
    if(shift <= 0)
       return;
    if( (shift & 1) == 0)
    {
       BufferShiftEvenNumber(buffer,shift-1);
       BufferShiftEvenNumber(buffer,1);
    }
    else
       BufferShiftEvenNumber(buffer,shift);
      
}
void BufferRightShiftEvenNumber(int buffer[],int shift)
{
    int i,j,tt,res;
    res = buffer[0];
    for (i=0,j=0; i
    {
       tt = res;
       res = buffer[(j+shift)%ARRSIZE];
       buffer[(j+shift)%ARRSIZE] = tt;
       j = (j+shift) % ARRSIZE;
    }
}
这个算法并不需要开额外的辅助空间,而且时间复杂度同样也是O( N )。BufferRightShiftEvenNumber函数是这个算法的核心,该函数只能实现每次向右移动奇数位元素。如果要移动的位数是偶数的时候就需要把该数分解为两个奇数,n = (n – 1) + 1 。
方法五:
void RightCircleShift_04(int buffer[],int shift)
{
    shift %= ARRSIZE;
    ReverseArray(buffer,1,ARRSIZE);
    ReverseArray(buffer,1,shift);
    ReverseArray(buffer,shift+1,ARRSIZE);
}
void ReverseArray(int buffer[],int start,int end)
{
    int i,tt;
    if(end > ARRSIZE)
       return;
    start -= 1;
    end -= 1;
    while(start < end)
    {
       tt = buffer[start];
       buffer[start++] = buffer[end];
       buffer[end--] = tt;
    }
}
这个办法也是很不错,需要两次扫描数组即可,时间复杂度O(N)。这个办法跟 方法四 移动偶数个元素的情况一样,都是需要两次扫描数组。当然如果是移动奇数个元素的话,则不如方法四有效,方法四只需要扫描一次数组就可以了。
算法是网友 luodongshui 提出的:
1、先将整个数组反转。
2、然后再反转前shift个元素。
3、接着再反转后N-shift个元素。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

5
 
【我解C语言面试题系列】005 按位反转字符问题
按位反转字符问题
Write a C function to swap the bits of a unsigned char so that its bits become the mirror image of the char. MSBs become its LSBs, e.g.  01111000 binary should become 00011110 binary.
方法一:(最最容易想到的办法)
unsigned char ReverseBitsInChar00(unsigned char Num)
{
    unsigned char ret = 0;
    int i;
    for(i=0;i<8;i++)
    {
       ret <<= 1;
       ret |= Num & 1;
       Num >>=  1;
    }
    return ret;
}
上面的程序通过每次取传入参数的最后一位( Num & 1),然后与要返回的结果相 “ 或 ”,把传入参数 Num 右移 1 位,要返回的结果左移一位,来实现数字反转的。
方法二:  (对换)
unsigned char ReverseBitsInChar01(unsigned char Num)
{
    unsigned char ret = 0;
    int i;
    for(i=0;i<4;i++)
    {
         ret |= (Num & (1 << i)) << (7-2*i);
         ret |= (Num & (0x80 >> i) ) >> (7-2*i);
    }
    return ret;
}
上面的程序通过对换来实现的。
1、先找到低位,然后移动到对应的高位,再与要返回的结果 或 。
2、再找到高位,然后移动到对应的低位,再与要返回的结果 或。
3、循环,直至对换 4 次。
方法三:   (分而治之)
unsigned char ReverseBitsInChar02(unsigned char Num)
{
    Num = (Num & 0x55) <<  1  | (Num >>  1) & 0x55;
    Num = (Num & 0x33) <<  2  | (Num >>  2) & 0x33;
    Num = (Num & 0x0F0F) <<  4  | (Num >>  4) & 0x0F0F;
    return Num;
}
上面的程序采用的是分而治之的策略( divide and conquer strategy )。把反转32
位的程序分别分解为反转 2 位、4 位来实现的。无论是对于要反转几位,他们的算法是类似的。
1、取低位,左移。
2、右移,取高位。
3、( 1、2 的结果) 或
方法四:   (分而治之)
unsigned char ReverseBitsInChar03(unsigned char Num)
{
    Num = (Num & 0x55) <<  1 | (Num & 0xAA) >>  1;
    Num = (Num & 0x33) <<  2 | (Num & 0xCC) >>  2;
    Num = (Num & 0x0F) <<  4 | (Num & 0xF0) >>  4;
    return Num;
}
这个程序采用的也是分而治之的策略( divide and conquer strategy )。把反转32
位的程序分别分解为反转 2 位、4 位来实现的。无论是对于要反转几位,他们的算法是类似的。
1、取低位,左移。
2、取高位,右移。
3、( 1、2 的结果) 或
上面的四个程序,前两个是我写的,是一个按照常规思维方式写的代码。后面的两个来自于 Henry S.Warren 的 《Hacker's Delight》一书中的有关 Reversing Bits 的相关介绍。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

6
 
【我解C语言面试题系列】006 按位反转整数问题
按位反转整数问题
Write a C function to swap the bits of a unsigned int so that its bits become the mirror image of the char. MSBs become its LSBs, e.g.  0111100011110111 binary should become 1110111100011110 binary.
方法一:(最最容易想到的办法)
unsigned int ReverseBitsInWord00(unsigned int Num)
{
    unsigned int ret = 0;
    int i;
   
    for(i=0;i<32;i++)
    {
       ret <<= 1;
      ret |= Num & 1;
      Num >>=  1;
    }
   
    return ret;
}
上面的程序通过每次取传入参数的最后一位( Num & 1),然后与要返回的结果相 “ 或 ”,把传入参数 Num 右移 1 位,要返回的结果左移一位,来实现数字反转的。

方法二:   (对换)
unsigned int ReverseBitsInWord01(unsigned int Num)
{
    unsigned int ret = 0;
    int i;
   
    for(i=0;i<16;i++)
    {
         ret |= (Num & (1 << i)) << (31-2*i);
         ret |= (Num & (0x80000000 >> i) ) >> (31-2*i);
    }
    return ret;
}
上面的程序通过对换来实现的。
1、先找到低位,然后移动到对应的高位,再与要返回的结果 或 。
2、再找到高位,然后移动到对应的低位,再与要返回的结果 或。
3、循环,直至对换 16 次。
方法三:   (分而治之)
unsigned int ReverseBitsInWord02(unsigned int Num)
{
    Num = (Num & 0x55555555) <<  1  | (Num >>  1) & 0x55555555;
    Num = (Num & 0x33333333) <<  2  | (Num >>  2) & 0x33333333;
    Num = (Num & 0x0F0F0F0F) <<  4  | (Num >>  4) & 0x0F0F0F0F;
    Num = (Num & 0x00FF00FF) <<  8  | (Num >>  8) & 0x00FF00FF;
    Num = (Num & 0x0000FFFF) <<  16 | (Num >>  16) & 0x0000FFFF;
   
    return Num;
}
上面的程序采用的是分而治之的策略( divide and conquer strategy )。把反转32位的程序分别分解为反转 2 位、4 位、8位、16位来实现的。无论是对于要反转几位,他们的算法是类似的。
1、取低位,左移。
2、右移,取高位。
3、( 1、2 的结果) 或
方法四:   (分而治之)
unsigned int ReverseBitsInWord03(unsigned int Num)
{
    Num = (Num & 0x55555555) <<  1 | (Num & 0xAAAAAAAA) >>  1;
    Num = (Num & 0x33333333) <<  2 | (Num & 0xCCCCCCCC) >>  2;
    Num = (Num & 0x0F0F0F0F) <<  4 | (Num & 0xF0F0F0F0) >>  4;
    Num = (Num & 0x00FF00FF) <<  8 | (Num & 0xFF00FF00) >>  8;
    Num = (Num & 0x0000FFFF) << 16 | (Num & 0xFFFF0000) >> 16;
    return Num;
}
这个程序采用的也是分而治之的策略( divide and conquer strategy )。把反转32位的程序分别分解为反转 2 位、4 位、8位、16位来实现的。无论是对于要反转几位,他们的算法是类似的。

1、取低位,左移。
2、取高位,右移。
3、( 1、2 的结果) 或

上面的四个程序,前两个是我写的,是一个按照常规思维方式写的代码。后面的两个来自于 Henry S.Warren 的 《Hacker's Delight》一书中的有关 Reversing Bits 的相关介绍。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

7
 
【我解C语言面试题系列】007 运算符优先级问题
运算符优先级问题
给出下面程序的运行结果:
int main()
{
    if( 0 & 1 == 0)
       printf("0 & 1 == 0/n");
    else
       printf("0 & 1 != 0/n");
   
    if( 0 & 1 != 0)
       printf("0 & 1 != 0/n");
    else
       printf("0 & 1 == 0/n");
   
    system("pause");
    return 0;
}
答案是:
0 & 1 != 0
0 & 1 == 0
而不是我们想象中的
0 & 1 == 0
0 & 1 == 0
== 和 != 运算符优先级要高于 &、^、|、&&、|| 运算符,所以,
if( 0 & 1 == 0) 相当于 if( 0 & (1 == 0) )     执行else。
if( 0 & 1 != 0) 相当于 if( 0 & (1 != 0) )   执行else。
    这个面试题不是要求我们强记住运算符的优先级,而是因为这个问题让很多程序员想当然是这样,结果最后debug后,才发觉是自己吃了亏,程序运行结果并不是自己想要的结果。这仅仅是告诉C/C++程序员一个很容易犯错误的陷阱。

 
 
 

回复

6366

帖子

4917

TA的资源

版主

8
 
【我解C语言面试题系列】008 去除数组中重复数字问题
去除数组中重复数字问题
有一个大小为100的数组,里面的数字均介于1到99之间,但是里面的数字有重复,请写个函数去除数组中的重复数字。
#define    INIT_NUM -1
方法一:(最最容易想到的办法)
void RemoveBufferRepNum_00(int buffer[])
{
    int i,j;
    for(i=0;i
    {
       for(j = i+1;j
       {
           if(buffer == buffer[j])
           {
              buffer = INIT_NUM;
              break;
           }
       }
    }
   
    for(i=0,j=0;i
    {
       if(buffer == INIT_NUM)
           continue;
       buffer[j++] = buffer;
    }
    while(j < BUFFERSIZE)
        buffer[j++] = INIT_NUM;
}
这个算法最简单,时间复杂度是O(N2)
方法二:(采用hash表法解决)
void RemoveBufferRepNum_01(int buffer[])
{
    int tBuffer[BUFFERSIZE];
    int i = 0,j = 0;
   
    for(i=0;i
       tBuffer = INIT_NUM;
    for(i=0;i
    {
       if(tBuffer[buffer] == INIT_NUM)
           tBuffer[buffer] = buffer;
    }
    for(i=0;i
    {
       if(tBuffer == INIT_NUM)
           continue;
       buffer[j++] = tBuffer;
    }
    while(j < BUFFERSIZE)
        buffer[j++] = INIT_NUM;
}
这个办法是用开辅助空间,设置hash表来实现的,总共执行N次就可以了。时间复杂度是:O( N )。但是唯一的弱点就是需要额外的空间。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

9
 
【我解C语言面试题系列】009 特殊的去除数组中重复数字问题

特殊的去除数组中重复数字问题
有一个大小为101的数组,里面的数字均介于0到99之间,但是里面的数字仅有一个数字是重复的,请写个函数去除数组中的重复数字。
#define       INIT_NUM          -1
#define       BUFFERSIZE     101
方法一:(最最容易想到的办法)
void RemoveBufferRepNum_00(int buffer[],int *num,int *loc)
{
    int i,j;
   
    for(i=0;i<100;i++)
    {
       for(j=i+1;j<101;j++)
       {
           if(buffer == buffer[j])
           {
              *num = buffer[j];
              *loc = j+1;
              return;
           }
       }
    }
}
    这个算法最简单,时间复杂度是O(N2)
方法二:(采用hash表法解决)
void RemoveBufferRepNum_01(int buffer[],int *num,int *loc)
{
    int tBuffer[BUFFERSIZE];
    int i = 0,j = 0;
   
    for(i=0;i
       tBuffer = INIT_NUM;
    for(i=0;i
    {
       if(tBuffer[buffer] == INIT_NUM)
           tBuffer[buffer] = buffer;
       else
           break;
    }
    *num = buffer;
    *loc = i+1;
   
    while(i < BUFFERSIZE-1)
    {
        buffer = buffer[i+1];
        i++;
    }
    buffer = INIT_NUM;
}
这个办法是用开辅助空间,设置hash表来实现的,总共执行N次就可以了。时间复杂度是:O( N )。但是唯一的弱点就是需要额外的空间。
方法三:(采用折半查找法)

void RemoveBufferRepNum_02(int buffer[],int *num,int *loc)

{

    int i,j,low,high,left=0,right=0,value;

    low = 0,high = BUFFERSIZE-2;

    while(low <= high)//查找重复数字

    {

       value = (low + high)/2;//low + ((high - low)/2);

       for(i = 0;i

       {

           if( buffer > value)

              right++;

           if( buffer < value)

              left++;

       }

       if( (right == (BUFFERSIZE-2 - value)) && (left == value) )

           break;

       else if(right > (BUFFERSIZE-2 - value))

       {

           low = value;

           right = 0;

           left = 0;

       }

       else if(left > (value-0))

       {

           high = value;

           right = 0;

           left = 0;

       }

    }

    j = 0;

    for(i = 0;i

    {

       if(buffer == value)

           j++;

       if(j == 2)

           break;

    }

    *num = buffer;

    *loc = i+1;

   

    while(i < BUFFERSIZE-1)

    {

        buffer = buffer[i+1];

        i++;

    }

    buffer = INIT_NUM;

}
这个题目很特殊,数组大小为101,而所有的数字范围是0~99,只有一个是重复的。这里我们就可以采用折半的思想来解决(对于一般的要去掉多个重复数字的情况未必有效)。0~99之间共有100个数字,只有一个重复。
我们可以猜测这个重复的数字是50(处于中间的数字),那么在0~49之间有50个数字,在51~99之间49个数字。如果有一边大于它所应该有的数字个数,那么这个重复数字就肯定在多出来一个那一边。然后再拿出一个中间数字来猜测,不断的去拿中间的数字来猜测,直到猜出那个重复的数字为止。
因为 100 大于 2的6次方,小于 2的7次方。所以我们猜测到这个重复数字的次数最多是7次,最后加上1次查找循环,最多是需要8次扫描数组。时间复杂度是:O( N * log2 N )。相对于方法一来说已经大大的降低了执行次数,相对于方法二来说执行次数是仅仅是log2 N倍,这已经是在不增加额外空间的前提下修改 O(N2) 级别算法的较理想办法了。
方法四:

void RemoveBufferRepNum_03(int buffer[],int *num,int *loc)

{

    int i,j,tt;

    for(i=0,tt=0;i

       tt += buffer;

    tt -= 4950;

    for(i=0,j=0;i

    {

       if(buffer == tt)

           j++;

       if(j == 2)

           break;

    }

    *num = buffer;

    *loc = i+1;

    while(i < BUFFERSIZE-1)

    {

        buffer = buffer[i+1];

        i++;

    }

    buffer = INIT_NUM;

}
本算法是经过网友的提醒,采用的是求和取余的办法来得到多余数字的,这个算法太巧妙了,很好的利用了题目中所给的条件。
0+1+2+3+4+5+…+98+99 = 4950 。题目说的是多而且只多一个重复的数字,那么所有的数字相加求和后减去 4950,余下的那个数就是重复数字。
然后我们再扫描一遍数组,找到数字的位置即可,时间复杂度是:O( N )。一个不加任何辅助空间,效率高的算法。这个算法来自于一个网友的提醒,这里先谢谢这个网友了。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

10
 
【我解C语言面试题系列】010 从相应位置开始删除指定字符串的相应个字符
从相应位置开始删除指定字符串的相应个字符
假设一个字符串 " abcdefg ",那么请你写一个函数,该函数将会从指定位置开始,删除指定长度的字符。如:要从第二个开始,删除2两个字符。则删除后的字符串是 “adefg”。

char *DeleteTheCharacters(char *str,int pos,int len)

{

    char *p = str+pos-1;

    int tt = strlen(str);

   

    // If over the p && (p + len) over the length of str

    if( pos < 1)         return str;

    if( (p-str) > tt )   return str;

    if( (p+len-str) > tt)

    {

        *p = '/0';

       return str;

    }

   

    //Delete the len characters

    while(*p && *(p+len))

    {

       *p = *(p+len);

       p++;

    }

    *p = '/0';

   

    return str;

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

11
 
【我解C语言面试题系列】011 删除指定字符串的相应字符
删除指定字符串的相应字符
假设字符串 "cabcdefcgchci" ,那么要求你写一个函数,把该字符串中所有的字符 ’c’ 删除掉。那么结果应该是 "abdefghi"。
00和01是用for循环来实现的算法

char * DeleteChararcter_00(char *str,int c)

{

    char *p,*ret;

   

    for(ret= p = str;*p;p++)

    {

       if(*p == c)

           continue;

       *str++ = *p;

    }

    *str = '/0';

    return ret;

}

char * DeleteChararcter_01(char *str,int c)

{

    char *p,*ret;

   

    for(ret= p = str;*p;p++)

    {

       if(*p != c)

           *str++ = *p;

    }

    *str = '/0';

    return ret;

}

02和03是用while循环来实现的算法

char * DeleteChararcter_02(char *str,int c)

{

    char *p,*ret;

   

    ret = p = str;

    while(*p)

    {

       if(*p++ == c)

           continue;

       *str++ = *(p-1);

    }

    *str = '/0';

    return ret;

}

char * DeleteChararcter_03(char *str,int c)

{

    char *p,*ret;

   

    ret = p = str;

    while(*p)

    {

       if(*p != c)

           *str++ = *p;

       p++;

    }

    *str = '/0';

   

    return ret;

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

12
 
【我解C语言面试题系列】012 查找整数数组中第二大的数
查找整数数组中第二大的数
题目:写一个函数找出一个整数数组中,第二大的数。【Mirosoft】
PS:1、” 66,66,66,66,66 ”,则没有第二大数。
2、” 99,99,88,86,68,66 ”,则最大数是88。
下面我先给出查找最大数字的程序:
int GetFirstMaxNumber(int buffer[])
{
    int i,max;
    max = buffer[0];
    for(i=1;i
    {
       if(buffer > max)
           max = buffer;
    }
   
    return max;
}
这个算法非常经典,时间复杂度是:O(N)。对于查找一个数组中的最大数字,我们至少要做的就是把数组扫描一遍,能在只扫描数组一遍的情况下就能解决问题的则算法已经是一个不错的算法的了。
查找第二大的数的算法就是在查找最大数的算法的基础上实现的,下面给出查找第二大数的程序:
#define  ARRSIZE             10
#define  MINNUMBER          0xFFFFFFFF
#define  FIND_SUCESS         1
#define  FIND_FAIL          0
int GetSecondMaxNumber(int buffer[],int *secondMax)
{
    int i,max;
    max = buffer[0];
    *secondMax = MINNUMBER;
    for(i=1;i
    {
       if(buffer > max)
       {
            *secondMax = max;
           max = buffer;
       }
       else if (buffer > *secondMax  && buffer < max)
            *secondMax = buffer;
    }
    if(*secondMax == MINNUMBER) //The numbers are all the same.
       return FIND_FAIL;
    return FIND_SUCESS;
}
查找第二大数实际上是伴随在查找最大数的过程中的。
1、如果当前元素大于最大数 max,则让第二大数等于原来的最大数 max,再把当前元素的值赋给 max。
2、 如果当前的元素大于第二大数secondMax的值而小于最大数max的值,则要把当前元素的值赋给 secondMax。――判断条件不能仅仅只是大于第二大的数secondMax,否则我们便无法处理” 99,99,88,86,68,66 ”这种情况。
PS:这个函数在调用时需要判断函数的返回值是否是 FIND_SUCESS 才能使用。
 
 
 

回复

6366

帖子

4917

TA的资源

版主

13
 
【我解C语言面试题系列】013 以单词为单位的翻转字符串

以单词为单位的翻转字符串

原题:Write a function string reverse string word By word (String input) that reverses a string word by word.

For instance:

"The house is blue" --> "blue is house The"

"Zed is dead" -->"dead is Zed"         

"All-in-one" -->"All-in-one"

在不增加任何辅助数组空间的情况下,对于这个问题我们可以采用的办法就是:

办法一

1、翻转整个字符串。

2、翻转每一个单词。

办法二

1、翻转每一个单词。

2、翻转整个字符串。

办法一和二其实就是一个顺序的问题,并不影响算法的时间或空间复杂度。

下面给出代码:【本程序在DEV C++ 4.9.9.2 下编译通过】

#include

#define IS_PRINT(ch) ( (ch) > 0x20 && (ch) < 0x7E ) // except space

char * ReverseEveryWord(char *str);

char * ReverseWholeString(char * str);

char * LR_Reverse(char *left,char *right);

int main(void)

{

    char str[] = "Hello      word! **";

    char *p = str;

#if 0

    ReverseWholeString(str);

    ReverseEveryWord(str);

    puts(str);

#else

    ReverseEveryWord(str);

    ReverseWholeString(str);

    puts(str);

#endif

    system("pause");

    return 0;

}

char * ReverseEveryWord(char *str)

{

    char *right = str,*left = str;

   

    if(str == NULL)

       return NULL;

      

    while( !IS_PRINT(*right) )

       right++;

    while(*right)

    {

       left = right;

       while(IS_PRINT(*right))

           right++;

       LR_Reverse(left,right-1);

       while(*right && !IS_PRINT(*right))

           right++;

    }

    return str;

}

char * ReverseWholeString(char * str)

{

    char *p = str;

   

    if(str == NULL)

       return NULL;

   

    while(*p)  p++;

    p--;

   

    LR_Reverse(str,p);

   

    return str;

}

char * LR_Reverse(char *left,char *right)

{

    char tt,*ret = left;

   

    if(left == NULL || right == NULL)

       return NULL;

   

    while(left < right)

    {

       tt = *left;

       *left++ = *right;

       *right-- = tt;

    }

    return ret;

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

14
 
重解几道华为经典C语言面试题
1、找错
void test1()
{
    char string[10];
    char* str1="0123456789";
    strcpy(string, str1);
}
       这里string数组越界,因为字符串长度为10,还有一个结束符’/0’。所以总共有11个字符长度。string数组大小为10,这里越界了。
PS:使用strcpy函数的时候一定要注意前面目的数组的大小一定要大于后面字符串的大小,否则便是访问越界。
void test2()
{
    char string[10], str1[10];
    for(i=0; i<10;i++)
    {
       str1 ='a';
    }
    strcpy(string, str1);
}
    这里有一个一眼就能看出的问题,那就是变量i没有定义,这在代码编译阶段编译器可以帮你发现,很容易搞定。然而很多问题是自己造成的漏洞,编译器是帮不上什么忙的。这里最大的问题还是str1没有结束符,因为strcpy的第二个参数应该是一个字符串常量。该函数就是利用判断第二个参数的结束符来得到是否拷贝完毕。所以在for循环后面应加上str1p[9] = ‘/0’;
PS:字符数组和字符串的最明显的区别就是字符串会被默认的加上结束符’/0’。
void test3(char* str1)
{
    char string[10];
    if(strlen(str1)<=10)
    {
       strcpy(string, str1);
    }
}
       这里的问题仍是越界问题。strlen函数得到字符串除结束符外的长度。如果这里是<=10话,就很明显越界了。
小结:上面的三个找错的函数,主要是考查对字符串和字符数组的概念的掌握以及对strcpy函数和strlen函数的理解。
2、找错
DSN get_SRM_no()
{
  static int SRM_no;
  int I;
  for(I=0;I
    {
       SRM_no %= MAX_SRM;
       if(MY_SRM.state==IDLE)
       {
         break;
       }
    }
    if(I>=MAX_SRM)
       return (NULL_SRM);
    else
       return SRM_no;
}
这里for循环的判断语句是后来我加上的,估计在网上流传的时候被人给弄丢了,根据对程序的分析,给补上了。估计错误应该不是这儿。
简单的阅读一下这个函数,可以大概的可以猜测出这个函数的功能是分配一个空闲的SRAM块。方法:从上次分配的RAM块后的RAM块开始检测SRAM每个RAM块,看是否是IDLE状态,如果是IDLE则返回当前的RAM块的号SRM_no。如果所有的RAM块都不是IDLE状态,则意味着无法分配一个RAM给函数调用者,返回一个表示没有RAM可分配的标志(NULL_SRM)。
经过上面的分析,则这里可以知道,这个函数的错误是for循环里面没有给SRM_no这个变量累加1。
3、写出程序运行结果
int sum(int a)
{
    auto int c=0;
    static int b=3;
    c+=1;
    b+=2;
    return(a+b+c);
}
void main()
{
    int I;
    int a=2;
    for(I=0;I<5;I++)
    {
       printf("%d,", sum(a));
    }
}
运行结果是:8,10,12,14,16,
在求和函数sum里面c是auto变量,根据auto变量特性知每次调用sum函数时变量c都会自动赋值为0。b是static变量,根据static变量特性知每次调用sum函数时变量b都会使用上次调用sum函数时b保存的值。
简单的分析一下函数,可以知道,若传入的参数不变,则每次调用sum函数返回的结果,都比上次多2。所以答案是:8,10,12,14,16,
4、func(1) = ?
int func(int a)
{
    int b;
    switch(a)
    {
        case 1: 30;
        case 2: 20;
        case 3: 16;
        default: 0;
    }
    return b;
}
在 case 语句中可能忘记了对变量b赋值。如果改为下面的代码:
int func(int a)
{
    int b;
    switch(a)
    {
        case 1:      b = 30;
        case 2:      b = 20;
        case 3:      b = 16;
        default:      b = 0;
    }
    return b;
}
因为case语句中漏掉了break语句,所以无论传给函数的参数是多少,运行结果均为0。
5、a[q - p] = ?
int a[3];
    a[0]=0; a[1]=1; a[2]=2;
    int *p, *q;
    p=a;
    q=&a[2];
    很明显:a[q - p] = a[2] = 2;
6、内存空间占用问题
定义 int **a[3][4], 则变量占有的内存空间为:16位系统24,32位编译系统中是48
PS:公式:3 * 4  * sizeof(int **) 。
7、程序编写
    编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的下一秒。如输入2004年12月31日23时59分59秒,则输出2005年1月1日0时0分0秒。
void ResetTheTime(int *year,int *month,int *date,int *hour,int *minute,int*second)
{
    int dayOfMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31};
   
    if( *year < 0   || *month < 1 || *month > 12 ||
       *date < 1   || *date > 31 || *hour < 0   || *hour > 23 ||
       *minute < 0 ||*minute > 59|| *second <0  || *second >60 )
       return;
    if( *year%400 == 0 || *year%100 != 0 && *year%4 == 0 )
       dayOfMonth[1] = 29;
    if(*second >= 60)
    {
       *second = 0;
       *minute += 1;
       if(*minute >= 60)
       {
           *minute = 0;
           *hour += 1;
           if(*hour >= 24)
           {
              *hour = 0;
              *date += 1;
              if(*date > dayOfMonth[*month-1])
              {
                  *date = 1;
                  *month += 1;
                  if(*month > 12)
                  {
                     *month=1;
                      *year += 1;
                  }
              }
           }
       }
    }
    return;
}
 
 
 

回复

6366

帖子

4917

TA的资源

版主

15
 
某型CPU的一级数据缓存大小为16K字节,cache块大小为64字节;二级缓存大小为256K字节,cache块大小为4K字节,采用二路组相联。经测试,下面两段代码运行时效率差别很大,请分析哪段代码更好,以及可能的原因。
为了进一步提高效率,你还可以采取什么办法?
A段代码:

int matrix[1023][15];

const char *str = "this is a str";

int i, j, tmp, sum = 0;

tmp = strlen(str);

for(i = 0; i < 1023; i++)

   for(j = 0; j < 15; j++)

      sum += matrix[j] + tmp;

B段代码 :

int matrix[1025][17];

const char *str = "this is a str";

int i, j, sum = 0;

for(i = 0; i < 17; i++)

   for(j = 0; j < 1025; j++)

      sum += matrix[j] + strlen(str);

A段代码效率要远远高于B段代码,原因有三:
1、   
B效率低最要命的地方就是每次都要调用strlen()函数,这是个严重问题,属于逻辑级错误。假设A的两层循环都不改变,仅仅是把A的那个循环里面的temp换成strlen()调用,在Windows 2000 (Intel 双) 下测试,竟然是A的执行时间的3.699倍。(这里没有涉及不同CPU有不同的Cache设计)仅仅是这一点就已经说明B段代码垃圾代码。
2、
       这也是一个逻辑级的错误。在这里我们再做个试验,A、B段代码分别采用大小一样的数组[1023][15]、[1023][16]、[1023][17],只是在循环上采取了不同的方式。两者在运行时间上也是有很大差异的了。B的运行时间大概是A的1.130倍。
       那么这是因为什么呢?其实也很简单,那就是A段代码中的循环执行语句对内存的访问是连续的,而B段代码中的循环执行语句对内存的访问是跳跃的。直接降低了B代码的运行效率。
       这里不是内层循环执行多少次的问题,而是一个对内存访问是否连续的问题。
3、
A的二维数组是[1023][15],B的二维数组是[1027][17],在这里B段代码有犯了一个CPU级错误(或者是Cache级的错误)。
因为在Cache中数据或指令是以行为单位存储的(也可以说是Cache块),一行又包含了很多字。如现在主流的设计是一行包含64Byte。每一行拥有一个Tag。因此,假设CPU需要一个标为Tag 1的行中的数据,它会通过CAM对Cache中的行进行查找,一旦找到相同Tag的行,就对其中的数据进行读取。
A的是15 *4B = 60B,一个Cache行刚好可以存储。B的是17*4B = 68B,超过了一个Cache行所存储的数据。很明显17的时候命中率要低于15的时候。
现在我们先不管A、B的循环嵌套的顺序,仅仅拿A段代码来做个试验,我们将会分三种情况来进行:
[1023][15]           [1023][16]     [1023][17]
运行结果并没有出乎意料之外 17 的时候的运行时间大概是 15 的时候的1.399倍,除去有因为17的时候多执行循环,17/15 = 1.133 。进行折算,17的时候大概是15的时候的1.265倍。
16的时候的执行时间要比15的时候的执行时间要短,因为是16的时候,Cache命中率更高。16/15 = 1.066 ,而15的执行时间却是16的1.068倍,加上16多执行的消耗,进行折算,15的时候大概是16的时候执行时间的1.134倍。
因为A段代码是15,而B段代码是17,在这一点上B段代码的效率要低于A段代码的效率。这是一个CPU级的错误(或者是Cache级的错误),这里涉及到Cache的块大小,也就涉及到Cache命中率,也就影响到代码效率。
不再假设什么,仅仅对A段和B段代码进行测试,B段代码的执行效率将是A段代码执行效率的3.95倍。当然最大的罪魁祸首就是B中的重复调用strlen()函数。后面两个错误告诉我们当需要对大量数据访问的时候,一定要注意对内存的访问要尽量是连续而且循环内层的访问接近Cache的块大小,以提高Cache的命中率,从而提高程序的运行效率。  
所以可以对代码进行一下修改:

#define XX    15   

#define YY    1023

int matrix[XX][YY];

const char *str = "this is a str";

int i, j, tmp, sum = 0;

tmp = strlen(str);

for(i = 0; i < XX; i++)

   for(j = 0; j < YY; j++)

      sum += matrix[j] + tmp;

这个程序仅仅是把数组的声明给颠倒了一下,循环也颠倒了一下,看起来和运行起来和上面给出的A段代码没有多大的区别。但是如果当XX很小,比如:8,那么这段程序和给出的A段代码就有区别了。这是因为这样做可以提高Cache的命中率。

 
 
 

回复

6366

帖子

4917

TA的资源

版主

16
 
11个中最大的10个数字

有一个10个数nA[10]的有序数组(从小到大),来了第11个数nNum,得出11个中最大的10个数字(排序方式(从小到大)不变),要求比较次数越少越好!

这是采用折半查找算法的程序
当要插入的数字小于第一个或者与有数字相等的时候,就不做插入工作。

void FindNumber()

{

    int i,j,Number[10],temp;

    int low = 0,high = 10,value;

    int num,flag=0;

   

    //随机产生数组

    srand((unsigned)(time(NULL)));

    for(i=0;i<10;i++)

       Number = rand()%100;

    for(i=0;i<9;i++)

    {

       for(j=0;j<9;j++)

       {

           if(Number[j] > Number[j+1])

           {

              temp = Number[j];

              Number[j] = Number[j+1];

              Number[j+1] = temp;

           }

       }

    }

    //打印数组

    for(i=0,j=0;i<10;i++)

    {

       j++;

       printf("%d/t",Number);

       if(j%6 == 5)

           printf("/n");

    }

    //随机产生要插入的数字

    num = rand()%100;

    printf("/nThe Givened Number is %d",num);

    //查找重复数字的位置

    if(num <= Number[0])//小于第一个啥都不用干

       printf("/nInsert None Number");

    else

    {

       //折半查找

       while(1)

       {

           value = low + ((high - low)/2);

           if(Number[value] > num)

              high = value;

           else if(Number[value] < num)

              low = value;

           else

           {

              flag = 1;//表示有相等的情况

              break;

           }

           if(low == high-1)

              break;

       }

       //处理收尾工作(插入要插入的数字)

       if(flag != 1)

       {

           printf("/nInsert Number %d",num);

           temp = 0;

           for(i=0;i<10;i++)

           {

              if(i == low)

              {

                  temp = Number[high];

                  Number[low] = num;

              }

              else

              {

                  if(i>low)

                  {

                     Number = temp;

                     temp = Number[i+1];

                  }

                  else

                     Number = Number[i+1];

              }

           }

       }

       else

           printf("/nInsert None Number");

    }

    //打印数组

    printf("/n");

    for(i=0,j=0;i<10;i++)

    {

       j++;

       printf("%d/t",Number);

       if(j%6 == 5)

           printf("/n");

    }

    printf("/n");

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

17
 
判断32位整数二进制中1的个数的算法
今天在CU上看到了关于 “判断32位整数二进制中1的个数的算法” 的问题。因为马上就要下班,没有时间再研究了。只好先把论坛中帖子的地址拷贝下来了。学习ing....

http://dev.bibts.com/32-1-t936968.htm

http://www.chinaunix.net/jh/23/795048.html

在下面的英文网址中,对这个问题有详细的介绍:

http://www.everything2.com/index.pl?node=counting%201%20bits

http://www.everything2.com/index.pl?node=counting%201%20bits%20SPOILER

http://www.everything2.com/index.pl?node_id=1181258

刚开始看到这个问题的时候,我就傻乎乎的开始写代码:

unsigned int FindOneInNumber_00(unsigned int x)
{
    unsigned int i,j=1;
    unsigned int count=0;
    for(i=0;i<32;i++)
    {
        if((x & j) != 0) count++;
        j = j<<2;
    }
    return count;
}


很明显我的这段代码写的是非常糟糕的。每次传过来一个数字,我总是要进行32次扫描。就这一点就可以说我的代码是典型的垃圾代码,那么别人是不是有简洁一点的代码呢。在上面的三个英文网址中找到了一些东西。

unsigned int FindOneInNumber_01(unsigned int x)
{
    unsigned int n;
    for(n=0; x; x >>= 1)
        if (x & 1) n++;
    return n;
}


在 英文文档中,原作者给出的第一种方法。看到这样的代码,俺只能说自己太笨,代码写起来太傻。不就是查查一个数字中 1 的个数吗?自己为啥非得要把所有的 位 都扫描呢? 这是一个值得想想的问题。 原作者给出的代码已经是很不错了,不过,在下面接着他又给出了第二种解法,这第二种解法,更是简洁 优雅 。

unsigned int FindOneInNumber_02(unsigned int x)
{
    unsigned int n;
    for(n=0; x; n++)
        x &= x-1;
    return n;
}

原作者给出的第二种方法明显的要优于第一种方法。两者的程序中,循环体执行完后,n表示 1 个个数。x的值变为 0 。两者都达到了目的,循环次数也是一样的。但是二者的区别就在于 第二种方法不用 执行条件判断跳转。当数据量的比较大的时候,二者的差距还是蛮大的。

原文作者又给出第三种方法来解决这个问题:

unsigned FindOneInNumber_03(unsigned int x)
{
    const unsigned MASK1  = 0x55555555;
    const unsigned MASK2  = 0x33333333;
    const unsigned MASK4  = 0x0f0f0f0f;
    const unsigned MASK8  = 0x00ff00ff;
    const unsigned MASK16 = 0x0000ffff;

    x = (x&MASK1 ) + (x>>1 &MASK1 );
    x = (x&MASK2 ) + (x>>2 &MASK2 );
    x = (x&MASK4 ) + (x>>4 &MASK4 );
    x = (x&MASK8 ) + (x>>8 &MASK8 );
    x = (x&MASK16) + (x>>16&MASK16);
    return x;
}


原 文作者的一个朋友又给出一种方法,【查表法】,不过,这样要浪费一定的主存。这种方法也是一个很不错的方法,不过,在单片机下开发的时候,就是个问题的 了。象我们公司在单片机上开发游戏,所有的能够给 图片、声音、程序的所有ROM空间仅仅 8MB,采用这种方法就是很不明智的一种选择了。
unsigned numbits_lookup_table[256] = {
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,
    3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,
    3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
    4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
    3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
    6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
    4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
    6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
    3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,
    4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,
    6, 7, 6, 7, 7, 8
};
unsigned FindOneInNumber_04(unsigned int x)
{
    unsigned n;
   
    n = numbits_lookup_table[x & 0xff];
    n += numbits_lookup_table[x>>8  & 0xff];
    n += numbits_lookup_table[x>>16 & 0xff];
    n += numbits_lookup_table[x>>24 & 0xff];
   
    return n;
}
 
 
 

回复

6366

帖子

4917

TA的资源

版主

18
 
将整数转换成字符串

请编写一个 C 函数,该函数将给定的一个整数转换成字符串。

【本程序在Dev C++ 4.9.9.2 下编译通过】

下面的这个算法比较傻,垃圾的很,显示了一个C语言新手

所应有的水平。而且处理不完全,算法考虑不周到,代码

过于啰嗦,不够简洁,紧接着这个后面会有一个较为简洁、

完全的代码。

char * IntToStr(int Number)

{

   char ch,*str,*t;

   int i,Temp,Len=0;

   str = (char *)malloc(11*sizeof(char));

   t = str;

   Temp =Number;

   while(Temp != 0)

   {

      *t = (Temp%10)+0x30;

      Temp = Temp/10;

      Len++;

      t++;

   }

   *t = '/0';

   t = str;

   for(i=0;i

   {

      ch = *t;

      *t = *(t+Len-2*i-1);

      *(t+Len-2*i-1) = ch;

      t++;

   }

   return str;

}

main()

{

   puts(IntToStr(123456));

}

下面是较为完全,较为简洁的代码。如发现什么错误,希望网友

能及时提出,俺将会给予改正。这里要谢谢 “阿郎” 网友的提醒。

char * IntToStr(int Number)

{

   char ch,*str,*right,*left;

   unsigned int Value;

   str = (char *)malloc(12*sizeof(char));

   left = right = str;

   //如果是负数,则应加上负号,left、right向后走。

   if(Number < 0)

   {

      Value = -Number;

      *str = '-';

      left++,right++;

   }

   else

      Value = (unsigned)Number;

   //把数字转换成字符串(倒置的)

   while(Value)

   {

      *right = (Value%10)+0x30;

      Value = Value/10;

      right++;

   }

   *right-- = '/0';

   //把倒置的字符串正放过来

   while(right > left)

   {

      ch = *left;

       *left++ = *right;

       *right-- = ch;

   }

   return str;

}

main()

{

   char * str;

   str = IntToStr(1234567);

   puts(str);

   free(str);

   str = IntToStr(-1234567);

   puts(str);

   free(str);

   str = IntToStr(0x7FFFFFFF);

   puts(str);

   free(str);

   str = IntToStr(-0x7FFFFFFF);

   puts(str);

   free(str);

   system("pause");

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

19
 

题目: 请编写一个 C 函数,该函数将给定的一个字符串转换成整数。

【本程序在Dev C++ 4.9.9.2 下编译通过】

下面的程序仅仅是考虑十进制字符串。

int StrToInt(char * str)

{

   int value = 0;

   int sign = 1;

   if(*str == '-')

   {

      sign = -1;

      str++;

   }

   while(*str)

   {

      value = value * 10 + *str - '0';

      str++;

   }

   return sign*value;

}

int main()

{

   printf("Number = %d/n",StrToInt("1234567"));

   printf("Number = %d/n",StrToInt("-1234567"));

   printf("Number = %d/n",StrToInt("2147483647"));

   printf("Number = %d/n",StrToInt("-2147483647"));

   system("pause");

   return 0;

}

下面的程序考虑了八进制、十进制、十六进制的字符串。


int StrToInt(char * str)

{

   int value = 0;

   int sign = 1;

   int radix;

   if(*str == '-')

   {

      sign = -1;

      str++;

   }

   if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))

   {

      radix = 16;

      str += 2;

   }

   else if(*str == '0')

   {

      radix = 8;

      str++;

   }

   else

      radix = 10;

   while(*str)

   {

      if(radix == 16)

      {

        if(*str >= '0' && *str <= '9')

           value = value * radix + *str - '0';

        else

           value = value * radix + (*str | 0x20) - 'a' + 10;

      }

      else

        value = value * radix + *str - '0';

      str++;

   }

   return sign*value;

}

int main()

{

   printf("Decimal string Translation!/n/n");

   printf("/"1234567/" = %d/n",StrToInt("1234567"));

   printf("/"-1234567/" = %d/n",StrToInt("-1234567"));

   printf("/"2147483647/" = %d/n",StrToInt("2147483647"));

   printf("/"-2147483647/" = %d/n",StrToInt("-2147483647"));

   printf("/nHex string Translation!/n/n");

   printf("/"0x200/" = %d/n",StrToInt("0x200"));

   printf("/"-0x200/" = %d/n",StrToInt("-0x200"));

   printf("/"0x7FFFFFFF/" = %d/n",StrToInt("0x7FFFFFFF"));

   printf("/"-0x7FFFFFFF/" = %d/n",StrToInt("-0x7FFFFFFF"));

   printf("/nOctal string Translation!/n/n");

   printf("/"0123/" = %d/n",StrToInt("0123"));

   printf("/"-0123/" = %d/n",StrToInt("-0123"));

   system("pause");

   return 0;

}

 
 
 

回复

6366

帖子

4917

TA的资源

版主

20
 

题目:请编写一个 C 函数,该函数将一个字符串逆序。

char * StrReverse(char * ch)
{
char tempch,* tch;
int Len,i;
tch = ch;
printf("/n");
Len = strlen(ch);
printf("Len = %d/n",Len);
for(i=0;i {
  tempch = *tch;
  *tch = *(tch + Len - 2*i - 1);
  *(tch+Len-2*i-1) = tempch;
  tch++;
}
return ch;
}
main()
{
puts(StrReverse("123456"));
system("pause");
}

下面是MS的C库给出的代码:

char * __cdecl strrev ( char * string )
{
    char *start = string;
    char *left = string;
    char ch;
    while (*string++)                 /* find end of string */
        ;
    string -= 2;
    while (left < string)
    {
        ch = *left;
        *left++ = *string;
        *string-- = ch;
    }
    return(start);
}MS给出的代码比较简洁,写的比俺的要好!
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表