发新话题
打印

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

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

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

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

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

TOP

关于数据类型的范围的问题

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

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

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

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

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

TOP

关于for里的自加

By EvilOctal
引用:
for(i=1;i<100;i++)和for(i=1;i<100;++i)有什么区别!
有人说i++是先循环在+ 而++i 是先+在循环 对么?
错!
这里是for语句 仔细看清楚了!
我把他用while重新写过你就明白了
for(i=1;i<100;i++) 的意思是
复制内容到剪贴板
代码:
int i = 0;
while(i < 100)
{
     some statement;
     i++;
}
而 for(i=1;i<100;++i) 的意思是
复制内容到剪贴板
代码:
int i = 0;
while(i < 100)
{
     some statement;
     ++i;
}
如果还不清楚 那么好 我们用个小例子
复制内容到剪贴板
代码:
#include <stdio.h>

int i = 0;

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

TOP

关于字符数组和字符串
引用:
火未燃说:
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;结束
结束符 系统会自带的,不用画蛇添脚^_^加上也无所


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

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

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


忽然想吃草的想法:
引用:
问题1:系统默认给字符串赋于一个&#39;\0&#39;字符,所以a[5]应该占6位
a[10]由于不足位补上&#39;\0&#39;所以应该占11位
但是看了书,给我的感觉应该是a[5]占6位  而a[10]占10位
数组分配多少位就是多少位 所有的字符都是一个字节 那么你分配的char a[N]; N是多少就是多少字节
但是int就不一定了 现在你也无需要知道 好好继续看书
引用:
问题2:个人认为应该会给予默认加上一个&#39;\0&#39;
只有字符串才会分配 千万不要象火未燃兄弟那样以为字符数组和字符串是完全一个类型的存储方式 那样以后有很大的麻烦
学习知识要扎实 不然以后你要煮假生米的!

TOP

关于格式化输出
引用:
为什么
int a;
a=5/2.0 a的值为2

int a=5;float b=2.0;
printf("%d",a/b) 值为0呢
By EvilOctal
问题不在求整上 而是在与你的格式化输出 计算机求取到正确的值 但是你必须让他以正确的方式输出
这个问题涉及到数据类型转换存储的问题 要学汇编编译才能明白 一般的C课本也不会详细说
我也不懂应该怎么给你讲 就现在你只需要知道如果a, b其中有一个是浮点数 那么应该这样写:
复制内容到剪贴板
代码:
#include <stdio.h>

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

     printf("%f",a/b);
     return 0;
}
才可以正常 如果想取整 这样定义并输出 就没问题了
复制内容到剪贴板
代码:
#include <stdio.h>

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

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

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

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

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

TOP

关于字符串和流的问题
引用:
老师要求写一个小程序 两次都输入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
这是为什么呀?
By EvilOctal
广告:多多讨论技术 欢迎来到邪恶八进制信息安全团队.....

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

为了证明我的解释是正确的 你可以再加两个字符数组来接收字符串 把你的程序这样修改
复制内容到剪贴板
代码:
#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;
}
你将看到这样的结果(黑体是您输入的 普通的字体是系统打印出来的内容 红色字是在缓冲区的内容):
How are you?回车
How are you?回车
How are you?
areyou?Howareyou?
怎么样?冰血清白了吧?:)

那你想看到正确的结果该怎么办 呵呵 只要清理一下缓冲区就可以了...这样修改程序:
复制内容到剪贴板
代码:
#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;
}
这样 您将看到
How are you?回车
How are you?回车
(被fflush函数把are you?刷掉....)
How are you?
How are you?

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

TOP

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

TOP

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

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

TOP

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

问个问题,急。。。
以下程序的输出结果是(  )
main()
.......
胡说八道
你自己运行一下 看看出什么结果
自己搞清楚再来问
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

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

TOP

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

TOP

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

TOP

还有一道题目~~
#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,在线等。。。

TOP

由于我是学计算机网络的.这学期汇编语言直接从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;
}
这个程序我有点搞不懂
我是不会输的!

TOP

引用:
下面是引用netdem0n于2005-11-05 23:23发表的:
之前用MFC6.0编译的,出错,后来用TC2。0编译,确实出现了3个512的答案,不得不佩服老师牛B的题目……不过还是不懂为什么。。。看冰血封情改成int main(void)就知道也是用MFC编译的了,你可以用TC试试。不知道哪位牛人能给我解释啊~~~急。。。
那就是执行程序的顺序问题了
以VC为准 TC什么狗屁
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

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

问个问题,急。。。
以下程序的输出结果是(  )
main()
.......
16位机的并且是小端字节序的,结果自然是512
[0x00][0x02]
-------------->将此值%d打印出来其实就是0x0200,自己算算~~

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

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

TOP

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

根据反编译得出结论,后者(使用++i )效率比前者高,特别在嵌入式系统中尤为明显
那对C++成立,在C是一样的。
[s:35]

TOP

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

你写程序的时候,用< 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 午夜
我的Blog http://blog.sina.com.cn/m/majianan

TOP

发新话题