Question: 如何把2个16位二进制数进行加减乘除

仅供参考：#include <iostream> #include <string> using namespace std; inline int compare(string str1,string str2) {//相等返回0，大于返回1，小于返回-1          if (str1.size()>str2.size()) return 1; //长度长的整数大于长度小的整数     else if (str1.size()<str2.size()) return -1;     else                              return str1.compare(str2); //若长度相等，则头到尾按位比较 } string SUB_INT(string str1,string str2); string ADD_INT(string str1,string str2) {//高精度加法     int sign=1; //sign 为符号位     string str;     if (str1[0]=='-') {         if (str2[0]=='-') {             sign=-1;             str=ADD_INT(str1.erase(0,1),str2.erase(0,1));         } else {             str=SUB_INT(str2,str1.erase(0,1));         }     } else {         if (str2[0]=='-') {             str=SUB_INT(str1,str2.erase(0,1));         } else { //把两个整数对齐，短整数前面加0补齐             string::size_type L1,L2;             int i;             L1=str1.size();             L2=str2.size();             if (L1<L2) {                 for (i=1;i<=L2-L1;i++) str1="0"+str1;             } else {                 for (i=1;i<=L1-L2;i++) str2="0"+str2;             }             int int1=0,int2=0; //int2 记录进位             for (i=str1.size()-1;i>=0;i--) {                 int1=(int(str1[i])-'0'+int(str2[i])-'0'+int2)%10;                 int2=(int(str1[i])-'0'+int(str2[i])-'0'+int2)/10;                 str=char(int1+'0')+str;             }             if (int2!=0) str=char(int2+'0')+str;         }     }     //运算后处理符号位     if ((sign==-1)&&(str[0]!='0')) str="-"+str;     return str; } string SUB_INT(string str1,string str2) {//高精度减法     int sign=1; //sign 为符号位     string str;     int i,j;     if (str2[0]=='-') {         str=ADD_INT(str1,str2.erase(0,1));     } else {         int res=compare(str1,str2);         if (res==0) return "0";         if (res<0) {             sign=-1;             string temp =str1;             str1=str2;             str2=temp;         }         string::size_type tempint;         tempint=str1.size()-str2.size();         for (i=str2.size()-1;i>=0;i--) {             if (str1[i+tempint]<str2[i]) {                 j=1;                 while (1) {//zhao4zhong1添加                     if (str1[i+tempint-j]=='0') {                         str1[i+tempint-j]='9';                         j++;                     } else {                         str1[i+tempint-j]=char(int(str1[i+tempint-j])-1);                         break;                     }                 }                 str=char(str1[i+tempint]-str2[i]+':')+str;             } else {                 str=char(str1[i+tempint]-str2[i]+'0')+str;             }         }         for (i=tempint-1;i>=0;i--) str=str1[i]+str;     }     //去除结果中多余的前导0     str.erase(0,str.find_first_not_of('0'));     if (str.empty()) str="0";     if ((sign==-1) && (str[0]!='0')) str ="-"+str;     return str; } string MUL_INT(string str1,string str2) {//高精度乘法     int sign=1; //sign 为符号位     string str;     if (str1[0]=='-') {         sign*=-1;         str1 =str1.erase(0,1);     }     if (str2[0]=='-') {         sign*=-1;         str2 =str2.erase(0,1);     }     int i,j;     string::size_type L1,L2;     L1=str1.size();     L2=str2.size();     for (i=L2-1;i>=0;i--) { //模拟手工乘法竖式         string tempstr;         int int1=0,int2=0,int3=int(str2[i])-'0';         if (int3!=0) {             for (j=1;j<=(int)(L2-1-i);j++) tempstr="0"+tempstr;             for (j=L1-1;j>=0;j--) {                 int1=(int3*(int(str1[j])-'0')+int2)%10;                 int2=(int3*(int(str1[j])-'0')+int2)/10;                 tempstr=char(int1+'0')+tempstr;             }             if (int2!=0) tempstr=char(int2+'0')+tempstr;         }         str=ADD_INT(str,tempstr);     }     //去除结果中的前导0     str.erase(0,str.find_first_not_of('0'));     if (str.empty()) str="0";     if ((sign==-1) && (str[0]!='0')) str="-"+str;     return str; } string DIVIDE_INT(string str1,string str2,int flag) {//高精度除法。flag==1时,返回商; flag==0时,返回余数     string quotient,residue; //定义商和余数     int sign1=1,sign2=1;     if (str2 == "0") {  //判断除数是否为0         quotient= "ERROR!";         residue = "ERROR!";         if (flag==1) return quotient;         else         return residue ;     }     if (str1=="0") { //判断被除数是否为0         quotient="0";         residue ="0";     }     if (str1[0]=='-') {         str1   = str1.erase(0,1);         sign1 *= -1;         sign2  = -1;     }     if (str2[0]=='-') {         str2   = str2.erase(0,1);         sign1 *= -1;     }     int res=compare(str1,str2);     if (res<0) {         quotient="0";         residue =str1;     } else if (res == 0) {         quotient="1";         residue ="0";     } else {         string::size_type L1,L2;         L1=str1.size();         L2=str2.size();         string tempstr;         tempstr.append(str1,0,L2-1);         for (int i=L2-1;i<L1;i++) { //模拟手工除法竖式             tempstr=tempstr+str1[i];             tempstr.erase(0,tempstr.find_first_not_of('0'));//zhao4zhong1添加             if (tempstr.empty()) tempstr="0";//zhao4zhong1添加             for (char ch='9';ch>='0';ch--) { //试商                 string str;                 str=str+ch;                 if (compare(MUL_INT(str2,str),tempstr)<=0) {                     quotient=quotient+ch;                     tempstr =SUB_INT(tempstr,MUL_INT(str2,str));                     break;                 }             }         }         residue=tempstr;     }     //去除结果中的前导0     quotient.erase(0,quotient.find_first_not_of('0'));     if (quotient.empty()) quotient="0";     if ((sign1==-1)&&(quotient[0]!='0')) quotient="-"+quotient;     if ((sign2==-1)&&(residue [0]!='0')) residue ="-"+residue ;     if (flag==1) return quotient;     else         return residue ; } string DIV_INT(string str1,string str2) {//高精度除法,返回商     return DIVIDE_INT(str1,str2,1); } string MOD_INT(string str1,string str2) {//高精度除法,返回余数     return DIVIDE_INT(str1,str2,0); } int main() {     char ch;     string s1,s2,res;      while (cin>>s1>>ch>>s2) {         switch (ch) {             case '+':res=ADD_INT(s1,s2);break;             case '-':res=SUB_INT(s1,s2);break;             case '*':res=MUL_INT(s1,s2);break;             case '/':res=DIV_INT(s1,s2);break;             case '%':res=MOD_INT(s1,s2);break;             default :                   break;         }         cout<<res<<endl;     }     return(0); }

有很多大数运算现有的库，楼主可以去搜索参考

这个你先手动算下，然后再转换为代码呗，应该不难吧

google 大数运算

引用 12 楼 zhao4zhong1 的回复:[quote=引用 11 楼 user-5 的回复:] [quote=引用 10 楼 zhao4zhong1 的回复:] [quote=引用 8 楼 user-5 的回复:] [quote=引用 5 楼 chimenghuanzhe 的回复:] @zhao4zhong1    谢谢你的解答。但是，导师说必须用汇编语言解决。至少中间的加减乘除计算部分要用汇编来完成。所以我在发愁呢。尤其是如何把汇编语言的代码嵌入到C语言的程序中。 把它的程序，编译成 asm 文件就可以了[/quote] 这个办法比较暗黑。[/quote] ^_^ 他 写错字了，抱歉[/quote] 是和手滑点错鼠标、忘关摄像头、……、一个节奏吗？[/quote]嗯

引用 11 楼 user-5 的回复:[quote=引用 10 楼 zhao4zhong1 的回复:] [quote=引用 8 楼 user-5 的回复:] [quote=引用 5 楼 chimenghuanzhe 的回复:] @zhao4zhong1    谢谢你的解答。但是，导师说必须用汇编语言解决。至少中间的加减乘除计算部分要用汇编来完成。所以我在发愁呢。尤其是如何把汇编语言的代码嵌入到C语言的程序中。 把它的程序，编译成 asm 文件就可以了[/quote] 这个办法比较暗黑。[/quote] ^_^ 他 写错字了，抱歉[/quote] 是和手滑点错鼠标、忘关摄像头、……、一个节奏吗？

引用 10 楼 zhao4zhong1 的回复:[quote=引用 8 楼 user-5 的回复:] [quote=引用 5 楼 chimenghuanzhe 的回复:] @zhao4zhong1    谢谢你的解答。但是，导师说必须用汇编语言解决。至少中间的加减乘除计算部分要用汇编来完成。所以我在发愁呢。尤其是如何把汇编语言的代码嵌入到C语言的程序中。 把它的程序，编译成 asm 文件就可以了[/quote] 这个办法比较暗黑。[/quote] ^_^ 他 写错字了，抱歉

引用 8 楼 user-5 的回复:[quote=引用 5 楼 chimenghuanzhe 的回复:] @zhao4zhong1    谢谢你的解答。但是，导师说必须用汇编语言解决。至少中间的加减乘除计算部分要用汇编来完成。所以我在发愁呢。尤其是如何把汇编语言的代码嵌入到C语言的程序中。 把它的程序，编译成 asm 文件就可以了[/quote] 这个办法比较暗黑。

你直接写C语言，然后在调试时按Alt+8打开汇编窗口，参考每句C对应的32位汇编将对应C语句翻译为嵌入汇编__asm指令？

引用 5 楼 chimenghuanzhe 的回复:@zhao4zhong1    谢谢你的解答。但是，导师说必须用汇编语言解决。至少中间的加减乘除计算部分要用汇编来完成。所以我在发愁呢。尤其是如何把汇编语言的代码嵌入到C语言的程序中。 把它的程序，编译成 asm 文件就可以了

@zhao4zhong1   请问您能不能帮我看一下这个帖子。http://bbs.csdn.net/topics/392006453  谢谢谢谢！

__asm Microsoft Specific   __asm  assembly-language-instruction  __asm { assembly-language-instructions }  If used without braces, the __asm keyword means that the rest of the line is an assembly-language statement. If used with braces, it means that each line between the braces is an assembly-language statement. For compatibility with previous versions, _asm is a synonym for __asm.  Since the __asm keyword is a statement separator, you can put assembly instructions on the same line.  For related information, see Assembler (Inline) Topics.   Note   Microsoft C++ does not support the AT&T C++ asm keyword.  END Microsoft Specific  Example  // Example of the __asm keyword __asm                  // __asm block {    mov eax, 01h    int 10h }  __asm mov eax, 01h      // Separate __asm lines __asm int 10h  // Multiple __asm statements on a line __asm mov eax, 01h   __asm int 10h


Question: 关于printf缓冲区的奇怪问题

引用 5 楼 小菜瓜呱呱呱 的回复:引用 2 楼 wen_eric 的回复:帮顶版主，不好意思，我明白加fflush刷新缓冲区，但还是不明白为什么关闭stdout前加了printf就不用fflush了  首先：printf的缓冲有多重情况，标准输出是行缓冲，重定向到文件是全缓冲，而系统调用是不带缓冲的。所以在重定向后它是全缓冲，所以printf("Nice to meet you!\n");中"\n"不能刷缓冲，所以此时如果不调用fflush，nice to meet you 就不会被写入到文件。  其次如果在重定向之前调用了 printf("-------------1----------------\n");//加了这个printf即使不flush(stdout);也会正常写入文件，这是为什么 这句话，那么 printf 在重定向之后还是行缓冲，并没有变为全缓冲。在行缓冲中"\n"具有刷缓冲的功能。所以printf("Nice to meet you!\n"); 可以写入文件中。

我也好奇。。按理说应该被改成全缓冲了啊？

引用 15 楼 qq_29532941 的回复：遇到跟楼主一样的问题，请问楼主解决了吗？请教一下，为什么在close(1)之前加了printf后之后的printf可以正常输出呢？谢谢不是关闭stdout，是重定位到了txt文档，在重定位前加printf，然后之后的printf都可以正常输出到该文档，否则不行

行缓冲方式被改变，缓冲区满，刷新。

stdout默认是行缓冲的，也就是遇到\n刷新缓冲。你把它关了，重新打开的话，肯定缓冲模式就重置了。 http://man7.org/linux/man-pages/man3/setbuf.3.html setvbuf可以用设置为行缓冲或者无缓冲。  的确close、open属于无缓冲的API，所以close文件是不会同步缓冲的。 你应该用freopen("redir.txt", "w", stdout)这样用支持缓冲的方式重新打开文件stdout， 这样当你fclose时就会正确同步文件了。

感觉楼主这里混淆了两套概念。linux C语言文件读写有两套API，一套是open，close，read这一类API，这些函数是系统调用，open返回的fd是一个整型数。还有一套API是C标准库中的fopen，fclose，fread等等，这是一类带缓冲的文件操作API，其中fopen返回的是一个FILE类型的指针。楼主的代码里貌似混用了这两套API，如果统一使用C标准库中以f开头的那些文件读写函数，是否还会出现这些问题？

引用 9 楼 u014735054 的回复:[quote=引用 8 楼 paschen 的回复:] [quote=引用 6 楼 u014735054 的回复:] [quote=引用 3 楼 paschen 的回复:] http://en.cppreference.com/w/c/io/fflush 版主，不好意思，我明白加fflush刷新缓冲区，但还是不明白为什么关闭stdout前加了printf就不用fflush了[/quote]  prinf函数时可能会刷新缓冲区[/quote]为什么两个printf时第二个就刷新缓冲区，而一个printf的时候就没有刷新[/quote]  第一个的时候你不是还没打开文件

引用 8 楼 paschen 的回复:[quote=引用 6 楼 u014735054 的回复:] [quote=引用 3 楼 paschen 的回复:] http://en.cppreference.com/w/c/io/fflush 版主，不好意思，我明白加fflush刷新缓冲区，但还是不明白为什么关闭stdout前加了printf就不用fflush了[/quote]  prinf函数时可能会刷新缓冲区[/quote]为什么两个printf时第二个就刷新缓冲区，而一个printf的时候就没有刷新

引用 6 楼 u014735054 的回复:[quote=引用 3 楼 paschen 的回复:] http://en.cppreference.com/w/c/io/fflush 版主，不好意思，我明白加fflush刷新缓冲区，但还是不明白为什么关闭stdout前加了printf就不用fflush了[/quote]  prinf函数时可能会刷新缓冲区

引用 4 楼 zhao4zhong1 的回复:printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方，而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。  在每个最后不带\n的printf后面加fflush(stdout); 在每个不想受接收缓冲区旧内容影响的scanf前面加rewind(stdin); 另外请检查scanf的返回值。 //请今后要用 int c; scanf("%c",&c); //时，都改为 char s[2]; int c; scanf("%1s",s); c=s[0];感谢回复，不过不太明白和我的问题的联系在哪里，不好意思请指教

引用 3 楼 paschen 的回复:http://en.cppreference.com/w/c/io/fflush 版主，不好意思，我明白加fflush刷新缓冲区，但还是不明白为什么关闭stdout前加了printf就不用fflush了

帮顶

#include <stdio.h>  int main() {     FILE* file = freopen("out.txt", "w", stdout);     if (file) {         printf("Nice to meet you!\n");     } } .... 我貌似记得fflush(stdout);不是标准?


Question: malloc与free 的问题

引用 5 楼 zhao4zhong1 的回复:判断是否越界访问，可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断，可将数组多声明一个元素，并设置数据读写断点在该多出元素对应的地址上。 #include <time.h> #include <stdlib.h> #include <windows.h> int main() {     int a,b[11];//本来是b[10]，为判断哪句越界，故意声明为b[11]      srand((unsigned int)time(NULL));//按两次F11，等黄色右箭头指向本行时，调试、新建断点、新建数据断点，地址：&b[10]，字节计数：4，确定。     while (1) {//按F5，会停在下面某句，此时a的值为10，b[10]已经被修改为对应0..4之一。         b[(a=rand()%11)]=0;         Sleep(100);         b[(a=rand()%11)]=1;         Sleep(100);         b[(a=rand()%11)]=2;         Sleep(100);         b[(a=rand()%11)]=3;         Sleep(100);         b[(a=rand()%11)]=4;         Sleep(100);     }     return 0; }  赵老师这个方法经典。

同意楼上的说法，free出错一般都是越界访问导致的。 跟踪调试找到越界的地方，改掉就好了。

free出错一般都是越界导致的。 你申请的空间周围是有各种内存管理信息的，一旦你不小心覆盖掉了，free就会释放出错

检查访问申请的内存时有没越界，如果越界会破坏了堆，很可能导致free时出错

我觉得应该是freeall函数中free的用法有点缺陷，加一个中间临时变量会更好一点。菜鸡拙见，不知对不对


Question: 在头文件中定义一个变量，为什么不赋值编译没错，赋初值就报错“重定义”？

多次声明一个变量没问题，多次定义就会重复  另外可以用#ifndef  #define #endif防止头文件重复包含

只是像是不同源文件#include 同一个头文件一样而已...独立的和函数声明相像. 可以重复声明, 但是不能重复实现

引用 1 楼 user-2 的回复:c/c++是以源文件为单位的, 这两个源文件都会对a初始化, 加上static就没事， 但是加上的话这每个源文件的a变量都是独立的了  为什么不赋值的就不会报错呢

为什么不赋值的时候就不会报错呢？


Question: 新人报道，求教各位大神一个问题

引用 1 楼 zhao4zhong1 的回复:代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！ 大神能否帮忙看下这个问题呢 http://bbs.csdn.net/topics/392005561


Question: 面向对象真的让问题变的更简单吗?我要从程序设计逻辑里不断去寻找类和对象，归类它们的属性和方法，还要考虑类与类之间的关系，反观面向过程，直接去实现就是了。

引用 26 楼 yyxgs 的回复:[quote=引用 24 楼 zhao4zhong1 的回复:] 我预言，程序开发语言永远追不上自然语言。   我预言赵老师出一本哲理书籍销量肯定高。[/quote] 出书太累，还是偷懒推荐一本书吧：《皇帝新脑》

引用 31 楼 yyxgs 的回复:大家说的对。存在即合理，面向对象肯定有过于面向过程的优势所以才能被广泛应用，谢谢大家指教! 结贴。  你是没学过GOF的人。这个必须学的。自己找找书看看吧。

引用 28 楼 zanfeng 的回复:[quote=引用 1 楼 yyxgs 的回复:] C代码:  #include <stdio.h>  typedef struct Person {  	char* name; 	int age; };  int main(int argc, char *argv[])  { 	int i = 0;  	Person one = { 0 }; 	one.name = "张三"; 	one.age = 18;  	printf("我是%s, 我今年%d岁!\n", one.name, one.age);  	return 0; }  这样用有啥优势啊。 public class student:person {     }  继承接口才是优势 单纯的定义一个类有或者结构体有啥意义[/quote]   结构体是种类型的，比如一个人有姓名和年龄 继承一个学生的话不是可以将Person定义到学生结构体里去吗?

引用 27 楼 u010165006 的回复:小程序体会不出面向对象的优势。 如果楼主学习了一种类库，理解了类的继承与多态，你会觉得不用面向对象无法想象如何实现，代码量会多出多少！ 面向对象分析与设计是专门的一门课，比较抽象。   原来如此。

引用 1 楼 yyxgs 的回复:C代码:  #include <stdio.h>  typedef struct Person {  	char* name; 	int age; };  int main(int argc, char *argv[])  { 	int i = 0;  	Person one = { 0 }; 	one.name = "张三"; 	one.age = 18;  	printf("我是%s, 我今年%d岁!\n", one.name, one.age);  	return 0; }  这样用有啥优势啊。 public class student:person {     }  继承接口才是优势 单纯的定义一个类有或者结构体有啥意义

引用 24 楼 zhao4zhong1 的回复:我预言，程序开发语言永远追不上自然语言。   我预言赵老师出一本哲理书籍销量肯定高。

引用 23 楼 anhuizhuanjiao 的回复:还有一种东西叫面向并发，如果你写过Erlang，就会发现那才是最适合人写的语言   好吧，可以说这还是第二次听到。

我预言，程序开发语言永远追不上自然语言。

还有一种东西叫面向并发，如果你写过Erlang，就会发现那才是最适合人写的语言

引用 19 楼 kongl123 的回复:俗话说“反抗不了那就学会去享受”。不的不用那就尝试去理解为什么大家都要用，去尝试看到美好的东西。  你现在说面向对象和面向对象，实际上围绕这两种思想而发明的知名的编译语言不下几十种，它们的优点体现在不同应用场景，当你遇到了这种场景，也许你会觉得非它莫属。一个优秀的公司和技术leader都会选择出一种适合自己情况的语言   好吧，我相信面向对象有它的优点，但我觉得它比面向过程更麻烦。。。

引用 18 楼 user-6 的回复:楼主试试用C语言写个矩阵的加减乘求逆等等。  为什么要我写这个?

引用 17 楼 zhao4zhong1 的回复:[quote=引用 16 楼 yyxgs 的回复:] [quote=引用 13 楼 zhao4zhong1 的回复:] 萝卜白菜，各有所爱。   但有时候必须去接受别人都在用的东西。 作个比喻: 我喜欢用QQ，朋友都喜欢用微信。后来我也就不得不也用微信了。[/quote] 随大溜 和 彰显个性 不矛盾。  为人随和 和 坚持自我 不矛盾。  双重人格不是贬义词。 [/quote]

楼主试试用C语言写个矩阵的加减乘求逆等等。

引用 16 楼 yyxgs 的回复:[quote=引用 13 楼 zhao4zhong1 的回复:] 萝卜白菜，各有所爱。   但有时候必须去接受别人都在用的东西。 作个比喻: 我喜欢用QQ，朋友都喜欢用微信。后来我也就不得不也用微信了。[/quote] 随大溜 和 彰显个性 不矛盾。  为人随和 和 坚持自我 不矛盾。  双重人格不是贬义词。

引用 13 楼 zhao4zhong1 的回复:萝卜白菜，各有所爱。   但有时候必须去接受别人都在用的东西。 作个比喻: 我喜欢用QQ，朋友都喜欢用微信。后来我也就不得不也用微信了。

引用 12 楼 kongl123 的回复:这种问题看看就行了。当你发现一个东西的好之前它就是不好的，你不用因为别人说好而勉强自己去用，因为你没发现，所以也用不到它的好。用你已经发现了它的好的东西对你来说利益是最大化的   如果只是我自己肯定随意，但是公司都使用面向对象.....

引用 9 楼 cxyOOOO 的回复:“从程序设计逻辑里不断去寻找类和对象”，这样做是不对的。   那应该怎么去找类和对象呢?


Question: fseek函数将文件指针设置到文件尾之后会产生什么行为？

fseek定位到文件尾部，如果是文件读取，则会返回EOF；如果是文件写入，则会在文件尾部追加数据。一般将文件定位到文件尾部有这么几个应用场景： 1. 获取文件大小。即首先用fseek到文件末尾，然后用ftell就可以知道文件占用了多少字节的空间。 2. 读取相对于文件末尾的某个重要字段，类似Magic Number，Magic Number一般是在文件头部，但是如果有某种文件规定文件末尾的几个字节有特殊含义，这是要读取这些字节就会定位到文件尾部。

仔细读：http://en.cppreference.com/w/c/io/fseek

引用 1 楼 zjq9931的回复:跳到文件尾，就是跳到文件尾了啊。 读是读不到了，只能写。 文件大小只有3K，继续写的时候却想从9K的地方写。 那么3K-9K之间你打算填充空白吗？你需要定义什么是空白，什么是空白你就往那一段里面写入什么，就好了。 谢谢，明白你的意思了，在文件尾追加空白数据，直到9KB处再写入新数据。

fseek Moves the file pointer to a specified location.  int fseek( FILE *stream, long offset, int origin );  Function Required Header Compatibility  fseek <stdio.h> ANSI, Win 95, Win NT    For additional compatibility information, see Compatibility in the Introduction.  Libraries  LIBC.LIB Single thread static library, retail version  LIBCMT.LIB Multithread static library, retail version  MSVCRT.LIB Import library for MSVCRT.DLL, retail version    Return Value  If successful, fseek returns 0. Otherwise, it returns a nonzero value. On devices incapable of seeking, the return value is undefined.  Parameters  stream  Pointer to FILE structure  offset  Number of bytes from origin  origin  Initial position  Remarks  The fseek function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. The next operation on the stream takes place at the new location. On a stream open for update, the next operation can be either a read or a write. The argument origin must be one of the following constants, defined in STDIO.H:  SEEK_CUR  Current position of file pointer  SEEK_END  End of file  SEEK_SET  Beginning of file  You can use fseek to reposition the pointer anywhere in a file. The pointer can also be positioned beyond the end of the file. fseek clears the end-of-file indicator and negates the effect of any prior ungetc calls against stream.  When a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. If no I/O operation has yet occurred on a file opened for appending, the file position is the start of the file.   For streams opened in text mode, fseek has limited use, because carriage return–linefeed translations can cause fseek to produce unexpected results. The only fseek operations guaranteed to work on streams opened in text mode are:   Seeking with an offset of 0 relative to any of the origin values.   Seeking from the beginning of the file with an offset value returned from a call to ftell.  Also in text mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing, fopen and all related routines check for a CTRL+Z at the end of the file and remove 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.   Example  /* FSEEK.C: This program opens the file FSEEK.OUT and  * moves the pointer to the file's beginning.  */  #include <stdio.h>  void main( void ) {    FILE *stream;    char line[81];    int  result;     stream = fopen( "fseek.out", "w+" );    if( stream == NULL )       printf( "The file fseek.out was not opened\n" );    else    {       fprintf( stream, "The fseek begins here: "                        "This is the file 'fseek.out'.\n" );       result = fseek( stream, 23L, SEEK_SET);       if( result )          perror( "Fseek failed" );       else       {          printf( "File pointer is set to middle of first line.\n" );          fgets( line, 80, stream );          printf( "%s", line );        }       fclose( stream );    } }   Output  File pointer is set to middle of first line. This is the file 'fseek.out'.   Stream I/O Routines  See Also   ftell, _lseek, rewind


Question: C语言dll文件，c#调用串口连接总是返回true

返回值 MarshalAs

引用 4 楼 user-2 的回复:[quote=引用 2 楼 shmily_19900314 的回复:] [quote=引用 1 楼 user-2 的回复:] 把dll的头文件贴出来看看 这个没有问题啊，用c进行测试的时候都能够正常运行。 #include "dll.h" #include <iostream>  #include <stdio.h> #include <stdlib.h> #include <string.h> #include "windows.h" #include <tchar.h> using namespace std;[/quote] 你确定使用“纯C”测试的？ 我说的是"dll.h"贴出来看看，是否符合C的接口约定[/quote] extern "C"_declspec(dllexport) int Sum(int x,int y); extern "C"_declspec(dllexport) int Sub(int x,int y); extern "C"_declspec(dllexport) bool TFI_Init(char* iComID); extern "C"_declspec(dllexport) void _sTFI_Exit(); typedef unsigned char uint8; extern "C"_declspec(dllexport) bool TFI_ShowLine(int nLineNo,int order,int style,int brightness,const char* szText); 我刚刚调试了一下，调用这个dll文件是没有问题的，该返回false的时候是返回false的，但是c#调用dll里面这个函数的返回值的时候就变成true了，我实在是搞不懂其中的原因了。。。。

引用 2 楼 shmily_19900314 的回复:[quote=引用 1 楼 user-2 的回复:] 把dll的头文件贴出来看看 这个没有问题啊，用c进行测试的时候都能够正常运行。 #include "dll.h" #include <iostream>  #include <stdio.h> #include <stdlib.h> #include <string.h> #include "windows.h" #include <tchar.h> using namespace std;[/quote] 你确定使用“纯C”测试的？ 我说的是"dll.h"贴出来看看，是否符合C的接口约定

大神快出来帮帮忙啊！！这个小问题困扰一天了。。。。没办法往下进行了都。。。。。

引用 1 楼 user-2 的回复:把dll的头文件贴出来看看 这个没有问题啊，用c进行测试的时候都能够正常运行。 #include "dll.h" #include <iostream>  #include <stdio.h> #include <stdlib.h> #include <string.h> #include "windows.h" #include <tchar.h> using namespace std;

把dll的头文件贴出来看看


Question: 结构体指针赋值问题，麻烦指点

理解正确

看起来-1是指uninitialized状态，真正使用前会有init是吧 @赵4老师 。 单片机内存没用保护模式，所以不用0作nil，这样吧

引用 2 楼 zhao4zhong1 的回复:BUF *dsp_buf_addr=(BUF *)-1;//将-1强制类型转换为BUF *类型后作为BUF*类型变量dsp_buf_addr的初始值。这样赋值结构体指针dsp_buf_addr指向的是什么内容呢？

引用 1 楼 kongl123 的回复:BUF *dsp_buf_addr=(BUF *)-1为什么这么定义和dsp_buf_addr怎么使用有关，你可以看看dsp_buf_addr是怎么用的 (long *)dsp_buf_addr==(long *)-1; 后边又进行了这个判断，看不懂是咋回事

BUF *dsp_buf_addr=(BUF *)-1  上面这句话与下面这句话的作用是相同的  BUF *dsp_buf_addr=0xFFFFFFFF;  因为在指针里-1 就是0xFFFFFFFF;  利用地址表示两种状态，也是可能存在的，一种是未初始化的，还有一种是失败的。 假如我们用NULL，也就是0表示失败的话，那么有人就喜欢用0xFFFFFFFF表示未初始化的。

引用 3 楼 shiyuzuxiaqianli 的回复:[quote=引用 1 楼 kongl123 的回复:] BUF *dsp_buf_addr=(BUF *)-1为什么这么定义和dsp_buf_addr怎么使用有关，你可以看看dsp_buf_addr是怎么用的 (long *)dsp_buf_addr==(long *)-1; 后边又进行了这个判断，看不懂是咋回事[/quote] 判断 将dsp_buf_addr强制类型转换为(long *)类型后的值 和 将-1强制类型转换为(long *)类型后的值 是否相等。  理解和讨论之前请先学会如何观察！  计算机组成原理→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执行停在该断点处的时候。  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。

我个人的理解，最后一句是定义一个指向结构体类型的指针，赋值号右边把-1强制类型转化为结构体指针类型，-1为十进制数，转化为二进制01组合的时候是没有正负的。个人建议，如有不妥，望指正。

就是把 -1 当作 nullptr （NULL） 使用的 因为 地址 0 是个经常会用到的的内存地址， 不能把0 当作 NULL，nullptr 使用

引用 6 楼 zhao4zhong1 的回复:理解正确还是不太懂啊，麻烦解释一下吧。没遇到过这样的情况，上网查资料也没找到


Question: 求大神看看出什么问题了

代码中Data就不是一个类型。写全struct Data，或者typedef一下就可以。还有就是你的代码想干什么。

node *i = (node*)malloc(sizeof(Data));  改成  Data *i = (Data*)malloc(sizeof(Data));

楼主要实现啥？  void Add(node a) { 	struct Data *i = (struct Data*)malloc(sizeof(struct Data)); 	i->data = a; }

node *i，i是一个指向整型的指针，哪有i->data，node *和struct Data *弄混淆了


Question: 关于多个文件的建立，编译

新建一个项目，然后把你的文件添加到项目，然后VS会帮你编译链接

编译链接vs会帮你搞定

逐个添加到项目资源管理器中的源代码文件夹中？


Question: vc++中加filetool.dll加不了

文件类型换一下，就可以找到了。我的找到了但是加载不了，手动注册也出错，直接安装MinGW一样运行c

引用 6 楼 user-4 的回复:你得先把那个dll文件放进AddIns文件夹，到你截图的这个界面时，是你下面的文件类型 选项没有选择Add-ins(.dll)，所以没出现。

引用 8 楼 phoenix06 的回复:换个Visual studio啊，用VC6这种古董做啥。。。一堆兼容问题，还不好用 用WinXP+VC6开发生成的exe程序，放Vista、Win7、Win8、Win10上都立即能用； 反之，令人大失所望！死的心都有！！

或者参考下面： 在64位Windows下： 64位exe和dll在目录c:\windows\system32目录下； 32位exe和dll在目录c:\windows\syswow64目录下； 所以要注意：     在win64位系统下注册32位ocx或dll需要将32位ocx或dll拷贝到c:\windows\syswow64\目录下。     且注册要用c:\windows\syswow64\regsvr32 xxxxxxx.ocx或dll     在win64位系统下设置32位程序使用的数据库别名要用c:\windows\syswow64\cliconfg.exe     在win64位系统下设置32位程序使用的系统DSN要用c:\windows\syswow64\odbcad32.exe

引用 3 楼 qq_35798046 的回复:是64位的，我装的是vc++6.0绿色版，32位虚拟机环境怎么搭建呀？！ 用 HyperV 或 VirtualBox 或 VMWare 在其中加载WinXP 再在里面的WinXP下使用VC6

是64位的，我装的是vc++6.0绿色版，32位虚拟机环境怎么搭建呀？！

确保当前OS是32位的。 如果不是，在32位虚拟机环境下使用VC6.

FileTool.exe 替换打开和添加到项目中 Visual C++ 的新功能 http://support.microsoft.com/kb/241396/zh-cn


Question: 结构体二级指针线性表初始化，程序崩溃

引用 9 楼 paschen 的回复:[quote=引用 8 楼 sinat_30990593 的回复:] [quote=引用 6 楼 qq423399099 的回复:] *PL必须要保证你的PL已经初始化过，这样才能取*（解引用） PS：注意区分和PL1 = Init_SeqList();的区别 那如何改呢，PL赋值为NULL吗？刚实验了也不对呀[/quote]  PseqList  pp =  Init_SeqList(); PL = &pp;[/quote]  谢谢啦，但是总感觉这样重新定义变量很麻烦

引用 8 楼 sinat_30990593 的回复:[quote=引用 6 楼 qq423399099 的回复:] *PL必须要保证你的PL已经初始化过，这样才能取*（解引用） PS：注意区分和PL1 = Init_SeqList();的区别 那如何改呢，PL赋值为NULL吗？刚实验了也不对呀[/quote]  PseqList  pp =  Init_SeqList(); PL = &pp;

引用 6 楼 qq423399099 的回复:*PL必须要保证你的PL已经初始化过，这样才能取*（解引用） PS：注意区分和PL1 = Init_SeqList();的区别 那如何改呢，PL赋值为NULL吗？刚实验了也不对呀

引用 5 楼 sinat_30990593 的回复:我是加入初始化语句  *PL = Init_SeqList(); statu = Merge_SeqList(PL1,PL2,PL); 程序才崩溃的呀  Init_SeqList();不就是初始化程序吗  是要先为指针分配一片内存或者让指针指向一个已有的对象，再去解引指针

因为你的PL没有初始化过，它指向的是未知区域（垃圾值，野指针）。 所以你*PL=XXX尝试向未知区域写入值，就程序崩溃了。

再供参考：//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]

仅供参考：#include <stdio.h> #include <stdlib.h> #include <malloc.h> int **newarr2d(int rows,int cols) {     int **p,i;      p=(int **)malloc(rows*sizeof(int *));     if (NULL==p) exit(1);     for (i=0;i<rows;i++) {         p[i]=(int *)malloc(cols*sizeof(int));         if (NULL==p[i]) exit(1);     }     return p; } void deletearr2d(int **p,int rows) {     int i;      for (i=0;i<rows;i++) {         free(p[i]);     }     free(p); } int main() {     int **arr2d,i,j,r,c;      r=4;     c=5;     //在堆中开辟一个4×5的二维int数组     arr2d=newarr2d(r,c);     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             arr2d[i][j]=i*c+j;         }     }     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             printf(" %2d",arr2d[i][j]);         }         printf("\n");     }     deletearr2d(arr2d,r);      r=6;     c=3;     //在堆中开辟一个6×3的二维int数组     arr2d=newarr2d(r,c);     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             arr2d[i][j]=i*c+j;         }     }     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             printf(" %2d",arr2d[i][j]);         }         printf("\n");     }     deletearr2d(arr2d,r);      return 0; } //  0  1  2  3  4 //  5  6  7  8  9 // 10 11 12 13 14 // 15 16 17 18 19 //  0  1  2 //  3  4  5 //  6  7  8 //  9 10 11 // 12 13 14 // 15 16 17 //

崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处，看不懂时双击下一行，直到能看懂为止。  理解和讨论之前请先学会如何观察！  计算机组成原理→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


Question: 使用C函数库中的幂函数pow()遇到个问题

pow 函数 C 只有 double pow(double ,double ) 1个 另有 powf 用于float,powl 用于 long double C++有四个重载函数 long double pow(long double ,long double) double pow (double ,double) float pow (float,float) long double pow(long double ,int ) //或者 double pow(double ,int)   如果 pow(10,2) 调用 double pow(double,double) 结果是不精确的 如果 调用 pow(double ,int) 结果是精确的 另一种可能是，产生二义性，编译出错。

因为math.h中的pow函数的两个形参是double类型的。如果传入pow(10, 2)则编译器会自动将这两个立即数转换为double类型，但是如果传入pow(10, n)，因为n被声明为整型，所以不会被转换为double类型，从而导致计算误差。在pow(10,n)中的n前面做强制类型转换或许可以解决这个问题，像这样：pow(10, (double)n)

引用 10 楼 qq_35899178 的回复:[quote=引用 3 楼 zhao4zhong1 的回复:] int运算会发生溢出 赵老师，你的那个kg游戏是不是又坏了，win10打开不了啊[/quote] 在64位Windows下： 64位exe和dll在目录c:\windows\system32目录下； 32位exe和dll在目录c:\windows\syswow64目录下； 所以要注意：     在win64位系统下注册32位ocx或dll需要将32位ocx或dll拷贝到c:\windows\syswow64\目录下。     且注册要用c:\windows\syswow64\regsvr32 xxxxxxx.ocx或dll  kg游戏依赖32位的MCI32.OCX，所以如果要在64位的WIn10下顺利运行的话，需要 c:\windows\syswow64\regsvr32 MCI32.OCX

强制转换int有可能导致数据被   引用 13 楼 yayouyayou 的回复:[quote=引用 11 楼 paschen 的回复:] 强制转换int有可能导致数据被截断  浮点数计算是有误差的  如果pow(10,n)计算出的结果是99.99....  转换后就变成了99；如果计算结果是100.00....，转换后就是100 是的，其实比较不明白的地方是为什么直接对这个函数进行强制类型转换是99，而先赋值给一个浮点变量，然后对浮点变量强制类型转换结果就是100。如果说pow(10,n)计算出来的结果是99.99...，那么赋值给一个浮点变量的时候存储的形式不是应该是一样的吗，因为pow（）本身就是返回的double型的变量啊。还有一点，就是（int）pow(10,2),然后赋值给一个int变量，结果输出确实100，这里用一个int型的变量n=2，与直接用常数2即使有区别，不是都会先转换为double变量然后再进行运算的吗，为什么结果会有区别，就是不太明白编译器到底是怎么处理的，表示不理解。[/quote]  那你得看pow的反汇编了

不是说用gdb看看吗，编译器也可能有bug

引用 11 楼 paschen 的回复:强制转换int有可能导致数据被截断  浮点数计算是有误差的  如果pow(10,n)计算出的结果是99.99....  转换后就变成了99；如果计算结果是100.00....，转换后就是100 是的，其实比较不明白的地方是为什么直接对这个函数进行强制类型转换是99，而先赋值给一个浮点变量，然后对浮点变量强制类型转换结果就是100。如果说pow(10,n)计算出来的结果是99.99...，那么赋值给一个浮点变量的时候存储的形式不是应该是一样的吗，因为pow（）本身就是返回的double型的变量啊。还有一点，就是（int）pow(10,2),然后赋值给一个int变量，结果输出确实100，这里用一个int型的变量n=2，与直接用常数2即使有区别，不是都会先转换为double变量然后再进行运算的吗，为什么结果会有区别，就是不太明白编译器到底是怎么处理的，表示不理解。

引用 3 楼 zhao4zhong1 的回复:int运算会发生溢出 赵老师，你的那个kg游戏是不是又坏了，win10打开不了啊

感谢老师赐教了！！！辛苦，辛苦！！！那这里应该是用的这个编译器对返回double类型的函数的转换与转换一个double变量的方式不同，100这个数可能在double实际是99.9999***，直接转换成int就成了99。而一个定义成double变量的数，编译器转换的方式不同，不会出现这种情况，不知道这样理解对不对？

//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); }

浮点数格式 http://bbs.csdn.net/topics/390676437

可是这里的数最大的才200，int类型怎么会溢出呢？

至少高版本gcc没有问题。你用gdb看看代码是怎么翻译的吧。我gcc 4.4和gcc 7.4都没有问题

vs下都是100 100

int运算会发生溢出

C++ Floating-Point Constants Floating-point constants specify values that must have a fractional part. These values contain decimal points (.) and can contain exponents.  Syntax  floating-constant :  fractional-constant exponent-partopt floating-suffixopt digit-sequence exponent-part floating-suffixopt  fractional-constant :  digit-sequenceopt . digit-sequence digit-sequence .  exponent-part :  e signopt digit-sequence E signopt digit-sequence  sign : one of  + –  digit-sequence :  digit digit-sequence digit  floating-suffix :one of  f l F L  Floating-point constants have a “mantissa,” which specifies the value of the number, an “exponent,” which specifies the magnitude of the number, and an optional suffix that specifies the constant’s type. The mantissa is specified as a sequence of digits followed by a period, followed by an optional sequence of digits representing the fractional part of the number. For example:  18.46 38.  The exponent, if present, specifies the magnitude of the number as a power of 10, as shown in the following example:  18.46e0      // 18.46 18.46e1      // 184.6  If an exponent is present, the trailing decimal point is unnecessary in whole numbers such as 18E0.  Floating-point constants default to type double. By using the suffixes f or l (or F or L — the suffix is not case sensitive), the constant can be specified as float or long double, respectively.  Although long double and double have the same representation, they are not the same type. For example, you can have overloaded functions like  void func( double );  and   void func( long double );

常量也有类型！ C++ Integer Constants Integer constants are constant data elements that have no fractional parts or exponents. They always begin with a digit. You can specify integer constants in decimal, octal, or hexadecimal form. They can specify signed or unsigned types and long or short types.  Syntax  integer-constant :  decimal-constant integer-suffixopt octal-constant integer-suffixopt hexadecimal-constant integer-suffixopt 'c-char-sequence'  decimal-constant :  nonzero-digit decimal-constant digit  octal-constant :  0 octal-constant octal-digit  hexadecimal-constant :  0x hexadecimal-digit 0X hexadecimal-digit hexadecimal-constant hexadecimal-digit  nonzero-digit : one of  1 2 3 4 5 6 7 8 9  octal-digit : one of  0 1 2 3 4 5 6 7  hexadecimal-digit : one of  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F  integer-suffix :  unsigned-suffix long-suffixopt long-suffix unsigned-suffixopt  unsigned-suffix : one of  u U  long-suffix : one of  l L  64-bit integer-suffix :  i64  To specify integer constants using octal or hexadecimal notation, use a prefix that denotes the base. To specify an integer constant of a given integral type, use a suffix that denotes the type.  To specify a decimal constant, begin the specification with a nonzero digit. For example:  int i = 157;   // Decimal constant int j = 0198;  // Not a decimal number; erroneous octal constant int k = 0365;  // Leading zero specifies octal constant, not decimal  To specify an octal constant, begin the specification with 0, followed by a sequence of digits in the range 0 through 7. The digits 8 and 9 are errors in specifying an octal constant. For example:  int i = 0377;   // Octal constant int j = 0397;   // Error: 9 is not an octal digit  To specify a hexadecimal constant, begin the specification with 0x or 0X (the case of the “x” does not matter), followed by a sequence of digits in the range 0 through 9 and a (or A) through f (or F). Hexadecimal digits a (or A) through f (or F) represent values in the range 10 through 15. For example:  int i = 0x3fff;   // Hexadecimal constant int j = 0X3FFF;   // Equal to i  To specify an unsigned type, use either the u or U suffix. To specify a long type, use either the l or L suffix. For example:  unsigned uVal = 328u;             // Unsigned value long lVal = 0x7FFFFFL;            // Long value specified                                    //  as hex constant unsigned long ulVal = 0776745ul;  // Unsigned long value


Question: 关于C两个问题，代码图如下

1) 不一定总是4，32位程序指针大小为4，64位程序为8 2） 关键是理清逻辑

1) 不一定是4，只不过在现在的很多机器上是4；得到21是因为碰巧 2) 4步：做什么、怎么做、做出来、做对了吗

32位机上，sizeof(指针)恒为4 因为指针存储的是一个32位的地址，并不是所指向的对象本身

在百度搜“C源代码 学生成绩管理系统”


Question: fopen函数创建文件失败

感谢楼上各位的回复，受教了

引用 5 楼 zhao4zhong1 的回复:_setmaxstdio Sets a maximum for the number of simultaneously open files at the stdio level.   int _setmaxstdio( int newmax );  Routine Required Header Compatibility  _setmaxstdio <stdio.h> Win 95, Win NT    For additional compatibility information, see Compatibility in the Introduction.  Libraries  LIBC.LIB Single thread static library, retail version  LIBCMT.LIB Multithread static library, retail version  MSVCRT.LIB Import library for MSVCRT.DLL, retail version    Return Value  Returns newmax if successful; –1 otherwise.   Parameter  newmax  New maximum for number of simultaneously open files at the stdio level  Remarks  The _setmaxstdio function changes the maximum value for the number of files which may be simultaneously open at the stdio level.   C run-time I/O now supports many more open files on Win32 platforms than in previous versions. Up to 2,048 files may be open simultaneously at the lowio level (that is, opened and accessed by means of the _open, _read, _write, and so forth family of I/O functions). Up to 512 files may be open simultaneously at the stdio level (that is, opened and accessed by means of the fopen, fgetc, fputc, and so forth family of functions). The limit of 512 open files at the stdio level may be increased to a maximum of 2,048 by means of the _setmaxstdio function.  Since stdio level functions, such as fopen, are built on top of the lowio functions, the maximum of 2,048 is a hard upper limit for the number of simultaneously open files accessed through the C run-time library.  Note   This upper limit may be beyond what is supported by a particular Win32 platform and configuration.     Stream I/O Routines 赵老师果然强大

楼主，我建议你用CreateFile函数，WriteFile函数和CloseHandle函数来完成操作。 因为这些是正规的API函数。

引用 2 楼 zjq9931 的回复:因为你创建打开后不关闭，句柄资源被用完后就出错了。  新手还不知道句柄，刚才查了  谢谢~

引用 1 楼 user-4 的回复:检查返回值 及 errno  判断 失败原因  具体看：http://en.cppreference.com/w/c/io/fopen  多谢！

因为你创建打开后不关闭，句柄资源被用完后就出错了。


Question: 为什么内存free两次会使系统崩溃？

引用 7 楼 akirya 的回复:借一次钱，你喜欢还2次啊。 这个比喻亮

引用 8 楼 zhao4zhong1 的回复:为什么我借了张三100万元后还他第二次100万元会使张三进疯人院？  我就是那个张三，你还我，我不会去疯人院的

我也觉得很奇怪，free貌似就是把申请的空间使用权归还给系统，这个跟malloc不一样。malloc会修改内存里面的数据，这个会导致产生问题，但是free不会修改内存对应的数据，就算被别的系统使用了之后也不会修改数据。就好像，malloc是租房子，free是归还房子，我把房子归还了以后，再归还一遍，感觉没有什么问题呀。为什么系统一定会崩溃？

赵老师 还我 我不疯

为什么我借了张三100万元后还他第二次100万元会使张三进疯人院？

借一次钱，你喜欢还2次啊。

实际free做的不只有你代码中的内容

重复释放 则指这样一种场景：程序分配一块内存之后，经过使用将这块内存释放，但并没有将指向这块内存的所有指针抹零或回收，并在其他部分再次将指向同一块内存单元的指针交给内存分配器去进行释放操作。这种情况下，我们可以断言：程序逻辑并不清楚这块内存已经被释放；并且， 有理由相信，对这块内存进行的写操作，可能已经影响了程序其他部分的行为，因为这块内存可能已经分配作为其他用途。 因此，这应被看作立即停止程序运行的一项致命错误，因为程序行为已经出现了异常，而C函数库拥有的信息不足以纠正这种异常行为，而另一方面，程序可能已经发生了堆缓冲区溢出。为了削弱这类问题带来的实质性安全影响，现代的内存分配器往往会将尺寸接近的内存块放在一起（这样做还能够抑制内存碎片的产生，并提高CPU的数据缓存命中率，因为通常程序会倾向于一次性地访问相近的内存结构），从而能够在一定程度上减轻由于向已经释放的内存块继续写数据导致的损害（因为这些内存很可能被分配给同样的数据结构，这类写操作的危害往往会低于向其他类型的数据结构写数据，特别是当这些数据中包含一部分用户输入的时候）。当然，彻底消除这类问题，需要为程序设计语言增加一些新的基础设施（例如强类型、托管内存等）。

这个主要看free的底层实现。free一次后，系统即知道这块内存已经被释放了，可以再此被申请。若是第二次free，系统虽说知道如何首地址，但空间的大小呢。或许底层设计时每个内存块都有过结束符，释放后就会访问到其他内存块的结束符，就可能造成非法读写内存，造成崩溃

free 的实现方法不尽相同  关键在这里，任何一个现成实现的源代码， 都不能说明其他实现的问题 。。。。。。。。。。。。。。。。。。。。。。。。。。。 多数free 实现的时候，要合并相邻内存； 如果内存已经合并了，你再去free 他， 此时他已经是别的内存块的一部分了； 你就会弄乱， 自由内存链表之类的数据结构。 即便本次free 不出问题，以后malloc,free也会出问题。 。。。。。。。。。。。。。。。 但是，free 的任何一个实现，两次 free 会出问题，都说明两次 free 是有问题的。 而有一个或者多个不出问题，不能代表所有的实现，都没有问题。 ///很多未定义，都是类似现象，这个也是未定义吧？。。。。

free两次肯定“应该”出问题，因为系统没办法判断你第二次free这块儿内存是否以及被重新分配了，如果没有，那再释放一次也没啥关系，只是空释放了一次，如果已经被重新分配了，那肯定就不能释放了，就因为系统没办法确定是否又重新分配了，所以就一概报错

首先你不能假设所有的free实现都是这样的，另外一个简单的场景就是你第一次free的内存很可能马上再另外一个地方malloc了。这个是你再次free就有问题了。


Question: 二进制读入，读出失败

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

对了，文件打开的时候"rb",“wb”是“b”不是“d”

验证了你的代码，是可以的。 请确认一下，D:\ss这个目录是不是存在。

推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,ftell,fread,fwrite,fgetc,fclose //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

The character string mode specifies the type of access requested for the file, as follows:  "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.


Question: 怎么用C语言进行串口连接与数据收发啊，封装成dll文件

char s2[]="////.//"; 	char s[2]; 	char s1[5]="COM"; 	itoa(iComID,s,10); 	strcat(s1,s); 	strcat(s2,s1); 	//将char*转为LPCTSTR 	int num = MultiByteToWideChar(0,0,s2,-1,NULL,0); 	wchar_t *wide = new wchar_t[num]; 	MultiByteToWideChar(0,0,s2,-1,wide,num); 	//LPCTSTR s1=_T("COM1"); 	/*LPCTSTR转char* 	wchar_t widestr[1024] = L"wo shi ni yeye"; 	int num = WideCharToMultiByte(CP_OEMCP,NULL,widestr,-1,NULL,0,NULL,FALSE); 	char *pchar = new char[num]; 	WideCharToMultiByte (CP_OEMCP,NULL,widestr,-1,pchar,num,NULL,FALSE);*/ 	m_hCom = CreateFile(wide,           // 定义串口名    #include <tchar.h>  						GENERIC_READ | GENERIC_WRITE,                // 存取模式（读写）  						0,                               // 共享模式：必须设置为0，表示设备独占使用  						NULL,                        // 保密性  						OPEN_EXISTING,      // 必须设置为OPEN_EXISTING打开不是创建  						FILE_FLAG_OVERLAPPED,                // 文件属性，如果是异步模式，可设置为FILE_FLAG_OVERLAPPED  						NULL                         // 模版，串口设备必须设置为NULL  						); 	if (m_hCom == INVALID_HANDLE_VALUE) 	{ 		return false; 	} 	else 	{ 		return true; 	} 我用这个在程序中提示串口被打开了，但是我用串口调试助手却还是能够打开这个串口。奇怪的是，如果我用串口调试助手先打开了这个串口的话，则这个程序是打不开这个串口的。。。。求解答啊，不要沉下去啊，我还会很多问题需要请教的。。。

引用 5 楼 a7716021 的回复:你可以先用带界面的的练习啊， 练完了不让界面显示出来就是了。方便你验证准确性啊 我查了下，界面的话好像是添加了某个串口控件，但是我这个用不到控件。

你可以先用带界面的的练习啊， 练完了不让界面显示出来就是了。方便你验证准确性啊

引用 3 楼 zhao4zhong1 的回复:好象你没有界面（即窗口）的话，不好写回调函数之类的。 有没有别的方法了呀？我觉得应该是有的，可是我现在还没有找到方法，帮帮我 啊

好象你没有界面（即窗口）的话，不好写回调函数之类的。

引用 1 楼 zhao4zhong1 的回复:搜“串口调试助手源代码” 我看了一下，感觉像是要做一个界面，我不需要做界面的，只要能调用就可以了，还是我理解的不对啊？

搜“串口调试助手源代码”


Question: c socket 非阻塞 upd交互问题

引用 2 楼 zhao4zhong1 的回复:如果wireshark不支持本机抓包，试试Socket Sniff谢谢。 先试试不行再来问

如果wireshark不支持本机抓包，试试Socket Sniff

建议楼主先学会使用抓包软件比如wireshark


Question: 请问在C语言中怎么实现泛型?比如java中可以使用ArrayList任意类型，C怎么实现呢，基本类型可以用void*转换，结构类型又怎么知道内部的基本类型呢？

参考Variant的实现。

C本身没有泛型一说，本身就是比较低级的过程语言。 结构类型常见的是传递结构指针时再传递一个size参数，用大小来区分到底传的什么结构体，前提是你能明确掌控所有可能的结构体且不存在大小相同的结构体；另一种是所有结构体内部的首个变量相同，用来区分结构体类型。

也必须提供结构信息，用void*转换

泛型是一种语法糖。 语法糖越甜，编译调试查错越苦！ 把有限的生命浪费在品尝/品鉴无穷多种的语法糖中，我认为不值当。

C++提供了泛型。 vector<int *> abc; abc.push_back(new int);

用C++的STL不好么，兼容C。


Question: 二维数组 简单的复制数组 但输出数字乱码

谢谢 不过 是用%lf  因为我用的是double   不过 你后面是对的 我没发现 粗心了 谢谢

%.1lf  ==> %.1f for (x=0;x<n;n++) ==> for (x=0;x<n;x++)


Question: 关于fork的一个疑问。

http://stackoverflow.com/questions/16078188/why-getppid-from-the-child-return-1 在子进程调用 getppid 时，父进程已经退出了

没有判断fork调用失败，返回-1的情况。


Question: 求解，求TCP connect收包延时

传指针，指向一个类或结构体；或者用全局变量，可以解决访问多个参数的问题


Question: libcurl 获取服务器文件大小

有些会改变的资源确实是不提供长度的，防止你断点下载，例如github的代码压缩包。用迅雷下一下看看能不能获取到大小吧。

服务器没有提供Content-Length，只能等读完了才知道大小

假定一个最大大小比如200MB？

引用 4 楼 zhao4zhong1 的回复:服务器不一定支持。我猜。 应该是服务器没返回content-length 这个字段 但是不知还有什么其他方法能事先知道attachment的大小？

你用浏览器下载..如果浏览器都不能事先获取到大小..那就别浪费时间了...

好久没来了，这论坛 人气变得这么差，这么久了一条回复都没有

服务器不一定支持。我猜。

引用 2 楼 user-5 的回复:curl_easy_getinfo你 查下这个函数吧，里面应该有可以获取content-length首部的值的 返回的头部信息没content-length 这个字段， 无从获取


Question: 数据结构--单链表查找条件

仅供参考：//带表头结点的单向链表 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*q1,*s1,*s2,*s3,*s4,*s; int i,j,k,n,t,m; int main() {     srand(time(NULL));      //填写头节点数据     H.data=-1;     H.next=NULL;     head=&H;      //创建10个节点的单链表     p=head;     for (i=0;i<10;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) return 1;         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         p->next=q;         p=q;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将值为5的结点插入到单链表的第k个结点前     k=3;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) return 1;             q->data=5;             q->next=p->next;             p->next=q;             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //删除第k个节点     k=5;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=p->next;             if (q) {                 p->next=q->next;                 free(q);             }             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //从小到大排序     for (p=head;p!=NULL && p->next!=NULL;p=p->next) {         for (q=p->next;q!=NULL && q->next!=NULL;q=q->next) {             if (p->next->data > q->next->data) {                  //交换data //              printf("swap %02d %02d\n",p->next->data,q->next->data); //              t=p->next->data;p->next->data=q->next->data;q->next->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->next->data,q->next->data);                 s1=p->next;                 s2=p->next->next;                 s3=q->next;                 s4=q->next->next;                  if (s2!=s3) {                      p->next=s3;                     s3->next=s2;                      q->next=s1;                     s1->next=s4;                 } else {                      p->next=s3;                     s3->next=s1;                            q=s3;                     s1->next=s4;                 }                  //输出整个单链表 //              s=head->next; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将整个链表逆序     if (head->next!=NULL && head->next->next!=NULL) {         p=head->next;         q=p->next;         p->next=NULL;         while (1) {             q1=q->next;             q->next=p;             p=q;             q=q1;             if (NULL==q) break;         }         head->next=p;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将单链表中前 m 个结点和后 n 个结点进行互换,m+n为链表总长10     m=4;     n=6;     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m+1==k) {             q=p;         }         s=p;         p=p->next;     }     s1=head->next;     head->next=q->next;     s->next=s1;     q->next=NULL;      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head->next;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //84->28->20->23->96->19->59->97->29->41-> //84->28->05->20->23->96->19->59->97->29->41-> //84->28->05->20->96->19->59->97->29->41-> //05->19->20->28->29->41->59->84->96->97-> //97->96->84->59->41->29->28->20->19->05-> //41->29->28->20->19->05->97->96->84->59-> //

引用 5楼我是你的主体 的回复:[quote=引用 3 楼 qq423399099 的回复:] 大部分情况下其实一样的。 但不同的环境下可能有区别： NULL 只需要保证不是任何有效地址即可，NULL不保证实现为 0 抱歉，我没有太明白。 也就是说其实这两个也可以写成一样的 ？[/quote]可以这样理解

while(p)是判断指针p的值，如果p为0则假，p为非0则真；while(p!=NULL)是判断表达式(p!=NULL)的值，如果p为NULL，则表达式的值为0，即假，p不等于NULL，则表达式的值为1，即真，可以理解为：int a; a=(p!=NULL); while(a);

引用 3 楼 qq423399099 的回复:大部分情况下其实一样的。 但不同的环境下可能有区别： NULL 只需要保证不是任何有效地址即可，NULL不保证实现为 0 抱歉，我没有太明白。 也就是说其实这两个也可以写成一样的 ？


Question: c语言程序，从文本文件中提取由特定字符串开头的行，将提取出的行存储在另外一个文件中，程序大部分已经写好，但是输出部分搞不懂了，求改，求指教

仅供参考：#include <stdio.h> #include <stdlib.h> #include <string.h> #include <io.h> #define MAXFILES 100 char fn[MAXFILES][80]; FILE *f,*fo,*fi; char fno[80],tmp[80]; char ln[1024]; char bk[1024]; int n,i,fs,L,k,st,v; char *p; //char *t; void main() {     system("dir COM3*.log /b >alllog");     f=fopen("alllog","r");     if (NULL==f) {printf("Can not open file:alllog\n");return;}     for (i=0;i<MAXFILES;i++) {         if (NULL==fgets(fn[i],80,f)) break;         L=strlen(fn[i]);         fn[i][L-1]=0;     }     fs=i;     fclose(f);     for (n=0;n<fs;n++) {         strcpy(fno,"WR_");         strcat(fno,fn[n]);         strcat(fno,".txt");         if (!access(fno,0)) continue;         fo=fopen(fno,"w");         if (NULL==fo) {printf("Can not create file:%s\n",fno);return;}         fi=fopen(fn[n],"r");         if (NULL==fi) {printf("Can not open file:%s\n",fn[n]);return;}         st=0;         while (1) {             if (NULL==fgets(ln,1024,fi)) break;//             switch (st) {             case 0:                 if (strstr(ln,"\tIRP_MJ_READ")) {                     fprintf(fo,"%s",ln);                 }                 if (strstr(ln,"\tIRP_MJ_WRITE")) {                     fprintf(fo,"\n%s",ln);                     st=1;                 }             break;             case 1:                 if (strstr(ln,"\tIRP_MJ_READ")) {                     L=strlen(ln);                     ln[L-1]=0;                     if ('\t'==ln[L-2]) ln[L-2]=0;                     if (' '==ln[L-3]) ln[L-3]=0;                     fprintf(fo,"%s",ln);                     st=2;                 }                 if (strstr(ln,"\tIRP_MJ_WRITE")) {                     fprintf(fo,"\n%s",ln);                 }             break;             case 2:                 if (strstr(ln,"\tIRP_MJ_READ")) {                     L=strlen(ln);                     ln[L-1]=0;                     if ('\t'==ln[L-2]) ln[L-2]=0;                     if (' '==ln[L-3]) ln[L-3]=0;                     p=strstr(ln,"Length ");                     sscanf(p+7,"%d",&v);                     if (v>0) {                         sprintf(tmp,"%d",v);                         k=strlen(tmp);                         fprintf(fo,"%s",p+7+k+1);                     }                 }                 if (strstr(ln,"\tIRP_MJ_WRITE")) {                     fprintf(fo,"\n%s",ln);                     st=1;                 }             break;             }          }         fclose(fi);         fclose(fo);     } } //              strcpy(bk,ln); //              t=strtok(bk,"\t"); //              while (t!=NULL) { //                  if (0==strcmp("IRP_MJ_WRITE",t) //                  t=strtok(NULL,"\t"); //              }


Question: 我想写一个c语言程序，从文本文件中提取由特定字符串开头的行，将提取出的行存储在另外一个文件中，输出部分搞不懂了，求改，求大神指教

仅供参考：#include <stdio.h> #include <string.h> #define MAXLEN 1000 FILE *f; char ln[MAXLEN]; char fn[256]; int L; int n; int v1; int v2; void main() {     strcpy(fn,"in.txt");     f=fopen(fn,"r");     if (NULL==f) {         fprintf(stderr,"Can not open file [%s]!\n",fn);         return;     }     n=0;     while (1) {         if (NULL==fgets(ln,MAXLEN,f)) break;         n++;          if (NULL==strstr(ln,"object")) printf("%s",ln);          L=strlen(ln);         if ('\n'==ln[L-1]) {             ln[L-1]=0;         } else {             fprintf(stderr,"Too long(>=%d) at line %d:%s...\n",MAXLEN,n,ln);             break;         }          if (2==sscanf(ln,"%d%*s%d",&v1,&v2)) {             if (1<=v1 && v1<=10              && 1<=v2 && v2<=10) {                 printf("%d,%d\n",v1,v2);             } else {                 fprintf(stderr,"Data(%d,%d) Invalid at line %d:%s\n",v1,v2,n,ln);             }         } else {             fprintf(stderr,"Format error at line %d:%s\n",n,ln);         }     }     fclose(f); }

自己调试下呗！


Question: 求助：报错，P.J.Plauger的C标准库书里面拷贝的测试stdio.h头文件 代码报错

Assertion failed: strcmp(buf, " a|-4 |0010|0XC")== 0, file d:\itcast install pac

%#lX  %#X|   ?

导致出现这样的原因有：     1.非法指针访问和内存泄漏     2.大家再查查吧，一定是指针出现问题了。设置的指针范围跟你运行的不对     3.指针访问内存越界出现问题。     4.是因为不支持中文。     5.内存不够分配     6.当时后来检查发现的问题应该是多线程访问资源出的问题。     7.检查一下exe和dll是否混用的不同版本的crt     解决方法：     第一：检查申请的空间没有释放     第二：检查堆栈空间是否已经被全部分配满，建议每次内存分配尽量不要太大，并且记得释放     第三：指针指向了不可预期的内存位置

点重试、再点中断，然后通过调用堆栈、变量窗口定位与分析原因

仅供参考：#include <stdio.h> char buf[30]; int L; int main() {     L=sprintf(buf, "%2c|%-4d|%.4o|%#lX",'a', -4, 8, 12L);     printf("L:%d,buf:[%s]\n",L,buf);     return 0; } //L:16,buf:[ a|-4  |0010|0XC] //


Question: 新人对斐波那基数列的输出有了点问题

int： -2147483648～2147483647  long long的最大值：9223372036854775807 更大的数可以用数组来存储。

引用 2 楼 qq_34763772 的回复:那int的上限是多少？ http://www.cnblogs.com/xiangshancuizhu/archive/2010/12/12/1903719.html  如果需要表示很大的数，可以用long long

那int的上限是多少？

溢出了 结果超出了变量能表示的范围


Question: 新人报到顺便求教一个基础问题

函数定义与函数声明： http://blog.csdn.net/haiyan0106/article/details/3043998

一个是声明，一个是实现，不过声明的后面还要加上一个分号一个是声明，一个是实现，不过声明的后面还要加上一个分号

C语言教程（附带C语言100例）http://download.csdn.net/detail/zhao4zhong1/8830817

你学的是什么书？我学的时候用的是谭浩强的《C程序设计》，适合初学者学习。先把基础打牢，再向深处扩展。

嗯， 懂了，谢谢你的解答

int leap(int a) 是函数头部加个分号是函数声明。   下面这个是函数定义 包括函数头部，和函数体的语句组。     int leap()             {                 int a;             } 这里有个问题，没写返回语句，又返回值的函数，要写返回语句。   前面一个int a 是函数参数表中的形参声明， 在函数定义时候，声明形参a， 在函数调用时候（定义）初始化形参a（通常是复制一份实参的值）  后面一个int a  是（函数中的）语句组内部定义的变量，属于局部变量定义。 这时候， 没有初始化的变量，内部类型值不确定，类类型， 跟他的 ，构造函数有关。


Question: not found in current context

是否是 linux 环境 gdb调试，如果是检查编译条件是否加了 -g，不要加优化选项

估计你看的时候程序已经执行结束了 在main函数内设置断点，程序停到断点处，观察变量的值


Question: 初学c++的小题

调试一下看看效果

仅供参考： windows里常见的内存填充数据含义 * 0xABABABAB : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory * 0xABADCAFE : A startup to this value to initialize all free memory to catch errant pointers * 0xBAADF00D : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory * 0xBADCAB1E : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger * 0xBEEFCACE : Used by Microsoft .NET as a magic number in resource files * 0xCCCCCCCC : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory * 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory * 0xDEADDEAD : A Microsoft Windows STOP Error code used when the user manually initiates the crash * 0xFDFDFDFD : Used by Microsoft's C++ debugging heap to mark "no man's land" guard bytes before and after allocated heap memory * 0xFEEEFEEE : Used by Microsoft's HeapFree() to mark freed heap memory

第一个问题：do...while先做后判断，while...do先判断后做。判断的条件必须要有初始值，就像3楼和5楼的，i要初始化一个值。 第二个问题：switch(条件) case值1....break  case值2...break。条件不能是变量，还有每种情况做不同的处理，最好加个break。否则当条件满足值1的时候，后面的语句也会被执行。 这两个都是基础问题，还是多看看C语言基础知识吧

Microsoft C++编译器会发生访问冲突，它会把定义但未初始化的值设为0XCDCDCDCD（前提是Debug）

1.i没有初始化的情况下，很多编译器都不会把它初始化成0，而是一个随机值 2.case后面必须跟的是常量

第一个程式 变量 i 不初始化，会是一个随机值，楼主测不到想要的结果

版主大大说的对，对变量初始化，养成良好习惯，第二个 case 后不能是变量  第一个程式过程先执行循环内语句再判断循环条件，直至不满足退出，楼主找个环境单步执行看看就明白。

两个程序都不对  第一个没有对 i 进行初始化  第二个没有对a b 初始化，另外不能写成case (int)x

咦，论坛不能编辑吗？1<=5是笔误

一，相当于： int i=0; int s=0; start_of_do_while: s=s+i; i++; if(1<=5)goto start_of_do_while;  二，你没有编译环境吗？试一试不就知道了？ 没记错的话，switch里面case后面的值不能是变量。


Question: 创建链表的时候有点小问题想不明白！！！请指教

你好有耐心，好厉害啊，我也想画，但是画到一半就越画越不对劲了，然后就更想不明白了

引用 2 楼 上早无叶花的回复:那这样不是每次生成的一个新节点都是跟在head后面了？而不是跟在上一次的节点后面？但是我一样可以输出啊，只不过是反序输出 head 指向 p1 指向null head 指向 p2 再指向 p1 同是小白。

p->link = head->link; p是刚刚malloc出来的结点，让p->link指向head的link结点（即第一个结点），这句实现了将新结点的link指针指向第一个结点  head->link = p; 这句使head的link指针指向新结点p,实现了新节点的插入（头插法）

head为链表的头指针，保持在头部不变。第二次生成一个节点仍旧是放到head的后面，相当于  p2->link=head->link;head->link=p2;

谢谢啦！这么整齐，估计后面的学习还能用到

仅供参考：//带表头结点的单向链表 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*q1,*s1,*s2,*s3,*s4,*s; int i,j,k,n,t,m; int main() {     srand(time(NULL));      //填写头节点数据     H.data=-1;     H.next=NULL;     head=&H;      //创建10个节点的单链表     p=head;     for (i=0;i<10;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) return 1;         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         p->next=q;         p=q;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将值为5的结点插入到单链表的第k个结点前     k=3;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) return 1;             q->data=5;             q->next=p->next;             p->next=q;             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //删除第k个节点     k=5;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=p->next;             if (q) {                 p->next=q->next;                 free(q);             }             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //从小到大排序     for (p=head;p!=NULL && p->next!=NULL;p=p->next) {         for (q=p->next;q!=NULL && q->next!=NULL;q=q->next) {             if (p->next->data > q->next->data) {                  //交换data //              printf("swap %02d %02d\n",p->next->data,q->next->data); //              t=p->next->data;p->next->data=q->next->data;q->next->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->next->data,q->next->data);                 s1=p->next;                 s2=p->next->next;                 s3=q->next;                 s4=q->next->next;                  if (s2!=s3) {                      p->next=s3;                     s3->next=s2;                      q->next=s1;                     s1->next=s4;                 } else {                      p->next=s3;                     s3->next=s1;                            q=s3;                     s1->next=s4;                 }                  //输出整个单链表 //              s=head->next; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将整个链表逆序     if (head->next!=NULL && head->next->next!=NULL) {         p=head->next;         q=p->next;         p->next=NULL;         while (1) {             q1=q->next;             q->next=p;             p=q;             q=q1;             if (NULL==q) break;         }         head->next=p;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将单链表中前 m 个结点和后 n 个结点进行互换,m+n为链表总长10     m=4;     n=6;     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m+1==k) {             q=p;         }         s=p;         p=p->next;     }     s1=head->next;     head->next=q->next;     s->next=s1;     q->next=NULL;      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head->next;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //84->28->20->23->96->19->59->97->29->41-> //84->28->05->20->23->96->19->59->97->29->41-> //84->28->05->20->96->19->59->97->29->41-> //05->19->20->28->29->41->59->84->96->97-> //97->96->84->59->41->29->28->20->19->05-> //41->29->28->20->19->05->97->96->84->59-> //


Question: 关于c语言数组定义问题

定义数组的时候需要是常量，使用数组的时候可以是变量

1）C99 以前，定义数组（元素个数），要用常量表达式。 2）C99级以后 只要是初始化过的变量，都可以。（没初始化的，不论编译通过没有，都是不对的） 注意 仅仅使用变量的当前值定义数组的元素个数是多少， 数组的大小，不是随着变量变化的。 如果变量没初始化，结果就会出问题。  3)读写数组元素，可以用变量作为下标，也可以用常量。

原则上说是使用常量，但是实际上整形的变量也可以通过编译。

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

越界访问，当然就容易出事情了 Ｎ个元素的数组 第N元素（从第０开始算）的位置在数组之外

引用数组元素时[ ]内可以写任何整数类型表达式


Question: 关于C语言代码能不能直接在PB上使用

没用过PB，但是，C的代码肯定是可以在其他编译器上使用的。 就是编译器自带的库的不同会造成代码移植的时候回有不少麻烦。


Question: 关于整数溢出的问题

因为溢出并不是马上变成未知值，就像环一样，最小值的后面又连着最大值，因此溢出之后会回到最大值

只要 char 在 0～127

格式符号，和数据类型要一一对应  %c,int %d,char,short  是没有问题的，可以保证的结果是对的 只要int 在0~127 因为 char 在 0～127  这是因为 printf 参数传递，有个隐形的类型提升 %f 对 float,double 也是可以的，这个其实固然有类型提升在内， 其实标准的奇葩，才是主要的因素。 标准里莫名其妙的取消了对%lf 输出 double 的支持，虽然后来补上了，终归有点怪异。 至于 long long 对应 %lld 如果用 %d 就会发生截断输出的情况。

理解和讨论之前请先学会如何观察！  计算机组成原理→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执行停在该断点处的时候。

int 及比 int 更窄的类型使用 %d 可能不会出错，因为在传递给可变参数列表时进行默认整形提升到 int long 没有出错可能是因为你的环境中 long 和 int 等长 long long 出错是因为 %d 和 long long 不匹配，在解析可变参数列表时无法正确取到对应的值

为什么结果会这样？而且long long类型的打印-1?


Question: 请教一个sscanf匹配的问题

int j, i;      sscanf(buff, ",(\"vlan5\",%d),184544,\"LOCAL\",(\"vlan5\",%d),65535)",&j, &i);      printf("%d %d", j, j);

An asterisk (*) following the percent sign suppresses assignment of the next input field, which is interpreted as a field of the specified type. The field is scanned but not stored.

To read strings not delimited by space characters, a set of characters in brackets ([ ]) can be substituted for the s (string) type character. The corresponding input field is read up to the first character that does not appear in the bracketed character set. If the first character in the set is a caret (^), the effect is reversed: The input field is read up to the first character that does appear in the rest of the character set.  Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]. This is a common scanf function extension, but note that the ANSI standard does not require it.

作为一个C程序员，对  scanf,sscanf,fscanf  printf,sprintf,fprintf 这类函数的用法，还是要做到“拳不离手，曲不离口”的。  #include <stdio.h> char s[]="00:0C:29:08:EB:25\",(\"vlan5\",5),184544,\"LOCAL\",(\"vlan5\",5),65535),"; char mac[18]; int vlan1; char area[10]; int vlan2; int main() {     //我想把前面的mac地址和vlan后面对应的数字及“LOCAL”这个字段提取出来  就是要如下这些     //00:0C:29:08:EB:25   5   LOCAL  5  这4个     if (4!=sscanf(s,"%17[^\"]%*[^,],%*[^,],%d%*[^\"]\"%9[^\"]%*[^,],%*[^,],%d",mac,&vlan1,area,&vlan2)) {         printf("Format Error:[%s]\n",s);         return 1;     } else {         printf("mac:[%s]\n",mac);         printf("vlan1:%d\n",vlan1);         printf("area:[%s]\n",area);         printf("vlan2:%d\n",vlan2);         return 0;     } } //mac:[00:0C:29:08:EB:25] //vlan1:5 //area:[LOCAL] //vlan2:5 //


Question: 请问可不可以写出一个绝对安全的程序或者系统?

引用 12 楼 u010165006 的回复:[quote=引用 11 楼 u010165006 的回复:] [quote=引用 7 楼 yyxgs 的回复:] [quote=引用 4 楼 u010165006 的回复:] 系统的安全性与开放性是一对矛盾，理论上没有绝对安全的系统（好比一个没有门窗的碉堡，这样的碉堡有用吗？） Windows NT计算机系统安全等级属于C2 级，Unix/Linux好像也是。  那其他的呢，比如小型的静态网站，可以做到绝对安全吗?[/quote]  网站是需要Web服务器的，服务器软件和它跑在上面的操作系统可能都有漏洞，可能被攻击，攻击以后修改页面或者删除页面就跟操作本机文件一样的。[/quote]  攻击以后甚至把Web服务器软件进程关闭导致网站无法访问，或者使操作系统功能不正常、关机甚至被破坏（一句命令删光所有文件包括系统本身和网站页面文件，或格式化硬盘）。[/quote]   受教了！

引用 11 楼 u010165006 的回复:[quote=引用 7 楼 yyxgs 的回复:] [quote=引用 4 楼 u010165006 的回复:] 系统的安全性与开放性是一对矛盾，理论上没有绝对安全的系统（好比一个没有门窗的碉堡，这样的碉堡有用吗？） Windows NT计算机系统安全等级属于C2 级，Unix/Linux好像也是。  那其他的呢，比如小型的静态网站，可以做到绝对安全吗?[/quote]  网站是需要Web服务器的，服务器软件和它跑在上面的操作系统可能都有漏洞，可能被攻击，攻击以后修改页面或者删除页面就跟操作本机文件一样的。[/quote]  攻击以后甚至把Web服务器软件进程关闭导致网站无法访问，或者使操作系统功能不正常、关机甚至被破坏（一句命令删光所有文件包括系统本身和网站页面文件，或格式化硬盘）。

引用 7 楼 yyxgs 的回复:[quote=引用 4 楼 u010165006 的回复:] 系统的安全性与开放性是一对矛盾，理论上没有绝对安全的系统（好比一个没有门窗的碉堡，这样的碉堡有用吗？） Windows NT计算机系统安全等级属于C2 级，Unix/Linux好像也是。  那其他的呢，比如小型的静态网站，可以做到绝对安全吗?[/quote]  网站是需要Web服务器的，服务器软件和它跑在上面的操作系统可能都有漏洞，可能被攻击，攻击以后修改页面或者删除页面就跟操作本机文件一样的。

安全到就算停电了，程序还可以再跑...

人妄想超过上帝？！

引用 6 楼 yyxgs的回复:[quote=引用 3 楼 a88770202 的回复:] 感觉其实是相对的，因为你很多时候无法知道什么样的数据会导致你的程序出现bug，数据量很大是原因之一…其他一些原因…你这个程序也没给出那几个自定义函数…实在是无法分析……  也就是说安全性问题都是逻辑设计上的漏洞吗?[/quote] 我觉得很多bug是逻辑上考虑不周…毕竟考虑绝对周到这个感觉很难做到，只是很少人去没事儿触碰那种bug，就像那种小概率事件，可以视作不发生

引用 5 楼 zhao4zhong1 的回复:如果上帝当初创造出来的这个世界是一个绝对安全的程序或者系统的话，能进化出人类吗？   可是生态系统不是人设计的，操作系统是人设计的。。

引用 4 楼 u010165006 的回复:系统的安全性与开放性是一对矛盾，理论上没有绝对安全的系统（好比一个没有门窗的碉堡，这样的碉堡有用吗？） Windows NT计算机系统安全等级属于C2 级，Unix/Linux好像也是。  那其他的呢，比如小型的静态网站，可以做到绝对安全吗?

引用 3 楼 a88770202 的回复:感觉其实是相对的，因为你很多时候无法知道什么样的数据会导致你的程序出现bug，数据量很大是原因之一…其他一些原因…你这个程序也没给出那几个自定义函数…实在是无法分析……  也就是说安全性问题都是逻辑设计上的漏洞吗?

都是初学的时候写的一些函数，当前调试没什么问题，但是写一个稍微大一点程序，各种BUG出现了。。有点感叹大型程序或操作系统这样的工程，能写一个绝对安全的出来是不是特别艰难。。。


Question: 关于C中二级指针传参

如果要在函数中修改指针的值，需要传入一个二级指针，这样才能在函数中修改指针的值，否则传入的变量是按值传递的，也就是复制进去的，你在函数中修改一个复制后的指针是没什么用的  你程序中的L是一个二级指针，修改时直接*L = ... 即可修改到

引用 3 楼 qq423399099 的回复:因为你要在函数内修改指针的指向，所以必须传一级指针的引用或者二级指针。 L是指针本身在栈上的地址，而*L才是指针所指向的区域的地址 所以写成： *L=(Linklist)malloc(sizeof(Lnode));  是否可以如此简单化理解：   void change(int **p);  void main() { 	int c=1; 	int *a ; 	a=&c; 	change(&a); 	printf("%d",*a); }  void change(int **p) { 	**p=(int)malloc(sizeof(int)); }   1、这段里面，按照我正常的理解的话，内存分配结束的话，p存储的值应该改变了，这个时候我想的是因为p存的是a自身的地址，所以等价于a自身的地址改变了；而实际调试中发现，a自身以及它存储的值都没有变。好奇怪，有什么通俗的解释吗？

理解和讨论之前请先学会如何观察！  计算机组成原理→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


Question: 程序求解

cmp返回的是a和b mark的差值正或负，qsort 是快速排序。

cmp函数返回，当标记名字相同，返回年龄段差，当标记相同名字不同，返回前一个名字是否长于后一个的名字，当标记不同则当天标记差。 qsort()是标准库里的快排函数，有四个参数，第一个参数是数组名，第二个参数是要比较的数组元素个数，第三个参数是每个数组元素大小，第四个参数就是比较规则。比较规则是要自己定义的，就像你写的cmp函数，

比较 和 排序

qsort是排序的，属于标准库的函数。你可以去百度了解一下。cmp 就是比较的方式

qsort是自带的快速排序函数 cmp是比较规则 先比较mark，如果mark相同，就比较name，如果name相同，]就比较年龄。

VS IDE中，在不明白的符号上点鼠标右键，选转到定义。


Question: 求指导一下ubuntu代理设置问题

我也不懂帮顶

不懂帮顶


Question: 谁能帮我看看这段递归代码为什么错误，调试好多遍了

引用 9 楼 FFY_1208 的回复:你这个是C语言，循环里不可以加定义的.主函数里的实参数量比你设置的形参数量多 疏忽了

引用 2 楼 paschen 的回复:你代码没帮你调试，初步看了下  loop5 不是只有4个参数，为何主函数中调用时有5个参数  其次是提示什么错误，检查是否递归太深导致栈溢出  我居然没发现 疏忽了

引用 8 楼 ilikehigame 的回复:#define N 10  void show(int(*a)[N]) { 	for (int i = 0; i < N; i++) 	{ 		for (int j = 0; j < N; j++) 		{ 			printf("%7d", a[i][j]); 		} 		printf("\n"); 	} }  void loop5(int(*a)[N], int i, int j, int k) { 	static max = 0; 	static temp = 1; 	if (k>=(N+1)/2) 	{ 		return; 	} 	else 	{ 		if (j < N - k)   		{ 			a[i][j++] = temp++; 			max=1; 			loop5(a, i, j, k);	 		} 		if (max == 1) 		{ 			j--; 			i++; 		} 		 		if (i < N - k)    		{ 			a[i++][j] = temp++; 			max = 2; 			loop5(a, i, j, k); 		} 		if (max == 2) 		{ 			i--; 			j--; 			max = 0; 		}	 		loop5(a, i, j, k + 1); 	} 	 }   void main() { 	int a[N][N] = { 0 }; 	show(a); 	loop5(a, 0, 0, 0); 	show(a); 	system("pause"); }    这是原来的  我是想把他改成递归（新手 递归太差 所以想锻炼锻炼） void loop2(int(*a)[N])//while 循环 { 	int temp = 1; 	//i控制行，j控制列，k控制循环次数  算法：(N+1)/2 得到循环次数 	int i = 0, j = 0, k = 0; 	 	while (k < (N + 1) / 2) 	{ 		while (j < N - k)//左往右 		{ 			a[i][j++] = temp++; 		} 		j--; 		i++; 		while (i < N - k)//右往下 		{ 			a[i++][j] = temp++; 		} 		j--; 		i--; 		while (j >= k)//下往左 		{ 			a[i][j--] = temp++; 		} 		j++; 		i--; 		while (i > k)//左往上 		{ 			a[i--][j] = temp++; 		} 		i++; 		j++; 		k++; 	} 	show(a); }

你这个是C语言，循环里不可以加定义的.主函数里的实参数量比你设置的形参数量多

你的提示错误是什么？我初步看了一下，感觉你的递归有点错误，你的递归终止条件是什么？是k么？可是你的k的值没变啊。

http://www.codeproject.com/Articles/418776/How-to-replace-recursive-functions-using-stack-and 风格就是一种笔格！

你这个递归函数要干嘛？ 1     2    3    4       5       6      7    8      9 18  17 ·····································10 ················ 这样的数列？

引用 楼主 libinden71 的回复:#define N 10  void show(int(*a)[N]) { 	for (int i = 0; i < N; i++) 	{ 		for (int j = 0; j < N; j++) 		{ 			printf("%3d", a[i][j]); 		} 		printf("\n"); 	} }  void loop5(int(*a)[N], int i, int j, int k) { 	static max = 0; 	static temp = 1; 	if (k>=(N+1)/2) 	{ 		return; 	} 	else 	{ 		if (j < N - k)   		{ 			a[i][j++] = temp++;                          max=1; 			return  loop5(a, i, j, k);		 		} 		if (max == 1) 		{ 			j--; 			i++; 		}  		if (i < N - k)    		{ 			a[i++][j] = temp++; 			max = 2; 			return loop5(a, i, j, k); 		} 		if (max == 2) 		{ 			i--; 			j--; 			max = 0; 		}  //		if (j >= k) //		{ //			a[i][j] = temp++; //			max = 3; //			return loop5(a, i, j - 1, k); //		} //		if (max == 3) //		{ //			j++; //			i--; //			max = 0; //		} // // //		if (i > k) //		{ //			a[i][j] = temp++; //			max = 4; //			return loop5(a, i - 1, j, k); //		} //		if (max == 4) //		{ //			i++; //			j++; //			max = 0; //		} 		return loop5(a, i, j, k + 1); 	} 	 }  void main() { 	int a[N][N] = { 0 }; 	loop5(a, 0, 0, 0, 0); 	show(a); 	system("pause"); }  里面的4段递归，前面2段 显示是正确，后面这2段 不知道为什么一起运行就错误，求大神帮忙看看 哪里错了？还是说整个递归本来就有问题 只是我没发现？  loop5 的函数没有定义返回值但是过程总有return loop5

引用 1 楼 qq423399099 的回复:单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。 “给定一个小点的输入，完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门！ 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出  赵老师的风格


Question: 求大神指点应该怎样改进；

对角线 包括 正对角线 和 反对角线 正对角线 满足条件  i == j 反对角线 满足条件 i+j == 3-1  非对角线上元素之和  if(i != j && i+j != 2) {    sum = sum + a[i][j];	 }

楼上已经说得很清楚了。


Question: OJ求解

还是多谢你啦，这个问题我解决了。已经结贴了

边界条件 输入输出格式 ……

首先感谢一楼，你看得很仔细，我认为平时生活中不会出现一个人在一个楼层电梯，然后又按这个楼层的电梯这种情况，但是题目却要求包含这种情况，导致我一直不能AC，运行出错。参考了别人的好多能用的代码，解法有些区别，却一直看不出自己错在哪。现在终于明白了，多谢。 其次感谢二楼，我也调试了很多次，只是在测试用例上，我受个人思维约束，就这道题，有一种情况一直想不到，因此不知道在代码何处修改。不过你强调的调试方法，我会谨记的，十分感谢。

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

我来解释一波，第一种情况，楼主没有考虑，when elevator in the same level continuous test case as  4  1 2 2 3,通不过 我给你改了一下代码 楼主，记得结贴给分，我也是被迫的，有时候给别人调个程序，解答了他的问题，就没见了 我们辛辛苦苦回答问题，啥也没得到； #include <iostream> using namespace std;    int main(int argc, char *argv[]) {  //agrc 和 argv 可以不写，当你要用命令行参数的时候写     int temp=0;     while(cin>>temp)     {         if(temp!=0)         {             int before=0,rear=0,sum=0;             for(int i=0;i<temp;i++)             {                 cin>>rear;                 if(before<rear)                 {                     sum=sum + (rear-before)*6+5;                 }                 else  //把if删了                 {                     sum= sum + (before-rear)*4+5; // 把before = rear 的那种情况加进去了                 }                 //sum+=5;                 before=rear;             }             cout<<sum<<endl;         }         else             break;     }           return 0; }


Question: c语言写的文件传输为什么发送到服务端内容是空的

请问如何解决的，谢谢

已经解决啦谢谢各位

调试任何通信系统，都要先会用对应的抓包工具。我觉得。

建议先确认服务端是否真的接收到客户端发送的信息，然后尝试用fflush函数在每次写文件后刷下。

抓包，调试。。。

有时不将“调用函数名字＋各参数值，进入函数后各参数值，中间变量值，退出函数前准备返回的值，返回函数到调用处后函数名字＋各参数值＋返回值”这些信息写日志到文件中是无论如何也发现不了问题在哪里的，包括捕获各种异常、写日志到屏幕、单步或设断点或生成core文件、……这些方法都不行！ 写日志到文件参考下面： //循环向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; }  任何收发两端速度不一致的通讯，都需要在它们之间使用一个足够大的FIFO缓冲区。 对任何FIFO缓冲区的使用，都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已满这两种情况下该如何做。 这些概念都在这段经典代码中有所体现。 这段经典代码还包括以下必须考虑的因素： ◆跨Windows和Linux平台 ◆多线程锁 ◆多线程日志 ◆日志文件占用的磁盘空间可控 ◆日志中的时间包括毫秒 ◆传输的数据对应的每个字节到底是几 ◆如何退出多线程程序 ◆……


Question: 新人求教一个c语言的简单问题

lf 的l应该是小写，改过来就对了。这些细微的错误，平时一定要小心，养成一个好的编程习惯很重要。平时这些错误还是要先自己查找。

是%lf  是小写L  http://en.cppreference.com/w/c/io/fprintf

给我给我一双慧眼吧，让我把这“I1l|│”看得清清楚楚明明白白，……

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

那个应该是小写的L，你写成大写的i了  #include <stdio.h> #include <stdlib.h>  /* run this program using the console pauser or add your own getch, system("pause") or input loop */  int main(int argc, char *argv[]) { 	double d; 	d = 8.0; 	printf("d is %lf", d); 	return 0; }

float、double要用%f，long double用%lf

double类型的输出是用%lf，按照提供的代码应该没有问题。 测试用的什么环境呢？


Question: 关于多进程并发TCP套接字服务器（C语言）的一些困惑，求助

fork 写时拷贝 close会减少一个引用计数 写时拷贝：linux中不强调线程  fork出来的子进程会共享父进程的东西仅仅供读  如果是内核对象那么就是引用计数+1 非内核对象，比如：int i=1;  子进程也是i也是1，如果子进程赋值i=2 不会影响父进程的值

解决了就给分吧,,嘿嘿,凑个热闹

引用 7 楼 pengzhixi的回复:额 如果父进程没有设置FD_CLOEXEC那么意味着子进程会继承父进程的描述符。 也就意味着描述符对应的底层结构的引用计数会是2.这就是说你需要在父子进程都关闭相应描述符才会真正释放底层的结构。这也就解释了为什么关闭父进程或者子进程的描述符不会影响对方使用该描述符。 我现在懂了，file结构体中，有个记录引用次数的成员，当数目捡到零时就释放内存中打开文件所对应的资源。 谢谢回答

一个朋友针对我的问题推荐给我的文章，觉得写的不错，我把它发在这里供有同样问题的朋友学习， http://m.blog.csdn.net/article/details?id=9162453  题目：linux系统文件描述符file descriptor与inode的相关知识

引用 3 楼 zhao4zhong1 的回复:了解一下操作系统的相关概念。  好，谢谢提醒

了解一下操作系统的相关概念。

引用 3 楼 zhao4zhong1 的回复:了解一下操作系统的相关概念。还有tcp协议的知识

引用 1 楼 user-6的回复:子进程只是复制父进城的东西，fork之后子进程内部实现与父进城内部实现没关系。他们共享文件描述符表。子进程关闭连接文件描述浮表。只是把这个链接地址的引用计数减一。《表述不好，看不懂全当我放屁了》 请再多说一点吧，父子进程共享文件描述符表是什么意思，谢谢


将错误信息中出现的标识符放在百度里面搜一下，看其在哪个.lib中，然后在本地硬盘上搜索该.lib,如果没有，在网上搜索相关库或模块下载安装，然后将其所在目录填写到“附加依赖库所在目录”中，将其名字添加到“附加依赖库”中，重新连接。 VC6： 工程、设置、C/C++、分类：Preprocessor、附加包含路径：填写附加头文件所在目录 逗号间隔多项 工程、设置、Link、分类：Input、附加库路径：填写附加依赖库所在目录 分号间隔多项 工程、设置、Link、分类：Input、对象/库模块：填写附加依赖库的名字.lib 空格间隔多项 VS20xx： 项目、属性、C/C++、附加包含目录：填写附加头文件所在目录 分号间隔多项 项目、属性、链接器、常规、附加库目录：填写附加依赖库所在目录 分号间隔多项 项目、属性、链接器、输入、附加依赖项：填写附加依赖库的名字.lib 空格或分号间隔多项

#include <iphlpapi.h> // 需要头文件 #include <icmpapi.h> //需要头文件  #pragma comment( lib, "Iphlpapi.lib" )///再加上这一行VC缺省，并不把 这个库连接到文件中   因为库没有链接进来，函数所以就没定义了   Requirements Client  Requires Windows Vista, Windows XP, or Windows 2000 Professional.   Server  Requires Windows Server 2008, Windows Server 2003, or Windows 2000 Server.  Header  Declared in Icmpapi.h.  Library  Use Iphlpapi.lib.//注意这里  DLL  Requires Iphlpapi.dll on Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP. Requires Icmp.dll on Windows 2000 Server and Windows 2000 Professional.

哦。发现 MSDN示例  #include <iphlpapi.h> //  #include <icmpapi.h> //  HANDLE hIcmpFile;  hIcmpFile = IcmpCreateFile(); if (hIcmpFile == INVALID_HANDLE_VALUE) {   printf("\tUnable to open handle.\n");   printf("IcmpCreatefile returned error: %ld\n", GetLastError() ); } else   printf("\tHandle created.\n");

目测。库文件没有找到 这几个函数是在在某个DLL中实现的 并且不是VC和Windows 的。  。。。。。 另外一种可能，自己做的。或者引用的源代码文件已经有了（下载了） 但是没有编译，或者出现二义性，编译出错


Question: 大家好，有C语言试题不理解，请大家指正，，

打开一个二进制文件fp=fopen("root.txt","wb"); fp=fopen("root.txt" ,"w");是打开一个文本文件

#include <stdio.h> #include <math.h> # include <stdio.h> using namespace std; int main(void) {     double c;     int b;    char ch = ‘\n’;     FILE *fp;     fp=fopen("root.txt" ,"w");     for(b=1;b<=100;b++)     {         c=sqrt((double)b);         fprintf(fp,"%lf ",c);         fwrite (ch , 1, 1, fp);     }     fclose(fp); }    结果： 1.000000  1.414214  1.732051  2.000000  2.236068  2.449490  2.645751  2.828427  3.000000  3.162278  3.316625  3.464102  3.605551  3.741657  3.872983  4.000000  4.123106  4.242641  4.358899  4.472136  4.582576  4.690416  4.795832  4.898979  5.000000  5.099020  5.196152  5.291503  5.385165  5.477226  5.567764  5.656854  5.744563  5.830952  5.916080  6.000000  6.082763  6.164414  6.244998  6.324555  6.403124  6.480741  6.557439  6.633250  6.708204  6.782330  6.855655  6.928203  7.000000  7.071068  7.141428  7.211103  7.280110  7.348469  7.416198  7.483315  7.549834  7.615773  7.681146  7.745967  7.810250  7.874008  7.937254  8.000000  8.062258  8.124038  8.185353  8.246211  8.306624  8.366600  8.426150  8.485281  8.544004  8.602325  8.660254  8.717798  8.774964  8.831761  8.888194  8.944272  9.000000  9.055385  9.110434  9.165151  9.219544  9.273618  9.327379  9.380832  9.433981  9.486833  9.539392  9.591663  9.643651  9.695360  9.746794  9.797959  9.848858  9.899495  9.949874  10.000000

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

太谢谢了！！！

另外你这样只存了最后一个数的平方根，如果要每个数都存这样改：   #include <stdio.h> #include <math.h> #include <stdlib.h> int main(void) { 	double c; 	int b; 	FILE *fp; 	fp=fopen("root.txt" ,"w"); 	for(b=1;b<=100;b++) 	{ 		c=sqrt(b); 		fprintf(fp,"%lf ",c); 	} 	fclose(fp); }

fprintf(fp,"%lf ","c"); 改成 fprintf(fp,"%lf ",c);  去年c的双引号

fprintf(fp,"%lf ","c");  象这个语句，编译器肯定会提示错误，根据编译器提示的错误信息就可以查到一些低级的语法错误了。  记下来的功能，单步运行一下你就会发现，最终保存下来的只有sqrt(100)这一个结果。  归根到底，把代码动手输入电脑就好了。

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


Question: 关于回调函数机制

仅供参考：#pragma comment(lib,"user32") #include <stdio.h> #include <time.h> #include <sys/timeb.h> #include <windows.h> char datestr[16]; char timestr[16]; char mss[4]; void log(char *s) {     struct tm *now;     struct timeb tb;      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,s); } VOID CALLBACK myTimerProc1(   HWND hwnd, // handle of window for timer messages   UINT uMsg, // WM_TIMER message   UINT idEvent, // timer identifier   DWORD dwTime // current system time ) {  log("In myTimerProc1\n"); } VOID CALLBACK myTimerProc2(   HWND hwnd, // handle of window for timer messages   UINT uMsg, // WM_TIMER message   UINT idEvent, // timer identifier   DWORD dwTime // current system time ) {  log("In myTimerProc2\n"); } int main() {     int i;     MSG msg;      SetTimer(NULL,0,1000,myTimerProc1);     SetTimer(NULL,0,2000,myTimerProc2);     for (i=0;i<20;i++) {         Sleep(500);         log("In main\n");         if (GetMessage(&msg,NULL,0,0)) {             TranslateMessage(&msg);             DispatchMessage(&msg);         }      }     return 0; } //2012-07-26 17:29:06.375 In main //2012-07-26 17:29:06.875 In myTimerProc1 //2012-07-26 17:29:07.375 In main //2012-07-26 17:29:07.875 In myTimerProc2 //2012-07-26 17:29:08.375 In main //2012-07-26 17:29:08.375 In myTimerProc1 //2012-07-26 17:29:08.875 In main //2012-07-26 17:29:08.875 In myTimerProc1 //2012-07-26 17:29:09.375 In main //2012-07-26 17:29:09.890 In myTimerProc2 //2012-07-26 17:29:10.390 In main //2012-07-26 17:29:10.390 In myTimerProc1 //2012-07-26 17:29:10.890 In main //2012-07-26 17:29:10.890 In myTimerProc1 //2012-07-26 17:29:11.390 In main //2012-07-26 17:29:11.890 In myTimerProc2 //2012-07-26 17:29:12.390 In main //2012-07-26 17:29:12.390 In myTimerProc1 //2012-07-26 17:29:12.890 In main //2012-07-26 17:29:12.890 In myTimerProc1 //2012-07-26 17:29:13.390 In main //2012-07-26 17:29:13.890 In myTimerProc2 //2012-07-26 17:29:14.390 In main //2012-07-26 17:29:14.390 In myTimerProc1 //2012-07-26 17:29:14.890 In main //2012-07-26 17:29:14.890 In myTimerProc1 //2012-07-26 17:29:15.390 In main //2012-07-26 17:29:15.890 In myTimerProc2 //2012-07-26 17:29:16.390 In main //2012-07-26 17:29:16.390 In myTimerProc1 //2012-07-26 17:29:16.890 In main //2012-07-26 17:29:16.890 In myTimerProc1 //2012-07-26 17:29:17.390 In main //2012-07-26 17:29:17.890 In myTimerProc2 //2012-07-26 17:29:18.390 In main //2012-07-26 17:29:18.390 In myTimerProc1 //2012-07-26 17:29:18.890 In main //2012-07-26 17:29:18.890 In myTimerProc1 //2012-07-26 17:29:19.390 In main //2012-07-26 17:29:19.890 In myTimerProc2

二楼:我想问回调函数首先我得注册然后才能调用，注册其实就是将回调函数的地址给到结构体中，最后操作这个结构体来调用回调函数，你怎么传引用？

每个学习C，C++语言程序的人 都写过回调函数 因为main 函数，就是回调函数

回调函数的调用方式有两种常用方式 第一种是注册回调函数 第二种设计一个函数，专门调用回调函数 你这是其中一种 类似Windows 窗口过程 第二种，例如枚举类函数 EnumWindows ，专门用来 调用回调函数WNDENUMPROC类型函数的   EnumWindowsProc 的  C 标准库的 qsort，会调用 回调函数 int cmp( const void *a ,const void *b) 这种比较函数的  只是 标准库，并没有把它称为回调函数  Windows 操作系统，则把这一类函数，明确的称为回调函数  也许还有其他方法 不过这两种是经常用到的  Windows 启动线程的API也需要一个回调函数 就是我们经常说的线程函数，或者 线程过程  驱动程序里，也经常用到回调函数  回调函数，就是约定好调用格式的函数 你的函数参数，返回值类型 都是约定好的。一定会这么调用的  其实，我们最经常使用的main 函数，就是C,C++ 标准库 启动程序时候，会调用的回调函数 回调函数，不是很神秘的。

Windows系统：“不要调用我，请先填写好未来收到某个消息时你的处理流程，在那个消息到来时我会调用你！”

RegisterCB_Func 的第一个参数是传值调用，改成传引用


Question: 编程在一个已知的字符串中查找最长单词，假定字符串中只含字母和空格，空格用来分隔不同单词

可以了，确实要加括号，谢谢了

改成while ( c = getchar( ) && c != '\n') 试一下

我只能告诉你，C语言中的赋值运算符的优先级特别低。。。

while( ( c = getchar() ) != '\n' )  运算符优先级的问题，逻辑运算符优先级高，导致c的值其实是判断不等于后的结果