12个好笑的C语言面试问答——《拾贰个风趣的C语言问答》评析(1)

金沙js333娱乐场,  不止一次在网上看到一篇名为《12个有趣的C语言问答》的博文被郑重其事地转来转去( google了一下,居然有154,000条结果,其中不乏一些知名的技术网站),感到非常滑稽。因为那明摆着是一篇垃圾文,质量低下,漏洞比比皆是。其中基本上没有多少技术营养,倒是有很多技术毒素。

的博文被郑重其事地转来转去( google了一下,居然有154,000条结果,其中不乏一些知名的技术网站),感到非常滑稽。因为那明摆着是一篇垃圾文,质量低下,漏洞比比皆是。其中基本上没有多少技术营养,倒是有很多技术毒素。

Q:以下代码有个被隐藏住的问题,你能找到它吗?

  这篇垃圾文被转反复载的原因可能有两个:一是标题取的好,其中有“有趣”二字,不少很傻很天真的人就以为真的很有趣;第二个原因可能是这是一篇翻译文章,原文为12
Interesting C Interview Questions and
Answers,有些人潜意识里可能以为外文的东西会很有技术含量。但实际上洋文中也有垃圾,洋人中也有很多外行,正如国外也有老谭《C语言程序设计》那种门外汉写得畅销垃圾书(譬如邮电社翻译的《写给大家看的C语言书》,参见劣质代码评析——《写给大家看的C语言书(第2版)》附录B之21点程序(一) )一样。对国外的东西同样不能盲从轻信,不能根据畅销程度或转发多少更不能仅仅根据其名字来判断技术价值。

,有些人潜意识里可能以为外文的东西会很有技术含量。但实际上洋文中也有垃圾,洋人中也有很多外行,正如国外也有老谭《C语言程序设计》那种门外汉写得畅销垃圾书(譬如邮电社翻译的《写给大家看的C语言书》,参见 )一样。对国外的东西同样不能盲从轻信,不能根据畅销程度或转发多少更不能仅仅根据其名字来判断技术价值。

A:这个不显眼的问题就是使用了 gets()
方法。此方法接受一个string类型参数,但是却没有检测此数值是否
有足够的空间来拷贝数据。所以这里我们一般用 fgets() 方法将来的更好。

  下面对这篇《12个有趣的C语言问答》垃圾文,参照其出处(因为翻译本有很多错误),简要地评析一下。希望对垃圾文的不断扩散多少能起到点遏制的作用。 

 

#include<stdio.h>

int main

{

char buff[10];

memset(buff,0,sizeof;

gets;

printf(“\n The buffer entered is [%s]\n”,buff);

return 0;

}

 

 

Q:密码防护是很基本的功能,看看能否搞定下面这段代码?

  1. gets() 方法
    Q:以下代码有个被隐藏住的问题,你能找到它吗? 

    int main(void) { char buff[10]; memset(buff,0,sizeof(buff)); gets(buff); printf(“\n The buffer entered is [%s]\n”,buff); return 0; }

 A:这个不显眼的问题就是使用了 gets()
方法。此方法接受一个string类型参数,但是却没有检测此数值是否
有足够的空间来拷贝数据。所以这里我们一般用 fgets() 方法将来的更好。

Answer: The hidden problem with the code above is the use of the
function gets(). This function accepts a string from stdin without
checking the capacity of buffer in which it copies the value. This may
well result in buffer overflow. The standard function fgets() is
advisable to use in these cases.

 

 

int main(void) 
{ 
    char buff[10]; 
    memset(buff,0,sizeof(buff)); 
  
    gets(buff); 
  
    printf("\n The buffer entered is [%s]\n",buff); 
  
    return 0; 
}

 

answer=”Answer” buffer=”buffer” capacity=”capacity” cases=”cases”
checking=”checking” code=”code” copies=”copies” fgets=”fgets”
from=”from” function=”function” gets=”gets” hidden=”” in=”in” is=”is”
it=”it” may=”may” of=”of” overflow=”overflow” problem=”problem”
result=”result” standard=”standard” stdin=”stdin” string=”string”
the=”the” these=”these” this=”This” to=”to” use=”use” value=”value”
well=”well” which=”which” with=”with” without=”without”>

 

#include<stdio.h>

int main(int argc, char *argv[])

{

int flag = 0;

char passwd[10];

memset(passwd,0,sizeof;

strcpy(passwd, argv[1]);

if(0 == strcmp(“LinuxGeek”, passwd))

{

flag = 1;

}

if

{

printf(“\n Password cracked \n”);

}

else

{

printf(“\n Incorrect passwd \n”);

}

return 0;

}

评:  

  翻译很成问题。根据原文,是“gets()函数”,不是“gets()方法”;接受一个string参数,不是“string类型参数”(C语言中根本没有这种类型)。其余部分的翻译也有问题,但对原意影响不大,就不多说了。  

  Answer中说使用gets()函数可能导致buffer的overflow,这一点没什么疑问。因为这个缘故,C语言现在已经废弃了gets()函数。
  问题在于代码中的

    memset(buff,0,sizeof(buff));  

这句,这句很无聊得很愚蠢。它的效果是在buff中填充0,但其实根本用不着这样调用函数来实现,只需要简单地

    char buff[10] = { '\0' };  

就足够了。更重要的是,从后面对buff的使用来看,根本没必要在buff中填充0。 

 

1,strcpy() 方法 
Q:
密码防护是很基本的功能,看看能否搞定下面这段代码

#include<stdio.h>    int main(int argc, char *argv[])  {      int flag = 0;      char passwd[10];        memset(passwd,0,sizeof(passwd));        strcpy(passwd, argv[1]);        if(0 == strcmp("LinuxGeek", passwd))      {          flag = 1;      }        if(flag)      {          printf("\n Password cracked \n");      }      else      {          printf("\n Incorrect passwd \n");        }      return 0;  }  

 

    memset(buff,0,sizeof(buff));

    char buff[10] = { '\0' };

Q:请问下面这段代码能否通过编译?如果能的话,那么这段代码中隐含什么问题吗?

评:

  晕!Answer压根没翻译。那么多转来转去的人居然对此视而不见!
从这里就不难看出哪些转这篇垃圾的人究竟有没有认真看,究竟有没有自己的头脑。这也同样能够解释,为什么垃圾能传播很广,以及为什么那些说谭浩强的书发行量大就一定好的看法是无脑人的见解。

  根据原文,解答是这样的: 

Answer: Yes. The authentication logic in above password protector code
can be compromised by exploiting the loophole of strcpy() function.
This function copies the password supplied by user to the ‘passwd’
buffer without checking whether the length of password supplied can be
accommodated by the ‘passwd’ buffer or not. So if a user supplies a
random password of such a length that causes buffer overflow and
overwrites the memory location containing the default value ’0′ of the
‘flag’ variable then even if the password matching condition fails,
the check of flag being non-zero becomes true and hence the password
protection is breached.

For example :

  $ ./psswd aaaaaaaaaaaaa

   Password cracked
So you can see that though the password supplied in the above example
is not correct but still it breached the password security through
buffer overflow.
To avoid these kind of problems the function strncpy() should be used.

 

Note from author : These days the compilers internally detect the
possibility of stack smashing and so they store variables on stack in
such a way that stack smashing becomes very difficult. In my case
also, the gcc does this by default so I had to use the the compile
option ‘-fno-stack-protector’ to reproduce the above scenario.

   不翻译了。这个解答的意思就是通过输入较长的argv[1],借助数组越界来改变flag,实现“break”这个程序的目的(Can
you break it without knowing the password)。所以应该使用strncpy()。

  这种“break”多少有点歪门邪道的意味,而且作者也提到了,有些编译器可以防止这种情况,所以这种方法其实意义不大。

  这里想说的依然是代码风格的问题——那个flag极其丑陋,不仅丑陋,没有必要存在,还进行了不必要的初始化。那个

memset(passwd,0,sizeof(passwd));

同样画蛇添足。

  甚至连passwd这个数组都没必要,只要直接比较”LinuxGeek”和argv[1]指向的字符串就可以了。代码可以这样写: 

#include<stdio.h>    int main(int argc, char *argv[])  {      //char passwd[10];        //strncpy(passwd, argv[1], 10);        if( strcmp("LinuxGeek", argv[1] ) == 0  )    //if( strcmp("LinuxGeek", passwd) == 0  )      {          printf("\n Password cracked \n");      }      else      {          printf("\n Incorrect passwd \n");        }      return 0;  }

 简洁又自然。

 (未完待续)

续文链接:


 

#include<stdio.h>

void main

{

char *ptr = malloc;

if(NULL == ptr)

{

printf(“\n Malloc failed \n”);

return;

}

else

{

// Do some processing

free;

}

return;

}

 

A:答案是代码能通过编译,但是会留下针对main()方法的返回类型的警告。main()方法的真正返回类型应该为’int’而非’void’。这是因为’int’返回类型能够让程序返回状态值。尤其是当这段程序作为其他应用的附属程序时这个状态值将更加重要。

#include<stdio.h>

int main(int argc, char *argv[])
{
    int flag = 0;
    char passwd[10];

    memset(passwd,0,sizeof(passwd));

    strcpy(passwd, argv[1]);

    if(0 == strcmp("LinuxGeek", passwd))
    {
        flag = 1;
    }

    if(flag)
    {
        printf("\n Password cracked \n");
    }
    else
    {
        printf("\n Incorrect passwd \n");

    }
    return 0;
}

 

Q:请问以下代码有内存泄露吗?

 

#include<stdio.h>

void main

{

char *ptr = malloc;

if(NULL == ptr)

{

printf(“\n Malloc failed \n”);

return;

}

else

{

// Do some processing

}

return;

}

Answer: Yes. The authentication logic in above password protector code
can be compromised by exploiting the loophole of strcpy() function.
This function copies the password supplied by user to the ‘passwd’
buffer without checking whether the length of password supplied can be
accommodated by the ‘passwd’ buffer or not. So if a user supplies a
random password of such a length that causes buffer overflow and
overwrites the memory location containing the default value ’0′ of the
‘flag’ variable then even if the password matching condition fails,
the check of flag being non-zero becomes true and hence the password
protection is breached.

For example :

  $ ./psswd aaaaaaaaaaaaa

   Password cracked
So you can see that though the password supplied in the above example
is not correct but still it breached the password security through
buffer overflow.
To avoid these kind of problems the function strncpy() should be used.

 

Note from author : These days the compilers internally detect the
possibility of stack smashing and so they store variables on stack in
such a way that stack smashing becomes very difficult. In my case
also, the gcc does this by default so I had to use the the compile
option ‘-fno-stack-protector’ to reproduce the above scenario.

A:好,虽然上面的代码没有对指针 ptr
进行内存释放,但实际上即使是程序结束也不会造成内存泄露,因为当程序结束时所有一开始被占据的内存就全部清空了。但如果上面这段代码是在
while 循环里面那将会造成严重的问题

   

Q:以下代码当用户输入’freeze’时会奔溃,而如果输入’zebra’则运行正常,这是为什么?

memset(passwd,0,sizeof(passwd));

#include<stdio.h>

int main(int argc, char *argv[])

{

char *ptr = malloc;

if(NULL == ptr)

{

printf(“\n Malloc failed \n”);

return -1;

}

else if(argc == 1)

{

printf(“\n Usage \n”);

}

else

{

memset(ptr, 0, 10);

strncpy(ptr, argv[1], 9);

while(*ptr != ‘z’)

{

if(*ptr == ”)

break;

else

ptr++;

}

if(*ptr == ‘z’)

{

printf(“\n String contains ‘z’\n”);

// Do some more processing

}

free;

}

return 0;

}

]指向的字符串就可以了。 

A:问题的根源是因为代码在while循环中改变了 ptr
指针的地址。当输入为’zebra’时,while循环甚至在执行
第一遍前就结束了,所以free()释放的内存地址就是一开始malloc()分配的地址。但是当输入’freeze’时,
ptr记录的地址在while循环中被更改,因为将会是错误的地址传递到free()方法中引起崩溃。

发表评论

电子邮件地址不会被公开。 必填项已用*标注