邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2005-5-7 01:38

[TIPS]有关C语言的一些超基础问题 大部分原创

信息来源:邪恶八进制信息安全团队

照老规矩 TIPS帖内请不要做无关回复 参与添加工作 务必注意格式!

这只是一个FAQ 邪恶八进制安全团队也强烈建议您学这类东西去CSDN:)

冰血封情 2005-5-7 01:42

[b]关于数据类型的范围的问题[/b]

By EvilOctal
[quote]今天重新看C语言是突然有个问题不明白:
int的范围是-32768~32767(2的-7次方~2的-7次方-1)
32767是0111111111111111(15个1,0是符号位)但是-的为什么是32768怎么表示啊[/quote]
呵呵...估计牛人们都很忙

0111111111111111是正的32767
1000000000000000是负的32768
你一定想问
[quote]那1000000000000000还可以填满呀 比如1000000000000000+1==1000000000000001就比1000000000000000更负拉?[/quote]
很遗憾 呵呵...1000000000000001意思是-32767
:)

楼下楼下的兄弟 是我粗心了 感谢指正:)
是这样的 -1应该是通过补码表示法来进行计算
[-1]补 = 1111111111111111

比如当字长等于16的时候 因此通过计算机可以得到
[-1]补 = 2的16次方 - 1 =10000000000000000 - 1 = 1111111111111111
至于刚才我说错的1000000000000001应该是-32767 计算方法如下
[-32767]补 = 2的16次方 - 32767=10000000000000000 - 0111111111111111 = 1000000000000001

其实计算的方法很简单 求出负数的2进制 按位求反后在末尾加1

冰血封情 2005-5-7 01:45

[b]关于for里的自加[/b]

By EvilOctal
[quote]for(i=1;i<100;i++)和for(i=1;i<100;++i)有什么区别!
有人说i++是先循环在+ 而++i 是先+在循环 对么?[/quote]
错!
这里是for语句 仔细看清楚了!
我把他用while重新写过你就明白了
for(i=1;i<100;i++) 的意思是
[code]int i = 0;
while(i < 100)
{
     some statement;
     i++;
}[/code]

而 for(i=1;i<100;++i) 的意思是
[code]int i = 0;
while(i < 100)
{
     some statement;
     ++i;
}[/code]

如果还不清楚 那么好 我们用个小例子
[code]#include <stdio.h>

int i = 0;

int main(void)
{
     while(i < 100)
     {
          i++;  //换成++i是不会有区别的
     }
     printf("%d", i);
     return 0;
}[/code]
换成++i是不会有区别的 最后i都等于100
如果照你所说
i++是先循环在+ 那么最后应该是101 看清楚了么?:)

冰血封情 2005-5-7 01:48

[b]关于字符数组和字符串[/b]

[quote][b]火未燃[/b]说:
char a[5]={&#39;C&#39;,&#39;h&#39;,&#39;i&#39;,&#39;n&#39;,&#39;a&#39;};和char a[10]={&#39;C&#39;,&#39;h&#39;,&#39;i&#39;,&#39;n&#39;,&#39;a&#39;};
有效字符5个,&#39;\0&#39;表示结束,china共5个字符,但在内存占6个字节,a[10] 占足五个后遇到&#39;\0&#39;结束
结束符 系统会自带的,不用画蛇添脚^_^加上也无所[/quote]谓

By EvilOctal
首先说[b]火未燃[/b]关于空字符系统自己加的说法是错误的 只有字符串才自己加 但是字符串和字符数组并非同一个问题!

我详细给你说说吧:

[quote]问题1:  我们定义一个字符串数组
char a[5]={&#39;C&#39;,&#39;h&#39;,&#39;i&#39;,&#39;n&#39;,&#39;a&#39;};和char a[10]={&#39;C&#39;,&#39;h&#39;,&#39;i&#39;,&#39;n&#39;,&#39;a&#39;};
问这两个数组在内存中分别占几位?[/quote]
首先回答您的问题 a[5]肯定是占5个字节 a[10]肯定是占用10个字节
因为在C语言中 数组在声明的时候 系统会顺序给您分配N个sizeof(identifier)个空间 所谓顺序就是连续分配的 他们的内存地址是连续的
其实[b]火未燃[/b]说的[b]不对[/b]!
字符数组和字符串是两个完全不同的概念 一定要搞清楚 不然程序要出错的!
首先:[b]字符数组[/b]是有单个字符存储构成的数组 字符以ascii形式存储在数组的成员变量中 但是系统不会给字符数组末尾自动加空字符 并且不能通过数组名作为指针常量调用
其次:[b]字符串[/b]是以空字符结尾的一系列字符 可以使用数组存储 系统自动加空字符 但是一定要留下一个空字符的位置 可以直接通过数组名调用
现在说说[b]火未燃[/b]的回答错在什么地方 他混淆了字符数组和字符串的概念 概念我们前面说了 很抽象 现在看看声明和初始化
声明并初始化字符数组
char a[5]={&#39;C&#39;,&#39;h&#39;,&#39;i&#39;,&#39;n&#39;,&#39;a&#39;};
//看到了么 没有空字符的位置 因为我的数组中放字符就5个元素 系统不会主动加\0的 [b]火未燃[/b]说的不对 要想调用也得a[0]来使用C 这种特性和数值数组一样
声明并初始化字符串
char a[6]= "China";
//注意 是a[6]和双引号 因为这是一串字符 所以 最后要留空字符 否则如果你用a[5] 那么系统声明的空间里将没有给\0分配的那一个字节 你调用字符串的时候 系统将直到读到下一个空字符为止 有可能下一个空字符在系统内存的某个地方

最后副送一个知识点 当你用strlen求取字符串a[6]的长度的时候 将得到int 5的返回值 因为strlen函数不算空字符 系统自己加

[quote]问题2:  数组以&#39;\0&#39;为结束符,如果我们自己给数组的最后赋于一个&#39;\0&#39;字符,
问:系统还会默认再给该数组加上一 个&#39;\0&#39;结束符吗?[/quote]
这个问题你无须关心 取决于你是否多分配了一个给他的空间 空字符无法显示 不可见 用于标志字符串的末尾 使用
char a[6] = "China";  //数组存储字符串
char *p = "China"; //指针存储 注意在在使用前为指针初始化(你现在无须掌握)
puts(a);
puts(p);
打印的都将是China换行
但是如果是这样
char a[5] = "China";
puts(a);
那么将产生无可预料的错误 因为你不知道下一个空字符在哪里 而用指针则没那个问题
系统读到第一个空字符就直接把前面的内容打印
你在数值数组 字符数组 和 字符串的这几个章节的知识没有扎实 重新好好回去读 这个问题不是问题
多看几遍书 就可以了


[b]忽然想吃草[/b]的想法:
[quote]问题1:系统默认给字符串赋于一个&#39;\0&#39;字符,所以a[5]应该占6位
a[10]由于不足位补上&#39;\0&#39;所以应该占11位
但是看了书,给我的感觉应该是a[5]占6位  而a[10]占10位[/quote]
数组分配多少位就是多少位 所有的字符都是一个字节 那么你分配的char a[N]; N是多少就是多少字节
但是int就不一定了 现在你也无需要知道 好好继续看书

[quote]问题2:个人认为应该会给予默认加上一个&#39;\0&#39;[/quote]
只有字符串才会分配 千万不要象[b]火未燃[/b]兄弟那样以为字符数组和字符串是完全一个类型的存储方式 那样以后有很大的麻烦
学习知识要扎实 不然以后你要煮假生米的!

冰血封情 2005-5-7 01:49

[b]关于格式化输出[/b]

[quote]为什么
int a;
a=5/2.0 a的值为2

int a=5;float b=2.0;
printf("%d",a/b) 值为0呢[/quote]

By EvilOctal
问题[b]不在求整[/b]上 而是在与你的[b]格式化输出[/b] 计算机[b]能[/b]求取到正确的值 但是你必须让他以正确的方式输出
这个问题涉及到[b]数据类型转换[/b]和[b]存储[/b]的问题 要学[b]汇编[/b]或[b]编译[/b]才能明白 一般的C课本也不会详细说
我也不懂应该怎么给你讲 就现在你只需要知道如果a, b其中有一个是浮点数 那么应该这样写:
[code]#include <stdio.h>

int main(void)
{
     int a=5;
     float b=2.0;

     printf("%f",a/b);
     return 0;
}[/code]
才可以正常 如果想[b]取整[/b] 这样[b]定义并输出[/b] 就没问题了
[code]#include <stdio.h>

int main(void)
{
     int a=5, b=2;

     printf("%d",a/b);
     return 0;
}[/code]
如果你[b]实在变态[/b] 非要用[b]错误的方法看到正确的结果[/b] 虽然如果你真这么固执我会很担心你的健康状况 但是我一样[b]可以[/b]给你个好方法解决 [b]强制类型转换[/b] 霸王硬上弓 简称强奸
[code]#include <stdio.h>

int main(void)
{
     int a=5;
     float b=2.0;

     printf("%d",(int)(a/b));
     return 0;
}[/code]
这样一样可以看到2的结果 这样是十分不可取的 但是我保证也是[b]没有错误没有警告[/b]的

以上程序全部在[b]VC7[/b]下调试通过 0错误 0警告 不保证其他编译器是否通过 我使用的是Windows XP SP2正版操作系统 所以这里我以[b]微软[/b]为标准

冰血封情 2005-5-8 02:45

[b]关于字符串和流的问题[/b]

[quote]老师要求写一个小程序 两次都输入How are you?
第一次系统打印How 第二次系统打印How are you?
但是为什么我写的程序
#include <stdio.h>

int main(void)
{
    char s1[5], s2[5], s3[5], str[13];
    scanf("%s", str);
    printf("%s\n", str);
    scanf("%s%s%s", s1, s2, s3);
    printf("%s %s %s\n", s1, s2, s3);
    return 0;
}
第一次打印How 第二次却打印areyou?How
这是为什么呀?[/quote]

By EvilOctal
广告:多多讨论技术 欢迎来到邪恶八进制信息安全团队.....

解释:
老摩是这样的 你问的问题[b]不是字符数组[/b]的问题 [b]是字符串[/b]的问题 但是问题却不是由于字符串引起 而是由于C语言中的[b]流[/b]引起的...
原因是scanf("%s",str);这里读的时候 的确是如[b]红客之迷[/b]说的 空格是结束符 但是 他没说全
如果你输入[b]How are you?[/b]那么系统当然找到第一个空白认为How这里已经结束 因此打印的是[b]How[/b]
然后 你就继续输入了另外一条[b]How are you?[/b]此时 按照你的思考方式 应该是How给了s1 are给了s2 you?给了s3
那么冰血告诉你 确实应该是这样的!但是为什么出错了呢?
其实你看到的[b]are you?How[/b]其中的[b]are you?[/b]是你第一次输入后剩下在缓冲区里的...
明白了么?
当系统截断了你[b]第一次输入[/b]的[b]How are you?[/b]的时候把你的[b]are you?[/b]留在了缓冲区里(多么可怕的疏忽 是一个不安全的程序)...打印How后 [b]are you?[/b](还有一个回车)被一起给了下面的s1和s2
第二次 你不经过任何处理 直接输入[b]How are you?[/b] 这个时候只有s3空着接受了你的第一个[b]How[/b]
因此打印的结果成了
[b]areyou?How[/b]

[b]为了证明我的解释是正确的[/b] 你可以再加两个字符数组来接收字符串 把你的程序这样修改
[code]#include <stdio.h>

int main(void)  //EvilOctal提醒您请注意用C99的格式编写您的源代码
{
    char s1[5], s2[5], s3[5], str[13];
    char s4[5], s5[5];

    scanf("%s", str);
    printf("%s\n", str);

    scanf("%s%s%s%s%s", s1, s2, s3, s4, s5);
    printf("%s%s%s%s%s\n", s1, s2, s3, s4, s5);

    return 0;
}[/code]
你将看到这样的结果(黑体是您输入的 普通的字体是系统打印出来的内容 红色字是在缓冲区的内容):
[b]How are you?回车[/b]
How [color=red]are you?回车[/color]
[b]How are you?[/b]
areyou?Howareyou?
怎么样?冰血清白了吧?:)

那你想看到正确的结果该怎么办 呵呵 只要清理一下缓冲区就可以了...这样修改程序:
[code]#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char s1[5], s2[5], s3[5], str[13];

    scanf("%s", str);
    printf("%s\n", str);

    fflush(stdin);

    scanf("%s%s%s", s1, s2, s3);
    printf("%s %s %s\n", s1, s2, s3);

    return 0;
}[/code]
这样 您将看到
[b]How are you?回车[/b]
How [color=red]are you?回车[/color]
(被fflush函数把are you?刷掉....)
[b]How are you?[/b]
How are you?

这是个典型问题 一定要注意 否则容易间接造成溢出

傲雪 2005-8-16 16:33

字符串问题:
用scanf输入不是遇到空格之后就会结束么。。。。
那么输入How are you?的话。。。当输到How时不就应该结束。。而调用后面的printf了么?
不明白!~~~

netdem0n 2005-11-5 15:02

回楼上的,scanf只有遇到/S标志时才会遇空格停止。

问个问题,急。。。
以下程序的输出结果是(  )
main()
{ union
   {char i[2];
    int k;
   }r;
  r.i[0]=0; r.i[1]=2;
  printf("%d \n", r.k);
}
应该是不确定的值,但是。。竟然答案为512,迷茫中,希望有牛人解答……

EvilOctal 2005-11-5 16:02

[quote][b]下面是引用netdem0n于2005-11-05 15:02发表的:[/b]
回楼上的,scanf只有遇到/S标志时才会遇空格停止。

问个问题,急。。。
以下程序的输出结果是(  )
main()
.......[/quote]
胡说八道
你自己运行一下 看看出什么结果
自己搞清楚再来问

netdem0n 2005-11-5 20:07

因为自己编译运行过所以才来问,学校搞了个C语言的汇总练习题,几百多道,其中有一道题就是这个~~我觉得题目出错了才来这里问的,有时候编译器的不同结果也会不同,希望是题目出错了~~ [s:49]

冰血封情 2005-11-5 21:17

[quote][b]下面是引用netdem0n于11-05-2005 20:07发表的:[/b]
因为自己编译运行过所以才来问,学校搞了个C语言的汇总练习题,几百多道,其中有一道题就是这个~~我觉得题目出错了才来这里问的,有时候编译器的不同结果也会不同,希望是题目出错了~~ [s:49][/quote]
[quote]#include <stdio.h>

int main(void)
{
    union  //共用体 所以不论什么时候只能有一个可以用
    {
        char i[2];
        int k;
    }r;

    r.i[0]=0;
    r.i[1]=2;

    printf("%d \n", r.k);  //没有赋值所以值是不确定的
    return 0;
}[/quote]
可以写个程序验证一下

netdem0n 2005-11-5 23:23

之前用MFC6.0编译的,出错,后来用TC2。0编译,确实出现了3个512的答案,不得不佩服老师牛B的题目……不过还是不懂为什么。。。看冰血封情改成int main(void)就知道也是用MFC编译的了,你可以用TC试试。不知道哪位牛人能给我解释啊~~~急。。。

netdem0n 2005-11-5 23:24

还有一道题目~~
#include <stdio.h>      
#include <string.h>
main()
{ int fun(char*,int);
  char *p;
  p="1234567";
  fun(p,strlen(p));
  puts(p);
}
int fun(char *w,int n)
{ char t,*s1,*s2;
  s1=w; s2=w+n-1;
  while (s1<s2)
  { t=*s1++;
   *s1=*s2--;
   *s2=t;
  }
}

觉得自己老废的,竟然做不来~~~答案是1711717,在线等。。。

jiaoxun 2005-11-9 21:55

由于我是学计算机网络的.这学期汇编语言直接从c++语言开始学.所以不是太懂,请教高手一个问题#include <iostream>
#include<string>
using namespace std;
void main()
{
    string jiao = "resistance is futile";
    cout<<jiao.find("is",4)<<endl;
    string jiao1;
    int i=jiao1.find(" ");
    getline (cin , jiao1, i, i);
    cout<<jiao1<<endl;
}
这个程序我有点搞不懂

EvilOctal 2005-11-10 01:19

[quote][b]下面是引用netdem0n于2005-11-05 23:23发表的:[/b]
之前用MFC6.0编译的,出错,后来用TC2。0编译,确实出现了3个512的答案,不得不佩服老师牛B的题目……不过还是不懂为什么。。。看冰血封情改成int main(void)就知道也是用MFC编译的了,你可以用TC试试。不知道哪位牛人能给我解释啊~~~急。。。[/quote]
那就是执行程序的顺序问题了
以VC为准 TC什么狗屁

门外汉 2005-11-12 11:46

[quote][b]下面是引用netdem0n于2005-11-05 15:02发表的:[/b]
回楼上的,scanf只有遇到/S标志时才会遇空格停止。

问个问题,急。。。
以下程序的输出结果是(  )
main()
.......[/quote]

16位机的并且是小端字节序的,结果自然是512
[0x00][0x02]
-------------->将此值%d打印出来其实就是0x0200,自己算算~~

在vc上有问题,其实我猜想是你的编译器是32位的缘故吧(手上没VC,猜的)
请用sizeof(int)证实一下,如是4,并且是小端字节序的话,就应如下:
[code]
union{
        char i[4];
        int k;
  }r;
  r.i[0]=0x00;
  r.i[1]=0x02;
  r.i[2]=0x00;
  r.i[3]=0x00;
[/code]
--------------->结果也是512~~

最后补充一句的是,我用的是gcc,--32位的

门外汉 2005-12-14 15:13

[quote][b]下面是引用kelvin于2005-12-01 22:46发表的:[/b]
记得在很久以前有一期C/C++ user journal上面有一篇文章专门讨论
for(i=1;i<100;i++) {}和for(i=1;i<100;++i) {}
的效率问题

根据反编译得出结论,后者(使用++i )效率比前者高,特别在嵌入式系统中尤为明显[/quote]



那对C++成立,在C是一样的。
[s:35]

yuanlaishi 2005-12-31 14:20

< iostream > 和 < iostream.h > 的区别
转自:[url]http://blog.sina.com.cn/u/476cd878010001ju[/url]

你写程序的时候,用< iostream >还是< iostream.h >?
你知道它们有什么区别么?还是认为他们根本就是一样的?
下面听我给你吹(文中纯属个人言论,不涉及国家机密,请放心阅读,若转载请注明出处作者^-^)
                    ---majianan


其实没有< iostream.h >这样的东西 --- 标准化委员会在简化非C标准头文件时用< iostream > 取代了它。但又没有完全取消< iostream.h >的使用,并且很多编译器都同时支持< iostream >和< iostream.h >,造成现在的局面,老大(标准化委员会)确实有不得已的苦衷。

话说当年,在标准化委员会动手重建新的标准库的时候,遇到了问题。为了避免类名函数名的冲突问题,引入了名字空间std,但无数现有的C++代码都依赖于使用了多年的伪标准库中的功能,例如,声明在< iostream.h >和< complex.h >等头文件中的功能。现有软件没有针对使用名字空间而进行相应的设计或者升级,如果用std来包装标准库导致现有代码不能使用,那手底下的小弟(程序员)是不会同意的。

标准化委员会为了拉拢人心,吸引更多的人入会,决定为包装了std的那部分标准库构建新的头文件名。将现有C++头文件名中的.h去掉,所以就出现了< iostream.h>和< iostream >等很多双胞胎。对于C头文件,采用同样方法但在每个名字前还要添加一个C,所以C的<string.h>变成了<cstring>。

旧的C++头文件是官方明确反对使用的,但旧的C头文件则没有(以保持对C的兼容性)。其实编译器制造商不会停止对客户现有软件提供支持,所以在可以预计的将来,旧的C++头文件还会嚣张一段时间。

如果能明白字符串头文件的使用,举一反三,其他的也差不多会用了。

<string.h>是旧的C头文件,对应的是基于char*的字符串处理函数;
<string>是包装了std的C++头文件,对应的是新的strng类;
<cstring>是对应旧的C头文件的std版本。

好像跑远了,言归正传。如果你的编译器都同时支持< iostream >和< iostream.h >,那使用#include < iostream >,得到的是置于名字空间std下的iostream库的元素;如果使用#include < iostream.h >,得到的是置于全局空间的同样的元素。在全局空间获取元素会导致名字冲突,而设计名字空间的初衷正是用来避免这种名字冲突的发生。还有,打字时< iostream >比< iostream.h >少两个字,所以我会使用< iostream > ^-^

困了,睡了。


                          马嘉楠
                       2005-12-26 午夜

页: [1]
© 1999-2008 EvilOctal Security Team