Question: 我想输入一个连续的4个数的全排列，代码写成这样，哪里出错了呢？

“给定一个小点的输入，完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门！ 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出

仅供参考：//qplw.cpp #include <stdio.h> #include <string.h> #include <stdlib.h> int v=0; int w=0; int m;//记录字符串长度 int n;//记录字符串中的字符种类数 char map[256];//记录是哪几种字符 int count[256];//记录每种字符有多少个 int stack[1000];//递归用的栈，并记录当前生成的排列 void Make_Map(char *str) {//统计字符串的相关信息     int s[256];     int i;     memset(s,0,sizeof(s));     memset(count,0,sizeof(count));     m=strlen(str);     if (w<1 || m<w) w=m;     while(*str) {         s[*str]++;         str++;     }     n=0;     for (i=0;i<256;i++)         if (s[i]) {             map[n]=i;             count[n]=s[i];             n++;         } } void Find(int depth) {//递归式回溯法生成全排列     if (depth==w) {         int i;         for (i=0;i<depth;i++) putchar(map[stack[i]]);         putchar('\n');     } else {         int i;         if (v && depth>0) {             for (i=0;i<depth;i++) putchar(map[stack[i]]);             putchar('\n');         }         for (i=0;i<n;i++)             if (count[i]) {                 stack[depth]=i;                 count[i]--;                 Find(depth+1);                 count[i]++;             }     } } void main(int argc,char**argv) {     if (argc<2) {         printf("%s 要产生全排列的字符串 [限定长度|-1]\n",argv[0]);         return;     }     if (argc>=3) w=atoi(argv[2]);     if (-1==w) v=1;     Make_Map(argv[1]);     Find(0); } //C:\test>qplw //qplw 要产生全排列的字符串 [限定长度|-1] // //C:\test>qplw 123 //123 //132 //213 //231 //312 //321 // //C:\test>qplw 123 2 //12 //13 //21 //23 //31 //32 // //C:\test>qplw 122333 3 //122 //123 //132 //133 //212 //213 //221 //223 //231 //232 //233 //312 //313 //321 //322 //323 //331 //332 //333 // //C:\test>qplw 123 -1 //1 //12 //123 //13 //132 //2 //21 //213 //23 //231 //3 //31 //312 //32 //321 //

用了3重的循环，只能处理3个数，无法产生4个数的全排列 另外if(i!=j && i!=j && j!=k)中的条件也错了

再供参考：//全排列的生成算法 //  全排列的生成算法就是对于给定的字符集，用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。任何n个字符集的排列都可以与1～n的n个数字的排列一一对应， //  因此在此就以n个数字的排列为例说明排列的生成法。 //  n个字符的全体排列之间存在一个确定的线性顺序关系。所有的排列中除最后一个排列外，都有一个后继；除第一个排列外，都有一个前驱。每个排列的后继都可以从 //  它的前驱经过最少的变化而得到，全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。 //  全排列的生成法通常有以下几种： //  字典序法 //  递增进位数制法 //  递减进位数制法 //  邻位交换法 //  递归类算法 //1.字典序法 效率高且顺序自然 //  字典序法中，对于数字1、2、3......n的排列，不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列12354和12345，排列12345在前， //  排列12354在后。按照这样的规定，5个数字的所有的排列中最前面的是12345，最后面的是54321。 //  字典序算法如下： //  设P是1～n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn //  1）从排列的右端开始，找出第一个比右边数字小的数字的序号j（j从左端开始计算），即 j=max{i|pi<pi+1} //  2）在pj的右边的数字中，找出所有比pj大的数中最小的数字pk，即 k=max{i|pi>pj}（右边的数从右至左是递增的，因此k是所有大于pj的数字中序号最大者） //  3）对换pi，pk //  4）再将pj+1......pk-1pkpk+1pn倒转得到排列p’’=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1，这就是排列p的下一个下一个排列。 //  例如839647521是数字1～9的一个排列。从它生成下一个排列的步骤如下： //  自右至左找出排列中第一个比右边数字小的数字4 839647521 //  在该数字后的数字中找出比4大的数中最小的一个5 839647521 //  将5与4交换 839657421 //  将7421倒转 839651247 //  所以839647521的下一个排列是839651247。 //2.递增进位数制法 //  在递增进位制数法中，从一个排列求另一个排列需要用到中介数。如果用 ki表示排列p1p2...pi...pn中元素pi的右边比pi小的数的个数，则排列的中介数就是对应的 //  排列k1 ...... ki...... kn-1。 //  例如排列839647521的中介数是72642321，7、2、6、......分别是排列中数字8、3、9、......的右边比它小的数字个数。 //  中介数是计算排列的中间环节。已知一个排列，要求下一个排列，首先确定其中介数，一个排列的后继，其中介数是原排列中介数加1，需要注意的是，如果中介数的 //  末位kn-1+1=2，则要向前进位，一般情形，如果ki+1=n-i+1，则要进位，这就是所谓的递增进位制。例如排列839647521的中介数是72642321，则下一个排列的中介数 //  是67342221+1=67342300（因为1+1=2，所以向前进位，2+1=3，又发生进位，所以下一个中介数是67342300）。 //  得到中介数后，可根据它还原对应得排列。 //  算法如下： //  中介数k1、k2、......、kn-1的各位数字顺序表示排列中的数字n、n-1、......、2在排列中距右端的的空位数，因此，要按k1、k2、......、kn-1的值从右向左 //  确定n、n-1、......、2的位置，并逐个放置在排列中：i放在右起的ki+1位，如果某位已放有数字，则该位置不算在内，最后一个空位放1。 //  因此从67342300可得到排列849617523，它就是839647521的后一个排列。因为9最先放置，k1=6，9放在右起第7位，空出6个空位，然后是放8，k2=7，8放在右起第8位， //  但9占用一位，故8应放在右起第9位，余类推。 //3.递减进位制数法 //  在递增进位制数法中，中介数的最低位是逢2进1，进位频繁，这是一个缺点。把递增进位制数翻转,就得到递减进位制数。 //  839647521的中介数是67342221(k1k2...kn-1)，倒转成为12224376(kn-1...k2k1)，这是递减进位制数的中介数：ki(i=n-1,n-2,...,2)位逢i向ki-1位进1。给定排列p， //  p的下一个排列的中介数定义为p的中介数加1。例如p=839647521，p的中介数为12224376，p的下一个排列的中介数为12224376+1=12224377，由此得到p的下一个 //  排列为893647521。 //  给定中介数，可用与递增进位制数法类似的方法还原出排列。但在递减进位制数中，可以不先计算中介数就直接从一个排列求出下一个排列。具体算法如下： //  1）如果p(i)=n且i<>n，则p(i)与p(i-1)交换 //  2）如果p(n)=n，则找出一个连续递减序列9、8、......、i，将其从排列左端删除，再以相反顺序加在排列右端，然后将i-1与左边的数字交换 //  例如p=893647521的下一个排列是983647521。求983647521的下一个排列时，因为9在最左边且第2位为8，第3位不是7，所以将8和9从小到大排于最右端364752189， //  再将7与其左方数字对调得到983647521的下一个排列是367452189。又例如求987635421的下一个排列，只需要将9876从小到大排到最右端并将5与其左方数字3对调， //  得到534216789。 //4.邻位对换法 效率最高但顺序不自然 //  邻位对换法中下一个排列总是上一个排列某相邻两位对换得到的。以4个元素的排列为例，将最后的元素4逐次与前面的元素交换，可以生成4个新排列： //  1 2 3 4, 1 2 4 3, 1 4 2 3, 4 1 2 3 //  然后将最后一个排列的末尾的两个元素交换，再逐次将排头的4与其后的元素交换，又生成四个新排列： //  4 1 3 2, 1 4 3 2, 1 3 4 2, 1 3 2 4 //  再将最后一个排列的开头的两个元素交换，将4从后往前移： //  3 1 2 4, 3 1 4 2, 3 4 1 2, 4 3 1 2 //  如此循环4!次既可求出全部排列。 //5.元素增值法（n进制法）效率低 //  1）从原始排列p=p1p2......pn开始，第n位加n-1，如果该位的值超过n，则将它除以n，用余数取代该位，并进位（将第n-1位加1） //  2）再按同样方法处理n-1位，n-2位，......，直至不再发生进位为止，处理完一个排列就产生了一个新的排列 //  3）将其中有相同元素的排列去掉 //  4）当第一个元素的值>n则结束 //  以3个数1、2、3的排列为例：原始排列是1 2 3，从它开始，第3个元素是3，3+2=5，5 Mod 3=2，第2个元素是2，2+1=3，所以新排列是1 3 2。通过元素增值，顺序产生的 //  排列是：1 2 3，1 3 2，2 1 1，2 1 3，2 2 2，2 3 1，2 3 3，3 1 2，3 2 1 //  有下划线的排列中存在重复元素，丢弃，余下的就是全部排列。 //6.递归类算法 //  全排列的生成方法用递归方式描述比较简洁，实现的方法也有多种。 //  1）回溯法 //  回溯法通常是构造一颗生成树。以3个元素为例；树的节点有个数据，可取值是1、2、3。如果某个为0，则表示尚未取值。 //  初始状态是(0，0，0)，第1个元素值可以分别挑选1，2，3，因此扩展出3个子结点。用相同方法找出这些结点的第2个元素的可能值，如此反复进行，一旦出现新结点的3个 //  数据全非零，那就找到了一种全排列方案。当尝试了所有可能方案，即获得了问题的解答。 //  2）递归算法 //  如果用P表示n个元素的排列，而Pi表示不包含元素i的排列，(i)Pi表示在排列Pi前加上前缀i的排列，那么，n个元素的排列可递归定义为： //  如果n=1，则排列P只有一个元素i //  如果n>1，则排列P由排列(i)Pi构成（i=1、2、....、n-1）。 //  根据定义，容易看出如果已经生成了k-1个元素的排列，那么，k个元素的排列可以在每个k-1个元素的排列Pi前添加元素i而生成。例如2个元素的排列是1 2和2 1，对与个 //  元素而言，p1是2 3和3 2，在每个排列前加上1即生成1 2 3和1 3 2两个新排列，p2和p3则是1 3、3 1和1 2、2 1，按同样方法可生成新排列2 1 3、2 3 1和3 1 2、3 2 1。 //  3）循环移位法 //  如果已经生成了k-1个元素的排列，则在每个排列后添加元素k使之成为k个元素的排列，然后将每个排列循环左移（右移），每移动一次就产生一个新的排列。 //  例如2个元素的排列是1 2和2 1。在1 2 后加上3成为新排列1 2 3，将它循环左移可再生成新排列2 3 1、3 1 2，同样2 1 可生成新排列2 1 3、1 3 2和3 2 1。


Question: 文件输入输出

不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,ftell,fread,fwrite,fgetc,fclose //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了  所谓修改删除文件a某位置的内容，其实是读打开文件a，再将‘a中修改删除位置之前的内容＋修改删除的内容＋a中修改删除位置之后的内容’保存到文件b，关闭文件a，删除文件a，将文件b改名为与之前文件a相同的名字，仅此而已。http://bbs.csdn.net/topics/391975224  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。

不能一个一个的读的方式追加到文件中吗？谢谢耐心解答。

引用为什么不能用while循环完成while((ch = getc(fs))!=EOF)  你循环的是根据文件个数，而不是根据文件中内容有没读完


Question: 求大神解答

指针转换类型。 首先要是个指针类型，所以要先取址& 然后强转(OS_TCB * )

VS IDE中，在不明白的符号上点鼠标右键，选转到定义或查找所有引用。

取StartTaskTCB地址，然后类型转换成OS_TCB *

将地址&StartTaskTCB（也就是变量StartTaskTCB的地址）的类型转换成指向OS_TCB类型变量的指针 &StartTaskTCB原来是指向StartTaskTCB类型的 (OS_TCB * )&StartTaskTCB则指向了OS_TCB类型 如果两者类型不同 前者无法引用OS_TCB类型中的成员，后者就可以了


Question: signed char 和 unsigned char

引用 4 楼 zhao4zhong1 的回复:理解和讨论之前请先学会如何观察！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  多谢赵4老师指点！

有符号和无符号在向右移位时，使用的填充数字是不一样的。无符号是以0来填充；有符号有些是以0，有些是以符号位。你给出的情况应该是以符号位来填充的

运算符 ~ 高于 >>，先取反再右移1位； 00000000取反为11111111； 无符号11111111取反为01111111，结果为127； 有符号11111111取反为11111111，结果为-1，为什么不是-127呢？因为是补码；  参考文章http://www.baiyy.com/portal/article/index/id/12

printf("%d\n", ((unsigned char)~0 >> 1)); //127 printf("%d\n", ((signed char)~0 >> 1));     //-1  1. ~取反，用来对一个二进制数按位取反，即将二进制中的0变1，将1变0，所以~0的二进制所有位都为1，0默认是有符号数，二进制最高位为符号位，所以 ~0 = -1；  2. signed char的最高位为符号位，因此char能表示-128~127。    对于有符号数，最高位是会被复制的，也就是它是1，则移位后还是填充1， 对于-1，二进制表示1111 1111，负数右移1位最高位补1，还是1111 1111，因此你无论移多少位，它还是-1,  所以 (signed char)~0 = (signed char)(-1) = -1  3. unsigned char没有符号位，-1 表示为二进制1111 1111, 右移一位 ==> 0111 1111, 转换为10进制 = 127


Question: C++遇到难题不会了，基础题，求解！！！

#include<iostream> #include<cstdlib> #include<ctime> using namespace std;     int main() {     int num;       int guess;       int diff;       bool isGuessed;       srand(time(0));     num = rand() % 100;     isGuessed = false;     cout << num;       while (!isGuessed)     {         cout << " Enter an integer greater"             << " than or equal to 0 and"             << " less than 100 : ";           cin >> guess;         diff = abs(num - guess);         if (diff == 0)         {             cout << " You guessed the correct "                 << " number. " << endl;             isGuessed = true;         }         else             cout << " Your guess wrong"             << " the number.\n Guess again!"             << endl;       }     return 0; }


Question: 头文件里面声明的函数，到底加extern好还是不加extern呢？

《程序员的自我修养——链接、装载与库》

三楼说错了：在硬件方面的程序，一般会在要用到该函数的文件的头文件里面用extern，告诉编译器，这个函数的声明在别的地方 正好说反了。   应该是  告诉编译器 这个函数定义在别的地方，这里只是声明并不是定义。加个extern 帮别人，或者后来的自己区分开来，提醒这里是声明，定义在别的地方。   通常函数不加extern 变量加。感觉就像写代码会对齐一样，算是个规范问题吧。加不加都一样。不加 下次再看的时候容易纠结，这里是定义还是声明。加了就能立刻明白是声明~

函数声明，正常是不写extern 的，因为那是多余的 就像 没有人会写 auto int x ;一样。 以至于 auto 现在用作别的用途了

引用 3 楼 user-7 的回复:在硬件方面的程序，一般会在要用到该函数的文件的头文件里面用extern，告诉编译器，这个函数的声明在别的地方  但是为什么不直接包含这个函数的头文件呢？如果这个函数是公开的，那应该在函数实体对应的头文件里面也会有一份声明吧？

函数和变量不同 函数声明，不写extern 也是 extern 并且函数声明，定义的形式不同。不写也不会造成混乱。   变量不写，可能会看成定义式 尤其是C++，对象类型。

好的，明白了，感谢各位。

一般习惯不加

通常为了简便不用加的，理解上也没什么歧义

我的习惯是一律不加。只是提供函数原型而已


Question: LPCVOID怎么转换成其他类型

LPCVOID 实际就是const void*  直接(char*)a 可类型转换

static_cast、dynamic_cast、reinterpret_cast和const_cast之间的区别 C-style cast举例：  int i;  double d;  i = (int) d; 上面的代码就是本来为double类型的d，通过(int)d将其转换成整形值，并将该值赋给整形变量i (注意d本身的值并没有发生改变)。这就是典型的c-style类型转换。 下面是一个简单的程序： #include <iostream> using namespace std; int main(void) {          int i;          double d = 11.29;          i = (int)d;          cout << i << endl;          cout << d << endl;          return 0; } 输出结果： 11 11.29 我们发现d值本身并没有发生任何变化。 在简单的情况下，上面这种类型转换可以很好地工作，但在C++中往往还是不够的，为此ANSI-C++新标准定义的四个转换符，即      static_cast     dynamic_cast reinterpret_cast       const_cast 同时在C++环境中，原先的C-Style的类型转换仍旧可以使用。 1)  static_cast     用法：static_cast <typeid> (expression)     说明：该运算符把expression转换为typeid类型，但没有运行时类型检查来确保转换的安全性。     用途：     a) 用于类层次结构中基类和派生类之间指针或者引用的转换。         up-casting (把派生类的指针或引用转换成基类的指针或者引用表示)是安全的；         down-casting(把基类指针或引用转换成子类的指针或者引用)是不安全的。     b) 用于基本数据类型之间的转换，如把int转换成char，这种转换的安全性也要由开发人员来保证。     c) 可以把空指针转换成目标类型的空指针(null pointer)。     d) 把任何类型的表达式转换成void类型。     注意： static_cast不能转换掉expression的const、volitale或者__unaligned属性。 2)  dynamic_cast     用法：dynamic_cast <typeid> (expression)     说明：该运算符把expression转换成typeid类型的对象。typeid必须是类的指针、类的引用或者void*。如果typeid是类的指针类型，         那么expression也必须是指针，如果typeid是一个引用，那么expression也必须是一个引用。一般情况下，dynamic_cast用         于具有多态性的类(即有虚函数的类)的类型转换。                dynamic_cast依赖于RTTI信息，其次，在转换时，dynamic_cast会检查转换的source对象是否真的可以转换成target类型，        这种检查不是语法上的，而是真实情况的检查。先看RTTI相关部分，通常，许多编译器都是通过vtable找到对象的RTTI信息        的，这也就意味着，如果基类没有虚方法，也就无法判断一个基类指针变量所指对象的真实类型，这时候，dynamic_cast只能        用来做安全的转换,例如从派生类指针转换成基类指针。而这种转换其实并不需要dynamic_cast参与。也就是说,dynamic_cast        是根据RTTI记载的信息来判断类型转换是否合法的。     用途：主要用于类层次之间的up-casting和down-casting，还可以用于类之间的交叉转换。在进行down-casting时，dynamic_cast         具有类型检查的功能，比static_cast更安全。检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针，         返回值为NULL。当用于多态类型时，它允许任意的隐式类型转换以及相反过程。不过，与static_cast不同，在后一种情况里         （注：即隐式转 换的相反过程），dynamic_cast会检查操作是否有效。也就是说，它会检查转换是否会返回一个被请求的有         效的完整对象。     注意：dynamic_cast不能转换掉expression的const、volitale或者__unaligned属性。 3)   reinterpret_cast      用法：reinterpret_cast <typeid>(expression)      说明：转换一个指针为其他类型的指针，也允许将一个指针转换为整数类型，反之亦然。这个操作符能够在非相关的类型之间进行         转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝，在类型之间指向的内容不做任何类型的检查和转换。这         是一个强制转换。使用时有很大的风险，慎用之。      注意：reinterpret_cast不能转换掉expression的const、volitale或者__unaligned属性。 4)   const_cast      用法：const_cast<typeid>(expression)      说明：这个类型操纵传递对象的const属性，或者是设置或者是移除。如：            Class C{…}            const C* a = new C;            C* b = const_cast<C*>(a);            如果将上面的const_cast转换成其他任何其他的转换，编译都不能通过，出错的信息大致如下：            “…cannot convert from 'const class C *' to 'class C *'”。      下面的代码是四种casting方法的典型用法示例：      #include <iostream>      using namespace std;      class Base      {      public:          int _base;          virtual void printinfo()          {               cout << _base << endl;          }      };      class Derived : public Base      {      public:          int _derived;          virtual void printinfo()          {               cout << _derived << endl;          }      };      int main(void)      {          Base    b1;          Derived d1;          int    aInt    = 10;          long   aLong   = 11;          float  aFloat  = 11.11f;          double aDouble = 12.12;          Derived* pd = static_cast<Derived*>(&b1);       // down-casting 不安全          Base*    pb = static_cast<Base*>(&d1);          // up-casting   安全          Derived& d = static_cast<Derived&>(b1);         // down-casting 不安全          Base& b = static_cast<Base&>(d1);               // up-casting   安全          aInt = static_cast<int>(aFloat);                // 基本数据类型转换          void* sth = static_cast<void*>(&aDouble);       // 将double指针类型转换成void指针类型          double* bDouble = static_cast<double*>(sth);    // 将void指针类型转换成double指针类型          cout << *bDouble << endl;          Base* pb1 = dynamic_cast<Base*>(&d1);          //Derived* pd1 = dynamic_cast<Derived*>(&b1);   // 编译时有warning，运行时出错          int bInt = reinterpret_cast<int>(pb1);          // 将地址或指针转换成整数          cout << bInt << endl;          pb1 = reinterpret_cast<Base*>(bInt);            // 将整数转换成地址或指针          int* cInt = reinterpret_cast<int*>(&aFloat);    // 这个转换的结果会出乎意料          cout << (int)*cInt << endl;          const Base* bBase = new Base();          Base* cBase = const_cast<Base*>(bBase);          //Base* dBase = dynamic_cast<Base*>(bBase);     // 不能通过编译          //Base* eBase = static_cast<Base*>(bBase);      // 不能通过编译          //Base* fBase = reinterpret_cast<Base*>(bBase); // 不能通过编译          return 0;     }

电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。


Question: 用中文写数据结构和算法可读性更高了

引用 20 楼 zhao4zhong1 的回复:[quote=引用 19 楼 zhao4zhong1 的回复:] 可以把里面的阿拉伯数字和标点符号全换成中文后再贴下吗？ 可以把里面的英文字母、阿拉伯数字和标点符号全换成中文后再贴下吗？[/quote]  这小意思啊！这么简单的事情，不就一个宏替换吗

其实中文英文都不重要，虽然我现在基本都是英文注释英文编码，不用中文只是现实的原因，无非就是乱码和团队合作的习惯问题。当然了，更重要的一个问题是：优秀的源码和讨论都是英文的，不能融入你就没法生存。如果有一天好的东西都是中文的，我不介意用中文。

你要么全中文，这样切输入法都烦死

似乎有一个问题，printf还是printf，函数没有中文化。

加减乘除号不好换中文

引用 19 楼 zhao4zhong1 的回复:可以把里面的阿拉伯数字和标点符号全换成中文后再贴下吗？ 可以把里面的英文字母、阿拉伯数字和标点符号全换成中文后再贴下吗？

可以把里面的阿拉伯数字和标点符号全换成中文后再贴下吗？

感觉上英文字母的不等高并且行间距比较大看着比较舒服  代码多了之后， 感觉大片等宽等高并且行间距比较小的中文看着很累

引用 11 楼 AiWolong 的回复:引用 9 楼 zhao4zhong1 的回复:http://bbs.csdn.net/topics/380157851 可以把里边的英文全换成中文后再贴下吗？

引用 15 楼 zhao4zhong1 的回复:要不习语言集成开发环境也借（piao）鉴（qie）一下我的无敌语法高亮配置： http://bbs.csdn.net/topics/390467268 ？

引用 19 楼 zhao4zhong1 的回复:可以把里面的阿拉伯数字和标点符号全换成中文后再贴下吗？  据说阿拉伯数字是源自中国，被印度改良，传入阿拉伯，然后叫成阿拉伯数字的。

引用 14 楼 zhao4zhong1 的回复:不错，在习语言中使用我自创的填表式编码风格毫无违和感。 看来习语言和C语言之间完全可以建立新型大国关系。  是否应该互派大使

全中文软件开发不是软件开发。 白马非马。

像易语言和习语言。 相对来说降低了某些人学习编程的门槛。 为大众多一个编程工具，方便尝试中文编程。 有空就尝试下，喜欢就学习下。

似乎英文代码和中文代码不是同样的东东  用同样的代码比较更有说服力一些吧

这工作量得增加一倍.

奇才呀


Question: 不采用printf（3），如何向屏幕输出一个整形或者浮点型

这还不简单，输出外挂…百度一下你就知道。acm小技巧。。。

putchar((char)i+48)输出，但是需要把整数或浮点数每一位提出来，一位一位输出，有点麻烦

参考我的打log=。=    http://blog.csdn.net/u010370871/article/details/50508859  #include<iostream> #include<sstream> #include<fstream> using namespace std;  int main() { 	int a = 5; 	wstring aa = "adadad";  	//第一种方法 c++ 	ofstream fout("D:\\outtxt.txt");  	fout<<a<<endl; 	fout<<endl;  	fout<<flush; 	fout.close();         return 0; }

可以用汇编指令，输出，如果你想了解printf的原理的话。 更深层次的是用加权系数法，将二进制转换成想要的进制，然后再变成字符输出。

还有直接用平台API

puts,字数补丁.

好像除了printf其他就没有了吧，（fprintf除外）

用比如printf对应的源代码 C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\output.c 行吗？

引用 2 楼 qq423399099 的回复:fprintf(stdout, "%d", num);  fprintf也是printf（3）里面的函数，限定了printf（3）里描述的任何函数都不能用

引用 1 楼 chengbar 的回复:cout。。。。。 这是c++里面的吧，我的是C...

fprintf(stdout, "%d", num);

cout。。。。。


Question: int *a = malloc(sizeof(int)); 对于这个已经分配好的空间，如何扩大（增加一个sizeof（int））？？？

引用 1 楼 qq423399099 的回复:不妨用realloc http://blog.csdn.net/hackerain/article/details/7954006 yes


Question: 这段代码为什么找不到符合水仙花的数

C语言的代码实现：  #include<stdio.h> #include<stdlib.h> #include<stdbool.h> int cube(const int n){ returnn*n*n; } bool isNarcissistic(const int n){ int hundreds=n/100; int tens=n/10-hundreds*10; int ones=n%10; return cube(hundreds)+cube(tens)+cube(ones)==n; } int main(void){ inti; for(i=100;i<1000;++i){ if(isNarcissistic(i)) printf("%d\n",i); } return EXIT_SUCCESS; }

1、外层每次循环时应该重新初始cnt 与 sum变量  2、水仙花数的定义是每个位上的数字的 n 次幂之和等于它本身，而你的算法不知是在求什么

引用 3楼我是你的主体 的回复:[quote=引用 1 楼 qq423399099 的回复:] 你每次for循环前都要将cnt这些变量置为初始值才行。  #include<stdio.h> int main() { 	int i, a, b, c; 	for (i = 100; i<10000; i++) 	{ 		a = i / 100; 		b = (i / 10) % 10; 		c = i % 10; 		if ((a*a*a + b*b*b + c*c*c) == i) 			printf("%d\n", i); 	} 	return(0); }  这个的话只能找出3位数的水仙花数，4位数就不行了[/quote]这个是找3,4位的，你改变下i的循环范围就好了

引用 1 楼 qq423399099 的回复:你每次for循环前都要将cnt这些变量置为初始值才行。  #include<stdio.h> int main() { 	int i, a, b, c; 	for (i = 100; i<10000; i++) 	{ 		a = i / 100; 		b = (i / 10) % 10; 		c = i % 10; 		if ((a*a*a + b*b*b + c*c*c) == i) 			printf("%d\n", i); 	} 	return(0); }  这个的话只能找出3位数的水仙花数，4位数就不行了

#include<stdio.h> int main() {  int i,a,b,c;  for(i=100;i<10000;i++)  {   a=i/100;      b=(i/10)%10;      c=i%10;   if((a*a*a+b*b*b+c*c*c)==i)   printf("%d\n",i);  }  return(0); }


Question: 将代码存储在数组中，执行数组中的代码

0100 BB00B8        MOV     BX,B800 0103 8EC3          MOV     ES,BX 0105 BB9006        MOV     BX,0690 0108 26            ES: 0109 C60763        MOV     BYTE PTR [BX],63 010C BB00B8        MOV     BX,B800 010F 8EC3          MOV     ES,BX 0111 BB9106        MOV     BX,0691 0114 26            ES: 0115 C60702        MOV     BYTE PTR [BX],02 0118 CB            RETF

引用 5 楼 zhao4zhong1 的回复:难者不会，会者不难！  赵老师又潇洒了一把哈

难者不会，会者不难！

仅供参考：/*     Application:    Code Injection in Explorer     Author:     @_RT     Compiled on:    Feb 2014     URL:http://www.codeproject.com/Tips/732044/Code-Injection-2      We will see the different steps involved to perform a code injection into an already running process.      Following are the quick steps through the process of injection.     1.Get the API addresses that you will be calling from the injected code.     2.Prepare shell code of your function that you want to get executed from the injected process.     3.Get the process ID of the running process that you wish to inject into by enumerating through the       list of processes or by finding the process's window (in case it's a GUI application) by class name or title.     4.Open the process using its Pid with All Access rights.     5.Allocate different memory spaces in the process that you are going to inject to with desired access       rights for holding different segments of your shell code.         Code part (executable instructions)         Data part (strings, function parameters, etc.)     6.Write the allocated memories with the respective values (code and data).     7.Call CreateRemoteThread API and pass to it the start of allocated memory address where you have       written your shell code from the process we are injecting. */  #include <windows.h> #pragma comment(lib,"user32.lib")  LPVOID addr; LPVOID addr2;  BOOL InjectExecutable(DWORD dwPid,LPVOID si,LPVOID pi,int sisize,int pisize) {     LPVOID hNewModule;     HANDLE hProcess;     CHAR S[]    = { "C:\\Windows\\system32\\notepad.exe" };     BYTE byt[]  = {0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x01, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x68};                  //push  0   , push     0, push     0, push     1, push     0, push     0, push     0, push 0xXXXXXXXX     BYTE byt2[] = {0xE8};//call 0xXXXXXXXX     BYTE byt3[] = {0x68};//push 0xXXXXXXXX      hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);     if (hProcess == NULL)     {         return FALSE;     }      LPVOID staddr = VirtualAllocEx(hProcess, NULL, sizeof(S), MEM_COMMIT, PAGE_READWRITE);     WriteProcessMemory(hProcess, staddr, S, sizeof(S), NULL);     LPVOID fnaddr = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);     WriteProcessMemory(hProcess, fnaddr, pi, sisize, NULL);     LPVOID fnaddr2 = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);     WriteProcessMemory(hProcess, fnaddr2, si, pisize, NULL);      hNewModule = VirtualAllocEx(hProcess, NULL, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);     if (hNewModule == NULL)     {         return FALSE;     }     LPTHREAD_START_ROUTINE strtaddr = (LPTHREAD_START_ROUTINE)hNewModule;      WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));     WriteProcessMemory(hProcess, hNewModule, &fnaddr, sizeof(fnaddr), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr));                    // push &pi ;lpProcessInformation     WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));     WriteProcessMemory(hProcess, hNewModule, &fnaddr2, sizeof(fnaddr2), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr2));                   // push &si ;lpStartupInfo     WriteProcessMemory(hProcess, hNewModule, byt, sizeof(byt), NULL);           // push 0 , push 0, push 0, push 1, push 0, push 0, push 0, push 0xXXXXXXXX==&S[0];"C:\\Windows\\system32\\notepad.exe"     hNewModule = (LPVOID)((int)hNewModule + sizeof(byt));                       // lpCurrentDirectory,lpEnvironment,dwCreationFlags,bInheritHandles,lpThreadAttributes,lpProcessAttributes,lpCommandLine,lpApplicationName     WriteProcessMemory(hProcess, hNewModule, &staddr, sizeof(staddr), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(staddr));     WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call CreateProcessA     addr = (LPVOID)((int)addr - ((int)hNewModule + 4));     WriteProcessMemory(hProcess, hNewModule, &addr, sizeof(addr), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(addr));     WriteProcessMemory(hProcess, hNewModule, byt, 2, NULL);     hNewModule = (LPVOID)((int)hNewModule + 2);                                 // push 0 ;DWORD dwExitCode   // exit code for this thread     WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);     hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call ExitThread     addr2 = (LPVOID)((int)addr2 - ((int)hNewModule + 4));     WriteProcessMemory(hProcess, hNewModule, &addr2, sizeof(addr2), NULL);      CreateRemoteThread(hProcess, 0, 0, strtaddr, NULL, 0, NULL);     return TRUE; }  int main() {     _STARTUPINFOA si;     PROCESS_INFORMATION pi;      ZeroMemory(&si, sizeof(si));     si.cb = sizeof(si);     ZeroMemory(&pi, sizeof(pi));      DWORD dwPid;     HMODULE ldlib = LoadLibraryA("Kernel32.dll");     addr = GetProcAddress(ldlib, "CreateProcessA");     addr2 = GetProcAddress(ldlib, "ExitThread");     HWND hWnd1=FindWindow(NULL, "Program Manager");     if (NULL==hWnd1) {         return 1;     }     GetWindowThreadProcessId(hWnd1, &dwPid);      InjectExecutable(dwPid,&si,&pi,sizeof(si),sizeof(pi));      return 0; }

C编译器的链接原理，最终只是寻找叫main的符号作为程序入口点 所以不管main是什么最后都会被当作程序入口点链接

引用 1 楼 user-2 的回复:把全局变量名a改成main，删除main函数 为什么啊，我想了很多办法都做不到。。

把全局变量名a改成main，删除main函数


Question: 不用库函数,用C语言实现将一整型数字转化为字符串

引用 4 楼 FFY_1208 的回复:函数的实参应该是 s，不是s[100]. s代表字符串的首地址，调用字符串用到的是地址传递，只需把首地址传递给函数就可以了。

函数的实参应该是 s，不是s[100].

代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。

reverse(s[100],b); 这个调用不能写s[100],s数组的合法范围是 s[0]~s[99],你这里直接写s就行了

37    reverse(s[100],b); 参数错了，应该是 reverse(s, b);


Question: 我是新手 大家帮我看看 我这个程序哪有问题

#define PATH "c:\\login.data" //用户信息保存文件

试了下没问题啊，代码前后重复了一遍。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。


Question: fclose本地文件会失败吗，失败怎么处理

您好，你让我每次写文件都打开，然后关闭，但是这个方式在我这性能跟不上，但还是谢谢您。

仅供参考：#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _MSC_VER     #pragma warning(disable:4996)     #include <windows.h>     #include <io.h> #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  _vsnprintf         vsnprintf #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef _MSC_VER void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} int main(int argc,char * argv[]) {     int i; #ifdef _MSC_VER     InitializeCriticalSection(&cs_log); #else     pthread_mutex_init(&cs_log,NULL); #endif     for (i=0;i<10000;i++) {         Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);     } #ifdef _MSC_VER     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_log); #endif     return 0; } //1-79行添加到你带main的.c或.cpp的那个文件的最前面 //81-86行添加到你的main函数开头 //90-94行添加到你的main函数结束前 //在要写LOG的地方仿照第88行的写法写LOG到文件MyLog1.log中

我的意思是让你参考用两个文件来回切换的思路。

问题是我这不是记日志的程序，而且是单线程的啊。


Question: 请教一个在看操作系统源码时碰到的关于变量的问题

引用 3 楼 ziibin 的回复:刚刚翻了下是我忘了C语言作用域的规则了，看编程规范约束的代码看多了一眼看到这样的代码就觉得有问题，我还是觉得这里的变量不能都叫做end，超级别扭 难道还有变量没有作用域的语言？

引用 1 楼 user-1 的回复:就近原则，听说过么？ 并且你所说的第一个循环里的end，既然是局部变量，循环的大括号就是它的作用域范围啊，对于大括号外面，它是不可见的。 C里面支持循环体里面定义只在循环体内有效的局部变量吗？这个我真忘了


Question: 汇编时寄存器的位数

EAX EBX都是32位  十六进制 0018FCD0 中每一个数字代表4位二进制，所以4*8=32

al ah 8位 ax 16位 eax 32位 rax 64位


Question: C语言和C++语言下(Type *)和（Type * &）有什么区别

char * pTemp1 = (char *&)szTemp;把数组名（地址值）强制转换为，指针引用 ，运行时出错。。。 感觉应该编译时出错才对。 这地方是不是编译器理解错了。

理解和讨论之前请先学会如何观察！  仅供参考：//char (*(*x[3])())[5];//x是什么类型的变量? // //分析C语言声明，关键是搞清楚这个变量是个什么东西（函数、指针、数组）， //是函数那么剩下的就是他的参数和返回值， //是指针那剩下部分是说明他指向什么， //是数组剩下的部分就是说明数组的成员是什么类型。 //解析C语言声明规则： //从左侧第一个标识符开始，按照优先级进行结合。*表示是..的指针，const表示只读的，volatile表示可变的，[]表示是数组，()表示是函数。 // //x和[3]结合说明是一个大小为3的数组，该数组的每个元素为一类指针，该类指针指向一类函数，该类函数无参数，返回一类指针，该类指针指向一个大小为5的char型数组 #include <stdio.h> #include <typeinfo.h> char num[5]; char (*x00())[5] {     return # } int main() {     char (*(*x[3])())[5];//是个数组，大小为3     char (*(*x0  )())[5];//数组的元素，是个函数指针     char (*( x00 )())[5];//函数原型，参数为空，返回值为指针     char (*  x000   )[5];//返回值      x0 = x00;     x[0] = x0;     x[1] = x0;     x[2] = x0;     printf("typeid(x).name() is %s\n",typeid(x).name());     return 0; } //typeid(x).name() is char (* (__cdecl**)(void))[5]

引用 5 楼 fefe82 的回复:C:  这个错误的。  C++: pTemp2 不解释了。 pTemp1 = (char *&)szTemp; C 形式的类型转换可以被解释为 const_cast, static_cast ( + const_cast), reinterpret_cast  ( + const_cast) 之一。哪个先成功(语法上)用哪个。  这里，由于 const_cast, static_cast 都不能成功（语法上）（static_cast 能处理啥就不列了），实际相当于： pTemp1 = reinterpret_cast<char *&>(szTemp); 对 reinterpret_cast ，当目标类型是左值引用时，被转换类型是不执行 array-to-pointer conversion 的。 引用5.2.10 Reinterpret cast  1 The result of the expression reinterpret_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-torvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expression v. Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast. 引用An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x)). The result refers to the same object as the source lvalue, but with a different type. The result is an lvalue for an lvalue reference type or an rvalue reference to function type and an xvalue for an rvalue reference to object type. No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.  pTemp1 = reinterpret_cast<char *&>(szTemp); 相当于 pTemp1 = *reinterpret_cast<char *>(&szTemp); 这实际相当于将szTemp 的内容（"abcd"，0x??????0064636261） 当作一个 char * 来解释，并把它（0x??????0064636261）赋值给了 pTemp1。  写错了： pTemp1 = reinterpret_cast<char *&>(szTemp); 相当于 pTemp1 = *reinterpret_cast<char **>(&szTemp);

你的这个char * pTemp1 = (char *&)szTemp;没报错么？我的vc6.0报错了。强制转换应该是第二种char * pTemp2 = (char *)szTemp; 而且强制转换的前提是类型不明的空指针，你的这个用强制转换时多此一举的。而且你的*&有点像Ｃ＋＋中的指向指针的引用，如： int i = 42; int *p; //p是一个int型指针 int  *&r=p; // r是一个对指针p的引用

引用 8 楼 lm_whales 的回复:pTemp1 = *reinterpret_cast<char **>(&szTemp); 这道可以解释的通了 不过，这地方，还是该给个警告才对。  这是标准规定好的行为。  另外，所有的用 reinterpret_cast (或者 C-style cast) 的地方，都应该自己给自己一个警告。 这各东西永远都有危险，编译器恐怕不好区分出相对“安全”的情况。 基本都需要程序员自行保证程序正确的。

char * pTemp1 = (char *&)szTemp; 这个什么含义呢？&放在这里感觉应该是作为取地址，而不是引用。 楼主的输出语句是怎么写的？

Type * & 是 Type * 指针的引用类型，正如int 与 int&的区别


Question: win  c语言多线程socket通信

搜“Jabber”？


Question: c语言 free()函数结果

其实电脑开机后物理内存的每个字节都是可读写的，从来不会因为所谓的new、delete或malloc、free而被创建、销毁。区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页，一页通常为4KB。

释放内存不是清零内存，只是告诉说这块内存不要了，你可以再分配给“别人”  在未被覆盖之前，上面的值仍然在，但这是未定义行为，因为这已经不是你的内存了，你也不知他什么时候会是什么

l_node p = ( l_node)malloc(sizeof(*p));

因为malloc释放内存是有先后问题的，虽然是结构体，但其包含的是不同的变量，分配给他们内存的时候有先后。而free释放的是最近一次调用的mallocfree的变量。而你这个问题出在，结构体内的char型，定义的是指针，系统不知道具体应该分配多少内存，所以字符串的内存并不是malloc分配的。所以释放的是int，释放后初始化为0；

未定义行为。 free只是把内存还给了操作系统。 一般都不会清零（出于效率考虑）

内存中任何位置，只要不重写，原来的数据总是保存着

《the c programming language》里说过memalloc是基于内存池机制的

释放的意义代表程序告诉系统,这块内存我不用了,系统可以把这块内存分配给其它申请内存的语句. 至于什么时候分配.什么时候被其它的语句改掉,那就是未知的了.  而p这个指针自从创建以后它就是一个具体的指针变量.不使用时,请把它=NULL;以防误使用时得到不正确的结果.这就是野指针了.


Question: 不理解restrict修饰词的具体用法，请高人指教。

你完全可以通过rarr修改到数组的值。 编译器可不会给你报错。 它默认你是不会这样去做的

引用 3 楼 cyshen 的回复:[quote=引用 1 楼 user-2 的回复:] restrict  告诉编译器， 你将遵守这个关键字的约定， 只使用这个指针修改 他指向的内存中的内容 不使用其他途径，修改该指针指向的内容。  和 const 关键字，一样，都是说你将遵守约定 而不是编译器必须遵守约定。  同样 如果函数参数 使用了这个关键字 调用者，可以放心的相信，你不会胡作非为，你一定会遵守约定的  对编译器的好处是，编译器，可以放心的优化代码，而不会造成优化结果，不是你想要的。   谢谢！如果是只这样，那我觉得这玩意没什么用呀。我告近他干嘛，反正他又不给我检查。[/quote] 有用啊，比如memcpy这个函数，就是他的两个指针参数，都是 restrict   如果你写的代码、违反了这个，也许现在，也许将来可以检测出来，报告错误

引用 1 楼 user-2 的回复:restrict  告诉编译器， 你将遵守这个关键字的约定， 只使用这个指针修改 他指向的内存中的内容 不使用其他途径，修改该指针指向的内容。  和 const 关键字，一样，都是说你将遵守约定 而不是编译器必须遵守约定。  同样 如果函数参数 使用了这个关键字 调用者，可以放心的相信，你不会胡作非为，你一定会遵守约定的  对编译器的好处是，编译器，可以放心的优化代码，而不会造成优化结果，不是你想要的。   谢谢！如果是只这样，那我觉得这玩意没什么用呀。我告近他干嘛，反正他又不给我检查。


Question: 一个结构体参数的疑问

《深度探索C++对象模型》 《C++反汇编与逆向分析技术揭秘》

引用 1 楼 user-2 的回复:因为 xxMat2 里的 m 和返回的 xxMat 即 cur_mat 已经不是同一个 xxMat 了。 它在函数返回时被复制， m 所占用的空间被释放，但返回的结构体里还包含指向 m 的成员的指针，因此返回的结构体是不可用的。 成员变量的指针赋值不会被复制吗，好久没看基础东西了，有点糊涂了


Question: 关于postgreSQL中表数据的删选

仅供参考：//输出PROG中有但LIST中没有的文本行，即集合PROG-LIST #include <stdio.h> #include <string.h> #include <stdlib.h> #include <search.h> #define MAXCHARS 512 int MAXLINES=10000,MAXLINES2; char *buf,*buf2; char PROG[256]="PROG";//程序Program需要的文件列表 char LIST[256]="LIST";//dir /b /s生成的实际文件列表List FILE *fp,*fl; int i,c,n,L,hh; int ignore_case=0; char ln[MAXCHARS]; int icompare(const void *arg1,const void *arg2) {    return stricmp((char *)arg1,(char *)arg2); } int compare(const void *arg1,const void *arg2) {    return strcmp((char *)arg1,(char *)arg2); } int main(int argc,char **argv) {     if (argc>1) strcpy(PROG,argv[1]);//命令行参数1覆盖PROG     if (argc>2) strcpy(LIST,argv[2]);//命令行参数2覆盖LIST     if (argc>3) ignore_case=1;//若存在命令行参数3，忽略大小写     if ((fl=fopen(LIST,"rt"))==NULL) {         fprintf(stderr,"Can not open %s\n",LIST);         fprintf(stderr,"Usage: %s [PROG] [LIST] [-i]\n",argv[0]);         return 1;     }     if ((fp=fopen(PROG,"rt"))==NULL) {         fclose(fl);         fprintf(stderr,"Can not open %s\n",PROG);         fprintf(stderr,"Usage: %s [PROG] [LIST] [-i]\n",argv[0]);         return 2;     }     buf=(char *)malloc(MAXLINES*MAXCHARS);     if (NULL==buf) {         fclose(fl);         fclose(fp);         fprintf(stderr,"Can not malloc(%d LINES*%d CHARS)!\n",MAXLINES,MAXCHARS);         return 4;     }     n=0;     hh=0;     i=0;     while (1) {         if (fgets(ln,MAXCHARS,fl)==NULL) break;//         hh++;         L=strlen(ln)-1;         if ('\n'!=ln[L]) {//超长行忽略后面内容             fprintf(stderr,"%s Line %d too long(>%d),spilth ignored.\n",LIST,hh,MAXCHARS);             while (1) {                 c=fgetc(fl);                 if ('\n'==c || EOF==c) break;//             }         }         while (1) {//去掉行尾的'\n'和空格             if ('\n'==ln[L] || ' '==ln[L]) {                 ln[L]=0;                 L--;                 if (L<0) break;//             } else break;//         }         if (L>=0) {             strcpy(buf+i,ln);i+=MAXCHARS;             n++;             if (n>=MAXLINES) {                 MAXLINES2=MAXLINES*2;                 if (MAXLINES2==1280000) MAXLINES2=2500000;                 buf2=(char *)realloc(buf,MAXLINES2*MAXCHARS);                 if (NULL==buf2) {                     free(buf);                     fclose(fl);                     fclose(fp);                     fprintf(stderr,"Can not malloc(%d LINES*%d CHARS)!\n",MAXLINES2,MAXCHARS);                     return 5;                 }                 buf=buf2;                 MAXLINES=MAXLINES2;             }         }     }     fclose(fl);     if (ignore_case) qsort(buf,n,MAXCHARS,icompare);     else qsort(buf,n,MAXCHARS,compare);     hh=0;     while (1) {         if (fgets(ln,MAXCHARS,fp)==NULL) break;//         hh++;         L=strlen(ln)-1;         if ('\n'!=ln[L]) {//超长行忽略后面内容             fprintf(stderr,"%s Line %d too long(>%d),spilth ignored.\n",PROG,hh,MAXCHARS);             while (1) {                 c=fgetc(fp);                 if ('\n'==c || EOF==c) break;//             }         }         while (1) {//去掉行尾的'\n'和空格             if ('\n'==ln[L] || ' '==ln[L]) {                 ln[L]=0;                 L--;                 if (L<0) break;//             } else break;//         }         if (L>=0) {             if (ignore_case) {                 if (NULL==bsearch(ln,buf,n,MAXCHARS,icompare)) printf("%s\n",ln);             } else {                 if (NULL==bsearch(ln,buf,n,MAXCHARS,compare)) printf("%s\n",ln);             }         }     }     fclose(fp);     free(buf);     return 0; }

这种删掉方式很怪异，没听说过


Question: C指针和数组的问题

理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

#include<stdio.h>  int main() { 	char *str[] = {"Hello", "World"};  	printf("%c\n", *(*(str + 1) + 4));  	return 0; }

#include <stdio.h> void main() { 	char *str[] = {"Hello", "World"}; 	printf("%s\n",*(str+1)); } 这是二级指针，不知道你要输出什么，是字符还是字符串？首字母就是地址，不需要再加一个&了

printf("%c\n", *(*(str+1)+4));

str已经是一个二级指针，为何还要去地址，如果你想指向Hello第二个字母，你可以*str + 1 来完成， 如果你想指向下一个单词World 你可以用 str + 1 来完成，你去对一个地址进行+1无任何意义

建议调试一下，然后看看各种变量的地址值就明白了（比如str,str[0],str[1],&str,&str+1） &str+1这个东西就已经是错误的东西了

这样就可以了

char *str[] = {"Hello\0" "World"};

&str + 1你这个相当于是str[2]了，已经造成越界了。 而且str是个指针数组，它里面存放的是指针，这几个指针各自指向常量字符串（这几个常量字符串并不一定相邻存储） 你这样根本达不到目的


Question: 结构体初始化列表未指明的字段保证是0吗，还是未定义行为

仅供参考：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("AD sizeof %d\n", sizeof(AD));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("A1 sizeof %d\n", sizeof(A1));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("A2 sizeof %d\n", sizeof(A2));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("A4 sizeof %d\n", sizeof(A4));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("A8 sizeof %d\n", sizeof(A8));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("A16 sizeof %d\n", sizeof(A16));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 //AD sizeof 32 // //A1.a 0 //A1.b 4 //A1.c 17 //A1 sizeof 25 // //A2.a 0 //A2.b 4 //A2.c 18 //A2 sizeof 26 // //A4.a 0 //A4.b 4 //A4.c 20 //A4 sizeof 28 // //A8.a 0 //A8.b 4 //A8.c 24 //A8 sizeof 32 // //A16.a 0 //A16.b 4 //A16.c 24 //A16 sizeof 32 // //

引用 30 楼 ipqtjmqj 的回复:[quote=引用 23 楼 fefe82 的回复:] [quote=引用 17 楼 ipqtjmqj 的回复:] @fefe82  你对标准好像很有研究，说一下你的看法  4楼已经引过标准了，C99 6.7.8 Initialization / 20 ，不重复了。[/quote] 另外我对第9点比较困惑，里面说的unnamed members of structure objects到底是怎么样的 [/quote] unnamed bitfield, padding ...  struct a{   char c;   // 这里可能有 3 byte padding   int i;   char c1:1;   char :7; // unnamed bit-field   // 最后可能还有几个字节 padding };

引用 23 楼 fefe82 的回复:[quote=引用 17 楼 ipqtjmqj 的回复:] @fefe82  你对标准好像很有研究，说一下你的看法  4楼已经引过标准了，C99 6.7.8 Initialization / 20 ，不重复了。[/quote] 我英语不太好，你说个结论吧，标准说的是可以确定还是不确定的

引用 22 楼 akirya 的回复:[quote=引用 21 楼 FFY_1208 的回复:] [quote=引用 11 楼 akirya 的回复:] [quote=引用 9 楼 ipqtjmqj 的回复:] [quote=引用 8 楼 zhao4zhong1 的回复:] 不要轻信任何约定。 您的意思是标准规范没人遵守？[/quote]  各种编译器都还是朝着完全遵守标准走的。知道是符合标准的代码，各家编译器行为都会一致的。  否则就没有正确的代码了。[/quote] 标准也是人定的，是人就会出错。不轻信，不是不信。[/quote] 1 标准总是对的 2 如果标准错了，请参考第一条[/quote] 在现实世界： 1. 1+1从来就没有真正=2过！ 2. 如果你发现这次好象1+1=2了，请参考第1条。

引用 28 楼 Rewen 的回复:不保证，是未定义的行为。  但是有些编辑器，在debug版本的时候会增加一个做初始化的动作， 在release版本就没有。  所以有些时候我们会碰到debug版本是好的，release版本程序报错的情况。 我现在不管编译器有没有遵守了，我只想问标准是怎么说的

引用 23 楼 fefe82 的回复:[quote=引用 17 楼 ipqtjmqj 的回复:] @fefe82  你对标准好像很有研究，说一下你的看法  4楼已经引过标准了，C99 6.7.8 Initialization / 20 ，不重复了。[/quote] 另外我对第9点比较困惑，里面说的unnamed members of structure objects到底是怎么样的

引用 23 楼 fefe82 的回复:[quote=引用 17 楼 ipqtjmqj 的回复:] @fefe82  你对标准好像很有研究，说一下你的看法  4楼已经引过标准了，C99 6.7.8 Initialization / 20 ，不重复了。[/quote] 我看了c99标准，应该是第21点吧

引用 17 楼 ipqtjmqj 的回复:@fefe82  你对标准好像很有研究，说一下你的看法  4楼已经引过标准了，C99 6.7.8 Initialization / 20 ，不重复了。

引用 21 楼 FFY_1208 的回复:[quote=引用 11 楼 akirya 的回复:] [quote=引用 9 楼 ipqtjmqj 的回复:] [quote=引用 8 楼 zhao4zhong1 的回复:] 不要轻信任何约定。 您的意思是标准规范没人遵守？[/quote]  各种编译器都还是朝着完全遵守标准走的。知道是符合标准的代码，各家编译器行为都会一致的。  否则就没有正确的代码了。[/quote] 标准也是人定的，是人就会出错。不轻信，不是不信。[/quote] 1 标准总是对的 2 如果标准错了，请参考第一条

引用 11 楼 akirya 的回复:[quote=引用 9 楼 ipqtjmqj 的回复:] [quote=引用 8 楼 zhao4zhong1 的回复:] 不要轻信任何约定。 您的意思是标准规范没人遵守？[/quote]  各种编译器都还是朝着完全遵守标准走的。知道是符合标准的代码，各家编译器行为都会一致的。  否则就没有正确的代码了。[/quote] 标准也是人定的，是人就会出错。不轻信，不是不信。

引用 17 楼 ipqtjmqj 的回复:@fefe82  你对标准好像很有研究，说一下你的看法  "结构体初始化列表" 指的是啥？ A():a(1),b(2) {}  这个吗？  还是这个： A a{1, 2};

c++也不保证，因为C++使用初始化列表或者构造函数来完成初始化工作的。

引用 17 楼 ipqtjmqj 的回复:@fefe82  你对标准好像很有研究，说一下你的看法 这个标准是有明确规定的，不是未定义行为。

@fefe82  你对标准好像很有研究，说一下你的看法

引用 15 楼 user-8 的回复:引用 2 楼 ipqtjmqj 的回复:[quote=引用 1 楼 user-8 的回复:] 不保证如果是c＋＋呢，最好引用一个标准  静下心读：http://en.cppreference.com/w/cpp/language/initializer_list  另参看：《深度探索C++对象模型》[/quote] 我问的是aggregate initializaion http://en.cppreference.com/w/cpp/language/aggregate_initialization 上面的链接中说 If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are value-initialized.  然后看http://en.cppreference.com/w/cpp/language/value_initialization 上面的链接中说otherwise, the object is zero-initialized.

引用 20 楼 fefe82 的回复:[quote=引用 17 楼 ipqtjmqj 的回复:] @fefe82  你对标准好像很有研究，说一下你的看法  "结构体初始化列表" 指的是啥？ A():a(1),b(2) {}  这个吗？  还是这个： A a{1, 2};[/quote] 都不是，我在主楼链接里有代码。

struct test t;         t.a = 0; 这是赋值，不是初始化。

引用 2 楼 ipqtjmqj 的回复:引用 1 楼 user-8 的回复:不保证如果是c＋＋呢，最好引用一个标准  静下心读：http://en.cppreference.com/w/cpp/language/initializer_list  另参看：《深度探索C++对象模型》

在没有使用至少不同的五个编译器和开发环境之前，不要轻易下结论。个人意见。


Question: 请问怎么通过路径访问到跳转到其他目录下，比如我这样是错误的

SetCurrentDirectory(L"c:\\下载\\"); 解决了。。

它列出是这个程序所在的目录，而不是c:\下载\的目录，请问要跳转到c:\下载\目录下，该怎么写呢?


Question: 初学c，Devc++5.11  运行以下代码

long double是c99新增的类型，好像不同编译器对这种类型的支持不一样，我在mingw下测试了好几个版本，long double输出也是不正常，printf("%d", sizeof(long double))得到的结果是12。另一个类似的常见的问题就是64位整型数的输出了，微软用的好像是printf("%I64d", a)而gcc用的好像是printf("%lld", a)。不同编译器之间有些差异

楼主可以了解一下 C与C++程序设计学习与实验系统 2013.3

说实话dev-c++运行小一点的程序错误还是很多的，换一个吧，以前我也用这个，后来实在受不了了

printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方，而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。

vs下是可以的

引用 3 楼 u010165006 的回复:%Lf   l是大写还是小写？  VC 6.0试了下两种都是正确的。

%Lf   l是大写还是小写？

lf 对应的类型是double

我刚才拿VS2013,运行了你的程序，结果如下，估计是编译器的问题！


Question: C语言声明变量顺序会对程序执行的结果造成影响吗？

赵4老师的说法未免偏激了点呐！

虎头蛇尾是俗人的习惯， 有始有终是君子的操守。  从java转C/C++ 就和从虎头蛇尾的俗人转有始有终的君子 一样。

引用 2 楼 mywanneng 的回复:十分感谢你的回答！ 你分析的有道理，我按照你的建议，添加了代码，vs2013上跑程序没有异常，那么就可以断定：我提问的那种情况，是由于我对字符数组的赋值考虑不到位所致。我也觉得我对字符数组的赋值方式考虑得不是很周到，以前用java习惯了，用java对字符变量赋值习惯了，换成C语言的方式对字符数组赋值就有许多细节要注意，一下子适应不过来。  我还想问一个问题，我虽然按照你的建议做了，能在vs2013上顺利运行程序，但是你给的建议并不能保证程序在https://vijos.org/p/1001上提交通过（我之前是通过一遍一遍测试，最后改变了变量的顺序，才提交通过的）。我想知道对于https://vijos.org/这种编程网站，我在本地调试好程序，使用样例输入也能得到正确的样例输出，但提交就会可能出现这样那样的错误，你能不能有什么建议给我？或者说能不能告诉我这类网站是如何判断一个一个程序的正确性？我要如何做才能尽量使我的程序提交通过？ 网站通常是用很多数据作为输入来检测，只有所有的测试用例都得到正确的结果才算通过。如果不过，一般来说还是自己的程序问题，比如，有些条件考虑不周，有些组合忽略了，等等

编译器可能按声明变量顺序安排他们的位置，对字符串操作严重依赖在何处能找到字符串结束标志，如果没有，就用最近的'\0'，而它很可能是你上次赋值的其他变量的值的一部分。 建议这样改，在 while (' ' != (c = getchar())){             name[i++] = c;         } 后面加上 name[i] = '\0';


Question: 又一个while(getchar()!='\n') continue问题求解

Thank you 参考你的想法已经搞定了

只要没接收到\n，也就是换行符，就一直接收，你最后输入完会按回车，也就会产生一个换行符\n，这样可以接收到最后

单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。


Question: 关于while和scanf函数一起用的问题，读取的问题？

哈，原来是double的转换时修饰符用成ld%了。。。好难找==


Question: 双递归的执行过程谁能解释下给我听 谢谢！

引用 1 楼 user-1 的回复:自己单步跟踪程序运行比谁给你解释都好  忽然想起来还有调试 感谢

自己单步跟踪程序运行比谁给你解释都好


Question: strcpy（）漏洞举例说明

可以百度 缓冲区溢出

学习了

安全都是相对的。

学习了

溢出攻击的目的，是覆盖返回地址，跳转到需要执行的代码位置 代码也同攻击代码放在一起。 溢出攻击本身的代码，也就数输入的数据，其实是二进制代码

如果溢出的太厉害了，不仅修改了flag的内容，怕是把main函数的返回地址也破坏了，整个程序就完了


Question: 大家好，小白有一个疑问，PC可以装Windows，也可以装Linux，而手机却只能刷特定机型的刷机包，就算是相同品牌下的不同机型的刷机包也不能，这是为什么呢?

引用 5 楼 yyxgs 的回复:[quote=引用 4 楼 u010165006 的回复:] 不同的手机，CPU指令集可能不同，硬件配置也不相同，而一般的刷机包都是针对一款机型的，不像Windows、Linux等系统包括了众多的驱动程序，不过如果是专门的硬件卡也需要厂家提供专门的驱动，系统也不会自带的。  驱动可不可以自己写呢?[/quote]  难度系数很高亚，专门厂家的专门人员做专门的事才有效率。

当年HD2就既可以用WM系统，也可以用安卓系统

引用 3 楼 user-3 的回复:[quote=引用 2 楼 yyxgs 的回复:] [quote=引用 1 楼 user-3 的回复:] PC有硬盘，有光盘，能预存很多很多驱动程序，装个系统用几个小时也能忍受 手机呢 刷机包中只有针对本机的驱动，下载、安装，快啊  换句话说就是如果能包括其他机型的驱动的话，那么这个手机也可以刷其他机型的刷机包了吗?[/quote] 理论上是[/quote]    引用 4 楼 u010165006 的回复:不同的手机，CPU指令集可能不同，硬件配置也不相同，而一般的刷机包都是针对一款机型的，不像Windows、Linux等系统包括了众多的驱动程序，不过如果是专门的硬件卡也需要厂家提供专门的驱动，系统也不会自带的。  驱动可不可以自己写呢?

引用 2 楼 yyxgs 的回复:[quote=引用 1 楼 user-3 的回复:] PC有硬盘，有光盘，能预存很多很多驱动程序，装个系统用几个小时也能忍受 手机呢 刷机包中只有针对本机的驱动，下载、安装，快啊  换句话说就是如果能包括其他机型的驱动的话，那么这个手机也可以刷其他机型的刷机包了吗?[/quote] 理论上是

引用 1 楼 user-3 的回复:PC有硬盘，有光盘，能预存很多很多驱动程序，装个系统用几个小时也能忍受 手机呢 刷机包中只有针对本机的驱动，下载、安装，快啊  换句话说就是如果能包括其他机型的驱动的话，那么这个手机也可以刷其他机型的刷机包了吗?


Question: scanf()问题?

这要看你定义的是什么类型了，如果是int型数组，用多少，给多少，不需要考虑‘\0’的问题，如果是字符串，就需要多定义一位，因为系统会自动加上一个'\0'，这也就占了一位，如果你不多给一位，就越界了。

scanf("%10s",&a); 小心驶得万年船。

如果不是字符数组的话，系统一般不会把'\n'读取进去

只要你的a不是字符数组，\n只是留在缓冲区，不会放到你的数组中

#include <stdio.h> void main() { 	char a[11] = {0}; 	scanf("%s",&a); 	printf("%s",a);	 }   楼主的a定义类型是int还是char？？

当你定义的是存放数字的数组，而不是存放字符的数组时，scanf（）是不会把 '\n' 或 ‘\0’ 读入的。

scanf是不会读入回车符的。 你要输入0123456789的话，应该给数组开的长度是11而不是10，因为最后需要放'\0'


Question: 管与fwrite()函数不能写入文件的问题

"r"  Opens for reading. If the file does not exist or cannot be found, the fopen call fails.  "w"  Opens an empty file for writing. If the given file exists, its contents are destroyed.  "a"  Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it doesn’t exist.  "r+"  Opens for both reading and writing. (The file must exist.)  "w+"  Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.  "a+"  Opens for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file and the EOF marker is restored after writing is complete; creates the file first if it doesn’t exist.  When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten.  The "a" mode does not remove the EOF marker before appending to the file. After appending has occurred, the MS-DOS TYPE command only shows data up to the original EOF marker and not any data appended to the file. The "a+" mode does remove the EOF marker before appending to the file. After appending, the MS-DOS TYPE command shows all data in the file. The "a+" mode is required for appending to a stream file that is terminated with the CTRL+Z EOF marker.  When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.  In addition to the above values, the following characters can be included in mode to specify the translation mode for newline characters:  t  Open in text (translated) mode. In this mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing with "a+", fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z, may cause fseek to behave improperly near the end of the file.   Also, in text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).  b  Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed.   If t or b is not given in mode, the default translation mode is defined by the global variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL.   For more information about using text and binary modes in Unicode and multibyte stream-I/O, see Text and Binary Mode File I/O and Unicode Stream I/O in Text and Binary Modes.  c  Enable the commit flag for the associated filename so that the contents of the file buffer are written directly to disk if either fflush or _flushall is called.  n  Reset the commit flag for the associated filename to “no-commit.” This is the default. It also overrides the global commit flag if you link your program with COMMODE.OBJ. The global commit flag default is “no-commit” unless you explicitly link your program with COMMODE.OBJ.

检查fwrite返回值判断原因  http://en.cppreference.com/w/c/io/fwrite

if((tarFile = fopen(fileName,"wb")) == NULL)  //打开目标文件   {     printf("Open %s Fail!\n",fileName);     exit(3);   } "wb" 应该是 "rb"


Question: 关于C语言的错误，用VS2015编写的

引用 3楼我是你的主体 的回复:按照你的指点问题已经解决，我怎么样把分给你？ 我刚自学C语言没几天，有一点不太明白： 为什么 这一句”scanf("%lf %d %lf", &number1, &operation, &number2);“要加&， 而这里”result = number1 + number2;         printf("= %f\n", result);“却不能加呢？点结帖按钮。 因为scanf是这样规定的，你可以理解成要将输入的数据写入一个内存地址，由于是地址，所以要加&

1.scanf("%lf %c %lf\n", &number1, &operation, number2);这句不对 number2前面少了&，%c应该是%d吧，'\n'也要去掉 2.printf("= %f\n", &result);也不对，result前面多了&  #include<stdio.h> #include<stdlib.h>  int main(void) { 	double number1 = 0.0; 	double number2 = 0.0; 	int operation = 0; 	double result = 0.0;   	printf("\n请在里输入要计算数字\n"); 	scanf("%lf %d %lf", &number1, &operation, &number2);  	switch (operation) 	{ 	case 1: 		result = number1 + number2; 		printf("= %f\n", result); 		break;  	case 2: 		result = number1 - number2; 		printf("= %f\n", result); 		break;  	case 3: 		result = number1 * number2; 		printf("= %f\n", result); 		break;  	case 4: 		if (number2 == 0) 			printf("\n\n数字输入错误，除数不能为0!\n"); 		else 			result = number1 / number2; 		printf("= %f\n", result); 		break;    	default: 		printf("不正确的操作法!!!"); 		break;  	}  	system("pause"); 	return 0;  }

vs2015的话，应该有一大堆警告信息吧, 反正就是关于类型不安全的


Question: 真的自己解决不了才来求助的。。。。。

问题圆满解决，加个置零就好了，谢谢。

首先，我看不清你的截图，不知道我这里显示问题还是你没截好！其次，你的内循环似乎不太对！有以下几点:第一，你每次最内层都执行47次，不是很懂，我觉得应该是x2+1-x1次，即j次，你这样会导致有未定义的元素的使用。第二，按照你的代码，你每次最内层执行完b[]应该要重置！当然如果改成j则没有一定要求了。请指正


Question: 文件输入输出

谢谢了，原来是因为这

i从1开始吧 argv[0]是可执行文件本身，就是那个13.11.4.exe，DOS的exe文件不是文本文件，内容按字符格式输出就是乱码，但它是以十六进制4D5A开头的，按ASCII码解释就是MZ


Question: error: expected ')' before '&' token

写函数原型写疯了，谢谢！

第14行， 函数调用，去掉前面的函数返回值类型void


Question: 求助 C语言中怎么进行文件内容的读取？

引用 3 楼 user-1 的回复:[quote=引用 2 楼 lxh_849063924 的回复:] [quote=引用 1 楼 user-1 的回复:] 您好，文件类型的不同会影响函数的种类和用法吗？比如SensorTag传过来的不是TXT文件而是其他文件，那读取的步骤是否一样呢？谢谢！[/quote] fread,fwrite 用来读写二进制文件 fscanf,fprintf ,用来读写文本文件 当然，一切文件都可以看作二进制文件 所以，文本文件，可以用二进制方式打开，读写 反之，不成立 [/quote] 多写了个n 修改一下

引用 2 楼 lxh_849063924 的回复:[quote=引用 1 楼 user-1 的回复:] 您好，文件类型的不同会影响函数的种类和用法吗？比如SensorTag传过来的不是TXT文件而是其他文件，那读取的步骤是否一样呢？谢谢！[/quote] fread,fwrite 用来读写二进制文件 fscanf,fprinntf ,用来读写文本文件 当然，一切文件都可以看作二进制文件 所以，文本文件，可以用二进制方式打开，读写 反之，不成立

引用 1 楼 user-1 的回复:文件基本操作： 打开，读，写，移动文件指针，关闭文件,以及回绕文件指针，读取当前文件位置 C： fopen,fscanf,fprintf,fseek,fclose，以及rewind,ftell  就是做这个的，查一下帮助，看看怎么用 此外，还有 fgetc,fputc, 字符读写 fgets,fputs 字符串读写 fread,fwrite 二进制读写  还有错误相关的函数，文件错误ferror,文件结束feof 打开有两种方式 基本方式文本方式，二进制方式 文件读写，也可以在打开的时候确定，可以读方式打开，写方式打开，读写方式打开 您好，文件类型的不同会影响函数的种类和用法吗？比如SensorTag传过来的不是TXT文件而是其他文件，那读取的步骤是否一样呢？谢谢！


Question: 不明白if(a&b)

引用 2 楼 shan794462554 的回复:[quote=引用 1 楼 wen_eric 的回复:] 判断b的值是不是4. a与b不是进行按位与操作吗，if因该是判断a&b的值，怎么变成判断b的值是不是4？[/quote] 我上面的解释是错的。应该是判断第三位是否是1. 因为int a的值是4，换成2进制表示就是： 0000 0000 0000 0000 0000 0000 0000 0100 因为a的除第3位的其余位与b的对应位的与操作都是0. 只有b的第3位是1时，a&b的结果是4，if的条件表达式的结果才为true.

4的二进制是0000 0000 0000 0000 0000 0000 0000 0100 和4按位与就是取出那个数的第三位。 a&b就是如果为真，说明b的第三位就是1

引用 3 楼 u013790834 的回复:判断它的第三位是否置为1 我可以这样理解吗：因为b未初始化，则if(a&b)变成判断2者是否相等，如果b初始化，则变成判断a&b后的值，是不是这样理解？

判断它的第三位是否置为1

引用 1 楼 wen_eric 的回复:判断b的值是不是4. a与b不是进行按位与操作吗，if因该是判断a&b的值，怎么变成判断b的值是不是4？

判断b的值是不是4.


Question: 初学c语言，为什么两位数和一位数混合排序时会出错，有时候准确，有时候又不准确，求大神指教？

感谢你提供的学习方法，多谢！

感谢你的提醒，我把k=i;放进第二个循环里就可以了！

代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。

void sort(int number[],int n) {     int i,j,t;     for(i=0;i<n-1;i++)     {         for(j=i+1;j<n;j++)         {             if(number[i]>number[j]) {             t=number[i];             number[i]=number[j];             number[j]=t; }         }     } } 改成这样就对了，记得给分哈

if(number[k]>number[j]) k=j;             t=number[k];             number[k]=number[i];             number[i]=t; 这段代码有问题，if(number[k]>number[j]) k=j;后，如果后面有number[k]<=number[j]的话，就会出问题了，因为k的值不是i了


Question: 小白求指导

第一个程序只要get_first返回了，就会输出一次，而get_first要返回，是根据'\n'判断的 第二个程序是判断EOF的，在WINDOWS下要输入ctrl+z才行

程序一因为有个判断回车的，所以结束了，程序2，你输入一个字符，然后回车，相当于输入了两个字符，一个是你输入的，还有个回车的字符

那个回车保存在缓冲区

这个是缓冲区的问题，你输入一个字符后按了个回车，保存在缓冲区里，相当于下次你输入了个回车，然后结束了

同样是用getchar，为什么运行时程序一只能输入一行数据（按了回车就停止），而程序二可以输入很多行，直至^Z结尾


Question: csv格式一步计算的编程问题

这是你的作业，请自己完成！

最关键的是，如何将字符型数组转变为float型数组。比如a[i]={'1','2','3'};如何将其变为b[0]=123;  atoi  atof

拙见： 123 = 1*100 + 2*10 +  3*1


Question: free内存的时候出错，求助

越界访问了  改成 int     *pi = malloc(sizeof(int)*2); 可正常

你申请了4个字节，实际占用的空间当然是大于4字节的，它需要放内存管理信息，调试信息这些。 不然你free的时候它怎么能知道到底释放多大？

引用 5 楼 dy452876 的回复:[quote=引用 1 楼 zjq9931 的回复:] 倒数第2行访问越界了。。。  我在上面回复了，帮忙一起看下。[/quote] 这里有讲。 http://blog.csdn.net/yupei881027/article/details/42673343

引用 1 楼 zjq9931 的回复:倒数第2行访问越界了。。。  我在上面回复了，帮忙一起看下。

引用 2 楼 qq423399099 的回复:int     *pi = malloc(sizeof(int));你这个只申请了一个int的字节 *(pi+1)=101;这句会造成越界，破坏了你堆空间周围的信息，导致free出错  虽然是这个意思，按这么说在单步执行*(pi+1)=101的时候报错更合理。  此外，还有个现象，比如把*(pi+1)改成*(pi+2)=101,再释放的时候就没问题了， 有没有可能虽然申请了一个4字节的内存，但是实际上占用的字节不止4个字节？  前4个字节是100，后面那些字节都是什么？ 再看free以后的  明显有48个字节发生了变化，被清空了，这是编译器的问题吗？

其实电脑开机后物理内存的每个字节都是可读写的，从来不会因为所谓的new、delete或malloc、free而被创建、销毁。区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页，一页通常为4KB。

倒数第2行访问越界了。。。


Question: 请问OC怎样转换成字节{0XAA ,0X0F ,0X01, bs ,0X00 ,0X00 ,0X00, 0X00, 0X00,0X00, 0X00, 0X00,

谢谢，我去整理下

仅供参考：void HexDump(char *buf,int len,int addr) {     int i,j,k;     char binstr[80];      for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%08x -",i+addr);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             printf("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         printf("%s\n",binstr);     } }

从客户端发过来的是null,我现在要解析这个null，把它转换成0xFF,并显示出来，这样的，赵老师有方法吗？

bs可以不管它，现在我要把16进制的数据，显示出来，从客户端传过来的是看不见的，解决这个问题

bs是啥东东？


Question: 内存分配

服务器程序不行。 一般程序就算不释放一般也不会出问题

肯定不是的，再大再多不管理，也会耗光的，尤其是服务器程序，长时间运行，必须严格处理内存管理问题

再大的内存也会被用完

等人类发明了长生不老药之后，再等地球容纳不下全人类的时候，要么开拓第N个地球，要么研发长生不老药的克星——大规模杀死性武器。

用发展的眼光看待科技的发展，随着软件包大小的增长，人们对内存的需求越来越大，学习内存分配也很有必要。接触底层的数据分配，能够让软件的运行效率更高


Question: 初学者 求一个数的四色无人

C99和C++11有round()。 这里有一个实现 http://en.cppreference.com/w/c/numeric/math/round  要注意负数的情况，round(x)=sgn(x)*trunc(abs(x) + 0.5)。

仅供参考：//Round(1.234,2) = 1.23 //Round(1.234,0) = 1.0 //Round(123.4,-1) = 120.0 double Round(double dVal, short iPlaces) {     double dRetval;     double dMod = 0.0000001;     if (dVal<0.0) dMod=-0.0000001;     dRetval=dVal;     dRetval+=(5.0/pow(10.0,iPlaces+1.0));     dRetval*=pow(10.0,iPlaces);     dRetval=floor(dRetval+dMod);     dRetval/=pow(10.0,iPlaces);     return(dRetval); }  double round(double dVal, short iPlaces) //iPlaces>=0 {     unsigned char s[20];     double dRetval;      sprintf(s,"%.*lf",iPlaces,dVal);     sscanf(s,"%lf",&dRetval);     return (dRetval); }

void main() { 	double x = 3.1159; 	double result = floor(x * pow(10.0, 2.0) + 0.5)/pow(10.0, 2.0); 	printf("%f四舍五入精确到小数点后两位为：%f\n",x,result); }

b = (int)(a + 0.5);


Question: 求一组数的平均分，除去最大和最小值。

#include<stdio.h> #define max 50 void main() { 	int a,b; 	scanf("%d",&a); 	double c[max],Max,min,sum=0,s; 	for(b=0;b<a;b++) 	{ 		scanf("%lf",&c[b]); 	}     Max=c[0]; 	min=c[0]; 	for(b=1;b<a;b++) 	{ 		if(c[b]>Max) 		{ 			Max=c[b]; 		} 		if(c[b]<min) 		{ 			min=c[b]; 		} 	} 	for(b=0;b<a;b++) 	{         sum=sum+c[b]; 	}     s=(sum-min-Max)/(a-2); 	printf("%.2lf\n",s); }

#include<stdio.h>  #define Max 1000//定义一个符号常量  int main() { 	int n,i,j; 	double t,min,max,s;     double a[Max]; 	while(~scanf("%d",&n)) 	{ 		s=0; 		 		for(i=0;i<n;i++) 		scanf("%lf",&a[i]);  		min=a[0]; 		max=a[0];  		for(i=0;i<n-1;i++)         {//冒泡排序，将数组从小到大排序             for(j=0;j<n-i-1;j++)             {                 if(a[j]>a[j+1])                 {                     t=a[j];                     a[j]=a[j+1];                     a[j+1]=t;                 }             }         }  		for(i=1;i<n-1;i++) 		{//除去最大与最小值之后的加和 			s+=a[i]; 		}          max=a[n-1];         min=a[0];  		printf("%.2lf %.2lf %.2lf\n",min,max,s/(n-2)); 	} }   代码仅供参考

你的代码里面错误太多了，没有报错么？数组的长度是不能用变量来确定的，而且在while右边的括号中scanf不应该在里面吧，C++中可以实现。

引用 8 楼 qaz_7 的回复:[quote=引用 4 楼 starytx 的回复:] 修改了一下，仅供参考 		int n,i; 		double s ,min,max; 		scanf("%d",&n); 		while(n > 0) 		{ 			s=0.0; 			int *a = (int*)malloc(sizeof(int) *n); 			min = max = 0.0; 			for(i=0;i<n;i++) 			{ 				scanf("%d",&a[i]); 				if (0 == i) 				{ 					min = a[i]; 					max = a[i]; 				} 				s+=a[i]; 				if(min>a[i])  min=a[i]; 				if(max<a[i])  max=a[i]; 			} 			free(a); 			s=(s-min-max)/(n-2); 			printf("%.2f %.2f %.2f\n",min,max,s); 			scanf("%d",&n); 		}  if (0 == i)         {             min = a[i];             max = a[i];         }  这里可不可以直接改成min=max=a[0];[/quote]  明白了，min=max=a[0]; 每次都是和第一个比较，所以不可以这样赋值。

引用 8 楼 qaz_7 的回复:[quote=引用 4 楼 starytx 的回复:] 修改了一下，仅供参考 		int n,i; 		double s ,min,max; 		scanf("%d",&n); 		while(n > 0) 		{ 			s=0.0; 			int *a = (int*)malloc(sizeof(int) *n); 			min = max = 0.0; 			for(i=0;i<n;i++) 			{ 				scanf("%d",&a[i]); 				if (0 == i) 				{ 					min = a[i]; 					max = a[i]; 				} 				s+=a[i]; 				if(min>a[i])  min=a[i]; 				if(max<a[i])  max=a[i]; 			} 			free(a); 			s=(s-min-max)/(n-2); 			printf("%.2f %.2f %.2f\n",min,max,s); 			scanf("%d",&n); 		}  if (0 == i)         {             min = a[i];             max = a[i];         }  这里可不可以直接改成min=max=a[0];[/quote]当然不可以啊，必须是最初开始赋值为a[0]，也就是说是有条件的，否则min和max就一直是a[0]

引用 5 楼 paschen 的回复:a 的大小是n  那么scanf("%d",&a[n]);  已经越界了  大小为n的数组有效范围是a[0] -  a[n-1]

估计楼主自己都不知道自己的代码想表达什么意思。 1、你确定这代码能够得出去除最大值和最小值后的平均数？ 2、你确定这代码能够通过编译？ 即使能通过编译得出的结果也不是你想要的。 一句话：语法不对，语义不通！

引用 4 楼 starytx 的回复:修改了一下，仅供参考 		int n,i; 		double s ,min,max; 		scanf("%d",&n); 		while(n > 0) 		{ 			s=0.0; 			int *a = (int*)malloc(sizeof(int) *n); 			min = max = 0.0; 			for(i=0;i<n;i++) 			{ 				scanf("%d",&a[i]); 				if (0 == i) 				{ 					min = a[i]; 					max = a[i]; 				} 				s+=a[i]; 				if(min>a[i])  min=a[i]; 				if(max<a[i])  max=a[i]; 			} 			free(a); 			s=(s-min-max)/(n-2); 			printf("%.2f %.2f %.2f\n",min,max,s); 			scanf("%d",&n); 		}  if (0 == i)         {             min = a[i];             max = a[i];         }  这里可不可以直接改成min=max=a[0];

引用 5 楼 paschen 的回复:a 的大小是n  那么scanf("%d",&a[n]);  已经越界了 但是我在定义啊a[n]之前有先输入n的大小啊

引用 3 楼 qq423399099 的回复:int a[n]; scanf("%d",&a[n]);  我以为这样可以直接先输入一串数据

a 的大小是n  那么scanf("%d",&a[n]);  已经越界了

int a[n]; scanf("%d",&a[n]);

scanf("%d",&a[n]);不带这么玩的，要用循环，逐个输出 C99 都用上了啊， C99标准，各编译器支持一向不是很好 不过gcc 支持

你确定这代码能通过编译？

“多一少一”问题占程序员常犯错误的10%以上！ 避免“多一少一”问题的方法之一是将比如<10甚至<5的数代入程序片断，搬手指头心算验证一下程序到底应该写为 x、x-1、x+1中的哪个？ <、<=、==、>、>=中的哪个？


Question: 出现这个问题是怎么回事有没有大神解释下！

引用 2 楼 kevin_IoT 的回复:贴代码的时候能不能规范点，你这样叫人哪有兴趣看你的代码666

Do not let me think! Keep it simple and stupid.

不要使用这种语句，尽量在一行代码上，只写一条语句。这种代码没有任何好处，既不直观，又不能提高编译和执行速度。 if( fp = (fopen("file.dat", "w")) == NULL)  建议改为两句 fp = (fopen("file.dat", "w"))； if（NULL == fp）

哦哦！谢谢，懂了！

#include<stdio.h> #include<stdlib.h> void main(int argc, char **argv) { 	FILE *fp; 	char ch; 	if ((fp = fopen("file.dat", "w")) == NULL) 	{ 		printf("Can not open file.\n"); 		exit(0); 	}  	//fopen("file.dat", "w"); 	ch = getchar(); 	while (ch != '#') 	{ 		fputc(ch, fp); 		putchar(ch); 		ch = getchar(); 	} 	fclose(fp); }

贴代码的时候能不能规范点，你这样叫人哪有兴趣看你的代码

if( fp = (fopen("file.dat", "w")) == NULL)     if( (fp = fopen("file.dat", "w")) == NULL)   int main(int argc, char **argv)


Question: 急在线等！！！！！！！！！！！！！

仅供参考：#include <stdio.h> long a=10000; long b; long c=2800; long d; long e; long f[2801]; long g; int main() {     for(;b-c;) f[b++]=a/5; //  while (1) { //      if (0==b-c) break; //      f[b]=a/5; //      b++; //  }      //f[0 - 2800] = 10000/5     for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)           for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b); //  while (1) { //      d=0; //      g=c*2; //      if (0==g) break; //      b=c; //      while (1) { //          d+=f[b]*a; //          f[b]=d%--g; //          d/=g--; //          --b; //          if (0==b) break; //          d*=b; //      } //      c-=14; //      printf("%.4d",e+d/a); //      e=d%a; //  }      return 0; }


Question: 帮小弟看个代码呗。fatal error LNK1120: 2 unresolved externals

最好使用中文编译器，显示的将是中文错误、警告信息。

谢谢大家，我的问题解决了。

看2楼的代码

关于自己是否适合编程的很简单的测试： 在报纸或杂志上随便找一段约1000字的文章，在Word中输入一遍。输完后再参考下面答案：  A里面有10处以上文字或标点错误 B里面没有文字或标点错误并敢为此跟人打赌 C里面没有文字或标点错误并且字体和排版完全与原稿一致 D打印在半透明的纸上和原稿重叠在一起检查一模一样，且自我感觉很有成就感  A不适合编程（理由：打字准确度偏低、粗心大意） B初级程序员（理由：打字准确度很高、认真细致、自信、理解全角半角概念） C高级程序员（理由：在B的基础上理解字体和排版也是电脑打印的重要因素、但相比D还不够偏执、精益求精、结果可验证） D软件项目经理（理由：能针对项目给出令人信服的细致到极点的需求说明和典型测试用例。用户几乎挑不出毛病。专业！）  如果想从A变成B的话，到我的资源http://download.csdn.net/detail/zhao4zhong1/4084259里面下载“适合程序员的键盘练习”

prinft 改成 printf   拼写错误，一般编译器会用红线提示吧

#include <stdio.h> #define PI 3.14 void main() { 	double  r, k, s; 	scanf("%lf", &r); 	k = 2 * PI*r; 	s = PI*r*r; 	printf("circle:%.2f  area:%.2f\n", k, s); }

编译提示：error C2065: 'prinft' : undeclared identifier，就要仔细看看了...printf

楼主把prinft拼写错了


Question: 指针函数的问题。。。

返回的是当前EAX寄存器中的值，而这个值是什么你是不能确定的，是未定义行为  能收到不表示正确，或许换个编译器就是错的，需要自己加上return tmp;

返回的是EAX寄存器里的值（这里刚好是指针变量的值）

“未定义行为”

理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。  调用约定 https://msdn.microsoft.com/zh-cn/magazine/9b372w95.aspx

函数没有return的话，返回的是EAX寄存器里的值（这里刚好是指针变量的值）


Question: 关于函数调用的问题

#include <stdio.h>  #include <stdlib.h>  char t[110];  int strlen(char s[])  {      int i;      for(i=0;s[i];i++);          return i;  }  void print(char t[])  {      int i;      for(i=0;t[i];i++)          printf("%c",t[i]);      printf("\n");  }  void concat(char t[],char s1[],char s2[])  {      int i,j;      t=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));      for(i=0;s1[i];i++)          t[i]=s1[i];      for(j=0;s2[j];j++)          t[i++]=s2[j];          t[i]='\0';      }  int main()  {      char st1[110],st2[110];      while(gets(st1)!=NULL)      {          gets(st2);          concat(t,st1,st2);          print(t);      }      return 0;  } 这样就不对，为什么？

不是那里的问题，上面的程序是对的，如果把我标记的print();放在主函数里调用，程序就运行不出结果，为什么；

t[i]='\0'； 这句后面的分号你打成中文的分号了，改成英文的


Question: 对方给了私钥的明文，如何用openssl来进行rsa加密呀

私钥 = 解密 签名 公钥 = 加密 验证签名

公钥加密 ，私钥解密，双方都要有对方的公钥

当然可以了，不过一般是公钥加密，私钥解密。 私钥加密一般用在签名上面，签名的过程主要是先对数据做摘要，然后对摘要结果做私钥加密。


Question: 用栈写了一个“数值转换”的题目，执行时崩溃了。调试时显示“初始化”处第一行的s->base没办法进入，望指教

自己写的程序，总是容易崩溃，望大神们指教一下，问题何在？实在是不知道问题出在哪里，它崩溃了，我也好崩溃啊

引用 3 楼 qq423399099 的回复:你这个很多处小错误： 1.需要为S分配空间才行，否则它指向的是未知区域（野指针），S = (sqstackp)malloc(sizeof(sqstack)); 2.scanf("%d", N);少了一个& 3.s->base = (int *)malloc(sizeof(int));应该是s->base = (int *)malloc(sizeof(int)* STACK_INIT_SIZE); 4.#define  STACK_INIT_SIZE 10后面多了分号  #include<stdio.h> #include<stdlib.h> #include<malloc.h>  #define  STACK_INIT_SIZE 10 #define  STACKINCREMENT  5 typedef struct{ 	int *base; 	int *top; 	int stacksize; }sqstack, *sqstackp;   int initstack(sqstackp &s){ 	s->base = (int *)malloc(sizeof(int)* STACK_INIT_SIZE); 	if (!s->base) 		return 0; 	s->top = s->base; 	s->stacksize = STACK_INIT_SIZE; 	return 1; }  int push(sqstackp s, int e){ 	if (s->top - s->base >= s->stacksize){ 		s->base = (int *)realloc(s->base, 10 * sizeof(int)); 		if (!s->base) 			return 0; 		s->top = s->base + s->stacksize; 		s->stacksize += STACKINCREMENT; 	} 	*s->top++ = e; 	return 1; }   int pop(sqstackp s, int &e){ 	if (s->top == s->base) 		return 0; 	e = *--s->top; 	return 1; }   int stackempty(sqstackp s){ 	if (s->top == s->base) 		return 1; 	else 		return 0; }  sqstackp S; int N, e;  int main(){   	S = (sqstackp)malloc(sizeof(sqstack)); 	initstack(S); 	scanf("%d", &N);  	while (N){ 		push(S, N % 8); 		N = N / 8; 	}  	while (!stackempty(S)){ 		pop(S, e); 		printf("%d", e); 	} 	return 0; }    谢谢你第一个问题最重要的，别人也跟我说过“野指针"会使程序崩溃，但我没懂，谢谢谢谢

引用 2 楼 qq_28510761 的回复:initstack里面s->base = (int *)malloc(STACK_INIT_SIZE  * sizeof(int)); 那只是书上这样写的，真正运行时不对


Question: 计算某日是该年的第几天

leap和number这两个函数重复定义了，应该是在其它源文件中也定义了这两个函数，然后你将这个源文件和你这个源文件一起编译了

COleDateTime::GetDayOfYear int GetDayOfYear( ) const;  Return Value  The day of the year represented by the value of this COleDateTime object.  Remarks  Call this member function to get the day of the year represented by this date/time value.  Valid return values range between 1 and 366, where January 1 = 1. If the status of this COleDateTime object is not valid, the return value is AFX_OLE_DATETIME_ERROR.  For information on other member functions that query the value of this COleDateTime object, see the following member functions:   GetDay   GetMonth   GetYear   GetHour   GetMinute   GetSecond   GetDayOfWeek  COleDateTime Overview |  Class Members |  Hierarchy Chart  See Also   COleDateTime::COleDateTime, COleDateTime::SetDateTime, COleDateTime::operator =, COleDateTime::GetStatus

帮你测试了，能够正常编译链接，重新清理或重建工程再试一下

你是还有别的文件吧？ 你是不是有个叫1.c的文件include了你这个文件

scanf  （"%d%d%d&year",这里写错了吧？ for（i=1；i＜m；i++）应该是这样吧？

for (i=0;i<m;i++)应该是这样吧？

假设a年b月c日： 将a年b月c日转换成时间戳：timestamp_1 将a年1月1日转换成时间戳：timestamp_2 n = (timestamp_1 - timestamp_2) / (3600*24) + 1 则a年b月c日就是a年的第n天！ 在linux下转换时间戳的系统函数是：mktime

代码没问题，检查一下你工程里多余的文件，清理一下然后重新生成

#include "stdio.h" int Day(int year ,int month,int date) {     int months[13]={0,31,0,31,30,31,30,31,31,30,31,30,31} ,i,days=0;     /*是否是闰年*/     if((year % 4 == 0 && year % 100 !=0)||(year % 400 ==0 ))         months[2]=29;     else         months[2]=28;     for(i=0;i<month;i++)      days = days + months[i];     days = days + date;     return days; }


Question: 段错误，求大家指教，程序代码如下

恍然大悟，非常感谢两位的解答

p = "Lenovo";这样的写法，表示p指向的是常量字符串，一般是禁止进行写操作，要改成在堆栈上的字符串才行。  #include<stdio.h> #include<string.h> #include<stdlib.h>  void reverseMy(char *p);  void reverseMy(char *p) { 	char *t = p + strlen(p) - 1; 	char c;  	for (; p < t; p++, t--) 	{ 		c = *p; 		*p = *t; 		*t = c; 	} }  int main(void){ 	char s[100]; 	char *p = s;  	strcpy(p, "Lenovo");  	reverseMy(p);  	printf("%s\n", p);  	return 0; }

p指向的是常量区的字符串（p = "Lenovo";） 所以你不应该在reverseMy中修改该字符串  如果需要复制字符串到s中，使用strcpy


Question: C语言怎么像从标准输入流那样从字符串中读取指定格式的数据

引用 11 楼 xiaot_cs001 的回复:引用 10 楼 zhao4zhong1 的回复:[quote=引用 9 楼 xiaot_cs001 的回复:] [quote=引用 8 楼 zhao4zhong1 的回复:] scanf想读到EOF，输入Enter、Ctrl+Z、Enter是sscanf函数把字符串末尾的'\n'理解成EOF了吗？ 理解和讨论之前请先学会如何观察！  为什么不去看看或单步调试scanf,sscanf,fscanf对应的源代码比如 C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\input.c 呢？[/quote]学习了！这就去，再次感谢赵老师[/quote] 上联：人间正道是沧桑； 下联：软件本质是源码。 横批：IT人生

引用 2 楼 q932104843 的回复:就是把字符串当作输入流这样一个字符一个字符的输入？？ 用指针可以实现吧。确实用指针是可以的，如果有库函数就更好了

我的做法是，每次记录读入了多少长度，下次读取的时候对读取的字符串做个偏移。

就是把字符串当作输入流这样一个字符一个字符的输入？？ 用指针可以实现吧。

引用 10 楼 zhao4zhong1 的回复:引用 9 楼 xiaot_cs001 的回复:[quote=引用 8 楼 zhao4zhong1 的回复:] scanf想读到EOF，输入Enter、Ctrl+Z、Enter是sscanf函数把字符串末尾的'\n'理解成EOF了吗？ 理解和讨论之前请先学会如何观察！  为什么不去看看或单步调试scanf,sscanf,fscanf对应的源代码比如 C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\input.c 呢？[/quote]学习了！这就去，再次感谢赵老师

引用 9 楼 xiaot_cs001 的回复:引用 8 楼 zhao4zhong1 的回复:scanf想读到EOF，输入Enter、Ctrl+Z、Enter是sscanf函数把字符串末尾的'\n'理解成EOF了吗？ 理解和讨论之前请先学会如何观察！  为什么不去看看或单步调试scanf,sscanf,fscanf对应的源代码比如 C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\input.c 呢？

scanf想读到EOF，输入Enter、Ctrl+Z、Enter

引用 6 楼 zhao4zhong1 的回复:仅供参考：#include <stdio.h> char s[]="123 ab 4"; char *p; int v,n,k; void main() {     p=s;     while (1) {         k=sscanf(p,"%d%n",&v,&n);         printf("k,v,n=%d,%d,%d\n",k,v,n);         if (1==k) {             p+=n;         } else if (0==k) {             printf("skip char[%c]\n",p[0]);             p++;         } else {//EOF==k             break;         }     }     printf("End.\n"); } //k,v,n=1,123,3 //k,v,n=0,123,3 //skip char[ ] //k,v,n=0,123,3 //skip char[a] //k,v,n=0,123,3 //skip char[b] //k,v,n=1,4,2 //k,v,n=-1,4,2 //End. 看了您的代码，明白了sscanf配合%n的这种用法，表示感谢！您的代码中sscanf是可以读到文件结束表及EOF的，随后我测试了一下scanf函数，代码如下： #include <stdio.h> int main() { 	int v = 0, k = 0; 	while (1) 	{ 		k = scanf("%d", &v); 		printf("k,v=%d,%d\n", k, v); 		if (EOF == k) 			break; 	} 	printf("End.\n"); } 输入：1  23  45  67  8 输出： k,v=1,1 k,v=1,23 k,v=1,45 k,v=1,67 k,v=1,8，然后又循环等待输入，并没有输出"End."为什么scanf函数就读不到EOF呢？

c++可以通过istringstream实现，我觉得C语言应该也可以的，有人实现过吗，麻烦指点一二


Question: 多线程问题

《Windows核心编程》 仅供参考：//循环向a函数每次发送200个字节长度（这个是固定的）的buffer, //a函数中需要将循环传进来的buffer，组成240字节（也是固定的）的新buffer进行处理， //在处理的时候每次从新buffer中取两个字节打印 #ifdef _MSC_VER     #pragma warning(disable:4996) #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _MSC_VER     #include <windows.h>     #include <process.h>     #include <io.h>     #define  MYVOID             void     #define  vsnprintf          _vsnprintf #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  MYVOID             void * #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef _MSC_VER void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } void sleep_ms(int ms) {     Sleep(ms); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } void sleep_ms(int ms) {     usleep(ms*1000); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} #define ASIZE    200 #define BSIZE    240 #define CSIZE      2 char Abuf[ASIZE]; char Cbuf[CSIZE]; CRITICAL_SECTION cs_HEX ; CRITICAL_SECTION cs_BBB ; struct FIFO_BUFFER {     int  head;     int  tail;     int  size;     char data[BSIZE]; } BBB; int No_Loop=0; void HexDump(int cn,char *buf,int len) {     int i,j,k;     char binstr[80];      Lock(&cs_HEX);     for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%03d %04x -",cn,i);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             Log("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         Log("%s\n",binstr);     }     Unlock(&cs_HEX); } int GetFromRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      lent=0;     Lock(cs);     if (fbuf->size>=len) {         lent=len;         if (fbuf->head+lent>BSIZE) {             len1=BSIZE-fbuf->head;             memcpy(buf     ,fbuf->data+fbuf->head,len1);             len2=lent-len1;             memcpy(buf+len1,fbuf->data           ,len2);             fbuf->head=len2;         } else {             memcpy(buf     ,fbuf->data+fbuf->head,lent);             fbuf->head+=lent;         }         fbuf->size-=lent;     }     Unlock(cs);     return lent; } MYVOID thdB(void *pcn) {     char        *recv_buf;     int          recv_nbytes;     int          cn;     int          wc;     int          pb;      cn=(int)pcn;     Log("%03d thdB              thread begin...\n",cn);     while (1) {         sleep_ms(10);         recv_buf=(char *)Cbuf;         recv_nbytes=CSIZE;         wc=0;         while (1) {             pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);             if (pb) {                 Log("%03d recv %d bytes\n",cn,pb);                 HexDump(cn,recv_buf,pb);                 sleep_ms(1);             } else {                 sleep_ms(1000);             }             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef _MSC_VER     pthread_exit(NULL); #endif } int PutToRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      Lock(cs);     lent=len;     if (fbuf->size+lent>BSIZE) {         lent=BSIZE-fbuf->size;     }     if (fbuf->tail+lent>BSIZE) {         len1=BSIZE-fbuf->tail;         memcpy(fbuf->data+fbuf->tail,buf     ,len1);         len2=lent-len1;         memcpy(fbuf->data           ,buf+len1,len2);         fbuf->tail=len2;     } else {         memcpy(fbuf->data+fbuf->tail,buf     ,lent);         fbuf->tail+=lent;     }     fbuf->size+=lent;     Unlock(cs);     return lent; } MYVOID thdA(void *pcn) {     char        *send_buf;     int          send_nbytes;     int          cn;     int          wc;     int           a;     int          pa;      cn=(int)pcn;     Log("%03d thdA              thread begin...\n",cn);     a=0;     while (1) {         sleep_ms(100);         memset(Abuf,a,ASIZE);         a=(a+1)%256;         if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop         send_buf=(char *)Abuf;         send_nbytes=ASIZE;         Log("%03d sending %d bytes\n",cn,send_nbytes);         HexDump(cn,send_buf,send_nbytes);         wc=0;         while (1) {             pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);             Log("%03d sent %d bytes\n",cn,pa);             HexDump(cn,send_buf,pa);             send_buf+=pa;             send_nbytes-=pa;             if (send_nbytes<=0) break;//             sleep_ms(1000);             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef _MSC_VER     pthread_exit(NULL); #endif } int main() { #ifdef _MSC_VER     InitializeCriticalSection(&cs_log);     InitializeCriticalSection(&cs_HEX );     InitializeCriticalSection(&cs_BBB ); #else     pthread_t threads[2];     int threadsN;     int rc;     pthread_mutex_init(&cs_log,NULL);     pthread_mutex_init(&cs_HEX,NULL);     pthread_mutex_init(&cs_BBB,NULL); #endif     Log("Start===========================================================\n");      BBB.head=0;     BBB.tail=0;     BBB.size=0;  #ifdef _MSC_VER     _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);     _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2); #else     threadsN=0;     rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);     rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1); #endif      if (!access("No_Loop",0)) {         remove("No_Loop");         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     while (1) {         sleep_ms(1000);         if (No_Loop) break;//         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     sleep_ms(3000);     Log("End=============================================================\n"); #ifdef _MSC_VER     DeleteCriticalSection(&cs_BBB );     DeleteCriticalSection(&cs_HEX );     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_BBB);     pthread_mutex_destroy(&cs_HEX);     pthread_mutex_destroy(&cs_log); #endif     return 0; }


Question: 销毁双循环链表的方法

仅供参考：//不带表头结点的循环双向链表 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> #include <locale.h> struct NODE {     int          data;     struct NODE *next;     struct NODE *prev; } *head,*p,*q,*s,*p1,*p2,*q1,**ta; int i,k,n,t,m,v,N=10; int main() {     setlocale(LC_ALL,"chs");     srand(time(NULL));      head=NULL;      printf("创建%d个节点的循环双向链表:",N);//创建N个节点的循环双向链表     p=head;     for (i=0;i<N;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) exit(1);         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         q->prev=NULL;         if (NULL==p) {             head=q;             p=head;         } else {             p->next=q;             q->prev=p;             p=q;         }     }     p->next=head;     head->prev=p;      //输出整个循环双向链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      k=3;     v=5;     printf("将值为%d的结点插入到循环双向链表的第%d个结点前:",v,k);//将值为v的结点插入到循环双向链表的第k个结点前     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==1) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) exit(1);             q->data=v;             q->next=head;             q->prev=head->prev;             head->prev->next=q;             head->prev=q;             head=q;             break;         } else {             if (k-1==n) {                 q=(struct NODE *)malloc(sizeof(struct NODE));                 if (NULL==q) exit(1);                 q->data=v;                 q->next=p->next;                 q->prev=p;                 p->next->prev=q;                 p->next=q;                 break;             }         }         p=p->next;         if (p==head) break;     }      //输出整个循环双向链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      k=5;     printf("删除第%d个节点:",k);//删除第k个节点     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==1) {             q=head;             head=head->next;             head->prev=q->prev;             q->prev->next=head;             if (q==head) head=NULL;             free(q);             break;         } else {             if (k-1==n) {                 q=p->next;                 p->next=q->next;                 q->next->prev=p;                 free(q);                 break;             }         }         p=p->next;         if (p==head) break;     }      //输出整个循环双向链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      printf("从小到大排序:");//从小到大排序     for (p=head;p!=NULL;) {         p1=p->prev;         for (q=p->next,q1=p;q!=NULL;) {             if (p->data > q->data) {                  //交换data //              printf("swap %02d %02d\n",p->data,q->data); //              t=p->data;p->data=q->data;q->data=t;                  //或者                  //交换prev和next //              printf("swap %02d %02d\n",p->data,q->data);                 if (p==head) {//p是头                     if (p->next==q) {//pq挨着                         head=q;                         head->prev=p1;                         p1->next=q;                         p->next=q->next;                         p->prev=q;                         q->next->prev=p;                         q->next=p;                         q=p;                         p=head;                     } else {//pq不挨着                         head=q;                         head->prev=p1;                         p1->next=q;                         p2=p->next;                         p->next=q->next;                         p->next->prev=p;                         p->prev=q1;                         q->next->prev=p;                         q->next=p2;                         p2->prev=q;                         q1->next=p;                         q=p;                         p=head;                     }                 } else {//p不是头                     if (p->next==q) {//pq挨着                         p1->next=q;                         p->next=q->next;                         p->prev=q;                         q->next->prev=p;                         q->next=p;                         q->prev=p1;                         q=p;                         p=p1->next;                     } else {//pq不挨着                         p1->next=q;                         p2=p->next;                         p->next=q->next;                         p->prev=q->prev;                         q->next->prev=p;                         q->next=p2;                         q->prev=p1;                         p2->prev=q;                         q1->next=p;                         q=p;                         p=p1->next;                     }                 }                  //输出整个循环双向链表 //              s=head; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d(=)",s->data); //                  if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;} //                  s=s->next; //                  if (s==head) { //                      printf(" Loop\n"); //                      break; //                  } //              } //              printf("head,p,q:%02d %02d %02d\n",head->data,p->data,q->data); //              getchar();             }             q1=q;q=q->next;             if (q==head) break;         }         p=p->next;         if (p->next==head) break;     }      //输出整个循环双向链表并计算链表长度n     n=0;     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         n++;         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      printf("将整个链表逆序:");//将整个链表逆序     if (n>=2) {         p=head;         while (1) {             q=p->prev;p->prev=p->next;p->next=q;             p=p->next;             if (p==head) break;         }     }      //输出整个循环双向链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      m=4;     n=6;     printf("将循环双向链表中前%d个结点和后%d个结点进行互换:",m,n);//将循环双向链表中前m个结点和后n个结点进行互换,m+n为链表总长     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m==k) {             q=p;             break;         }         p=p->next;         if (p==head) break;     }     head=q->next;      //输出整个循环双向链表     s=head;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d(=)",s->data);         if (NULL!=s->next && s->next->prev!=s) {printf(" !\n");break;}         s=s->next;         if (s==head) {             printf(" Loop\n");             break;         }     }      //释放所有节点     p=head;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;         if (p==head) {             break;         }     }      return 0; } //创建10个节点的循环双向链表:12(=)46(=)31(=)63(=)25(=)91(=)39(=)02(=)92(=)68(=) Loop //将值为5的结点插入到循环双向链表的第3个结点前:12(=)46(=)05(=)31(=)63(=)25(=)91(=)39(=)02(=)92(=)68(=) Loop //删除第5个节点:12(=)46(=)05(=)31(=)25(=)91(=)39(=)02(=)92(=)68(=) Loop //从小到大排序:02(=)05(=)12(=)25(=)31(=)39(=)46(=)68(=)91(=)92(=) Loop //将整个链表逆序:92(=)91(=)68(=)46(=)39(=)31(=)25(=)12(=)05(=)02(=) Loop //将循环双向链表中前4个结点和后6个结点进行互换:39(=)31(=)25(=)12(=)05(=)02(=)92(=)91(=)68(=)46(=) Loop //


Question: 实现计算器功能，输出乱码？

仅供参考：/*--------------------------------------- 函数型计算器(VC++6.0,Win32 Console) 功能： 目前提供了10多个常用数学函数:     ⑴正弦sin     ⑵余弦cos     ⑶正切tan     ⑷开平方sqrt     ⑸反正弦arcsin     ⑹反余弦arccos     ⑺反正切arctan     ⑻常用对数lg     ⑼自然对数ln     ⑽ｅ指数exp     ⑾乘幂函数^     ⑿向上取整ceil     ⒀向下取整floor     ⒁四舍五入取整round 用法： 如果要求2的32次幂，可以打入2^32<回车> 如果要求30度角的正切可键入tan(Pi/6)<回车> 注意不能打入：tan(30)<Enter> 如果要求1.23弧度的正弦，有几种方法都有效： sin(1.23)<Enter> sin 1.23 <Enter> sin1.23  <Enter> 如果验证正余弦的平方和公式,可打入sin(1.23)^2+cos(1.23)^2 <Enter>或sin1.23^2+cos1.23^2 <Enter> 此外两函数表达式连在一起,自动理解为相乘如：sin1.23cos0.77+cos1.23sin0.77就等价于sin(1.23)*cos(0.77)+cos(1.23)*sin(0.77) 当然你还可以依据三角变换，再用sin(1.23+0.77)也即sin2验证一下。 本计算器充分考虑了运算符的优先级因此诸如：2+3*4^2 实际上相当于：2+(3*(4*4)) 另外函数名前面如果是数字,那么自动认为二者相乘. 同理，如果某数的右侧是左括号，则自动认为该数与括弧项之间隐含一乘号。 如：3sin1.2^2+5cos2.1^2 相当于3*sin2(1.2)+5*cos2(2.1) 又如：4(3-2(sqrt5-1)+ln2)+lg5 相当于4*(3-2*(√5 -1)+loge(2))+log10(5) 此外，本计算器提供了圆周率 Pi键入字母时不区分大小写,以方便使用。 ----------------------------------------*/ #include <iostream> #include <iomanip> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <stdio.h> #include <string.h> #include <windows.h> using namespace std; const char Tab=0x9; const int  DIGIT=1; const int MAXLEN=16384; char s[MAXLEN],*endss; int pcs=15; double round(double dVal, short iPlaces) {//iPlaces>=0     char s[30];     double dRetval;      sprintf(s,"%.*lf",iPlaces,dVal);     sscanf(s,"%lf",&dRetval);     return (dRetval); } double fun(double x,char op[],int *iop) {     while (op[*iop-1]<32) //本行使得函数嵌套调用时不必加括号,如 arc sin(sin(1.234)) 只需键入arc sin sin 1.234<Enter>         switch (op[*iop-1]) {         case  7: x=sin(x);    (*iop)--;break;         case  8: x=cos(x);    (*iop)--;break;         case  9: x=tan(x);    (*iop)--;break;         case 10: x=sqrt(x);   (*iop)--;break;         case 11: x=asin(x);   (*iop)--;break;         case 12: x=acos(x);   (*iop)--;break;         case 13: x=atan(x);   (*iop)--;break;         case 14: x=log10(x);  (*iop)--;break;         case 15: x=log(x);    (*iop)--;break;         case 16: x=exp(x);    (*iop)--;break;         case 17: x=ceil(x);   (*iop)--;break;         case 18: x=floor(x);  (*iop)--;break;         case 19: x=round(x,0);(*iop)--;break;         }     return x; } double calc(char *expr,char **addr) {     static int deep; //递归深度     static char *fname[]={"sin","cos","tan","sqrt","arcsin","arccos","arctan","lg","ln","exp","ceil","floor","round",NULL};     double ST[10]={0.0}; //数字栈     char op[10]={'+'}; //运算符栈     char c,*rexp,*pp,*pf;     int ist=1,iop=1,last,i;      if (!deep) {         pp=pf=expr;         do {             c = *pp++;             if (c!=' '&& c!=Tab)                 *pf++ = c;         } while (c!='\0');     }     pp=expr;     if ((c=*pp)=='-'||c=='+') {         op[0] = c;         pp++;     }     last = !DIGIT;     while ((c=*pp)!='\0') {         if (c=='(') {//左圆括弧             deep++;             ST[ist++]=calc(++pp,addr);             deep--;             ST[ist-1]=fun(ST[ist-1],op,&iop);             pp = *addr;             last = DIGIT;             if (*pp == '('||isalpha(*pp) && strnicmp(pp,"Pi",2)) {//目的是：当右圆括弧的右恻为左圆括弧或函数名字时，默认其为乘法                 op[iop++]='*';                 last = !DIGIT;                 c = op[--iop];                 goto operate ;             }         }         else if (c==')') {//右圆括弧             pp++;             break;         } else if (isalpha(c)) {             if (!strnicmp(pp,"Pi",2)) {                 if (last==DIGIT) {                     cout<< "π左侧遇）" <<endl;exit(1);                 }                 ST[ist++]=3.14159265358979323846264338328;                 ST[ist-1]=fun(ST[ist-1],op,&iop);                 pp += 2;                 last = DIGIT;                 if (!strnicmp(pp,"Pi",2)) {                     cout<< "两个π相连" <<endl;exit(2);                 }                 if (*pp=='(') {                     cout<< "π右侧遇（" <<endl;exit(3);                 }             } else {                 for (i=0; (pf=fname[i])!=NULL; i++)                     if (!strnicmp(pp,pf,strlen(pf))) break;                 if (pf!=NULL) {                     op[iop++] = 07+i;                     pp += strlen(pf);                 } else {                     cout<< "陌生函数名" <<endl;exit(4);                 }             }         } else if (c=='+'||c=='-'||c=='*'||c=='/'||c=='%'||c=='^') {             char cc;             if (last != DIGIT) {                 cout<< "运算符粘连" <<endl;exit(5);             }             pp++;             if (c=='+'||c=='-') {                 do {                     cc = op[--iop];                     --ist;                     switch (cc) {                     case '+':  ST[ist-1] += ST[ist];break;                     case '-':  ST[ist-1] -= ST[ist];break;                     case '*':  ST[ist-1] *= ST[ist];break;                     case '/':  ST[ist-1] /= ST[ist];break;                     case '%':  ST[ist-1] = fmod(ST[ist-1],ST[ist]);break;                     case '^':  ST[ist-1] = pow(ST[ist-1],ST[ist]);break;                     }                 } while (iop);                 op[iop++] = c;             } else if (c=='*'||c=='/'||c=='%') { operate:        cc = op[iop-1];                 if (cc=='+'||cc=='-') {                     op[iop++] = c;                 } else {                     --ist;                     op[iop-1] = c;                     switch (cc) {                     case '*':  ST[ist-1] *= ST[ist];break;                     case '/':  ST[ist-1] /= ST[ist];break;                     case '%':  ST[ist-1] = fmod(ST[ist-1],ST[ist]);break;                     case '^':  ST[ist-1] = pow(ST[ist-1],ST[ist]);break;                     }                 }             } else {                 cc = op[iop-1];                 if (cc=='^') {                     cout<< "乘幂符连用" <<endl;exit(6);                 }                 op[iop++] = c;             }             last = !DIGIT;         } else {             if (last == DIGIT) {                 cout<< "两数字粘连" <<endl;exit(7);             }             ST[ist++]=strtod(pp,&rexp);             ST[ist-1]=fun(ST[ist-1],op,&iop);             if (pp == rexp) {                 cout<< "非法字符" <<endl;exit(8);             }             pp = rexp;             last = DIGIT;             if (*pp == '('||isalpha(*pp)) {                 op[iop++]='*';                 last = !DIGIT;                 c = op[--iop];                 goto operate ;             }         }     }     *addr=pp;     if (iop>=ist) {         cout<< "表达式有误" <<endl;exit(9);     }     while (iop) {         --ist;         switch (op[--iop]) {         case '+':  ST[ist-1] += ST[ist];break;         case '-':  ST[ist-1] -= ST[ist];break;         case '*':  ST[ist-1] *= ST[ist];break;         case '/':  ST[ist-1] /= ST[ist];break;         case '%':  ST[ist-1] = fmod(ST[ist-1],ST[ist]);break;         case '^':  ST[ist-1] = pow(ST[ist-1],ST[ist]);break;         }     }     return ST[0]; } int main(int argc,char **argv) {     int a;      if (argc<2) {         if (GetConsoleOutputCP()!=936) system("chcp 936>NUL");//中文代码页         cout << "计算函数表达式的值。"<<endl<<"支持(),+,-,*,/,%,^,Pi,sin,cos,tan,sqrt,arcsin,arccos,arctan,lg,ln,exp,ceil,floor,round"<<endl;         while (1) {             cout << "请输入表达式：";             gets(s);             if (s[0]==0) break;//             cout << s <<"=";             cout << setprecision(15) << calc(s,&endss) << endl;         }     } else if (argc==2 && 0==strcmp(argv[1],"/?")) {         if (GetConsoleOutputCP()!=936) system("chcp 936>NUL");//中文代码页         cout << "计算由≥1个命令行参数给出的函数表达式的值。最后一个参数是.0～.15表示将计算结果保留小数0～15位"<<endl<<"支持(),+,-,*,/,%,^^,Pi,sin,cos,tan,sqrt,arcsin,arccos,arctan,lg,ln,exp,ceil,floor,round"<<endl;     } else {         strncpy(s,argv[1],MAXLEN-1);s[MAXLEN-1]=0;         if (argc>2) {             for (a=2;a<argc-1;a++) strncat(s,argv[a],MAXLEN-1);//将空格间隔的各参数连接到s             if (1==sscanf(argv[a],".%d",&pcs) && 0<=pcs && pcs<=15) {//最后一个参数是.0～.15表示将计算结果保留小数0～15位                 printf("%.*lf\n",pcs,calc(s,&endss));             } else {                 strncat(s,argv[a],MAXLEN-1);                 printf("%.15lg\n",calc(s,&endss));             }         } else {             printf("%.15lg\n",calc(s,&endss));         }     }     return 0; }

printf可以用%f输出double 但scanf只能用%lf

scanf的时候double用%lf才行，输出的时候都可  #include "stdlib.h" #include "string.h" #include "stdio.h" #include "math.h"  void main() { 	double aNum, bNum, Res; 	int No;  	system("title 简单计算器 ");                //程序窗口上的标题   	while (1) 	{ 		printf("输入需计算两数：\n"); 		scanf("%lf%lf", &aNum, &bNum);  		printf("*************************************************\n"); 		printf("请选择你要计算的方法:                        \n"); 		printf("  加法请按_1                                  \n"); 		printf("  减法请按_2                                  \n"); 		printf("  乘法请按_3                                  \n"); 		printf("  除法请按_4               退出_0             \n"); 		printf("*************************************************\n"); 		printf("Please write down the number:"); 		scanf("%d", &No);  		switch (No) 		{ 		case 1: 			Res = aNum + bNum; 			printf(" 结果是: %f\n", Res); 			break; 		case 2: 			Res = aNum - bNum; 			printf(" 结果是: %f\n", Res); 			break; 		case 3: 			Res = aNum * bNum; 			printf(" 结果是: %f\n", Res); 			break; 		case 4: 			if (bNum == 0) 			{ 				printf("无法进行除法运算\n"); 				break; 			} 			else 			{ 				Res = aNum / bNum; 				printf(" 结果是: %f\n", Res); 			} 			break; 		case 0: 			break; 		default: 			printf("输入错误\n"); 		}    		system("pause");        //按任意键继续   		system("cls");                //清屏   	} 	return; }

%f 输入的是 float,  用 %lf 来输入 double


Question: 如何求二维数组的最大路径

和你得到最大路径的个数方法大致一样，声明两个整数数组：一个临时性存储每一次尝试的路径的足迹（即所连的数字，逐个压入数组），在循环中每次尝试都被重置和填充。另一个存储到目前为止的最长路径所记录的足迹（即所连的数字）。当新计算的最大步数超过上一次最长的记录，更新最大步数时，也更新一下足迹数组。