Question: 关于用堆栈实现四则运算的问题

同意一楼跟三楼所说的，我也用C++（虽然你用的是C）写过一个用栈实现的计算器，我的做法是一开始输入的是字符串，然后我把字符串用 atof 函数转换为数字进行运算的。后来我就自己写了一个函数来把字符串转换为数字。你可以看看我的博客，应该有所启发的 栈实现计算器：http://blog.csdn.net/redrnt/article/details/65485202 将字符串转换为数字：http://blog.csdn.net/redrnt/article/details/70158010

需要重新定义栈的结构，因为超过10之后，一个数字就不是一个字符了

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

上面的程序支持的是10以内的运算，你的程序只是改了main函数，而没有修改对应的操作，push的第二个参数是一个字符，类似'1', '2'，而你要传入的是一个个值，比如5, 15等等。很明显，目前的栈操作不支持。 建议，将栈的操作有char类型，转成int类型，栈元素也用int类型。

#include <stdio.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <string.h>   #define STACK_INIT_SIZE 100 #define STACKINCRENMENT 10  #define ERROR 0 #define OK 1  typedef double SElemType; typedef int Status;  char a[][7]={     {'>','>','<','<','<','>','>'},     {'>','>','<','<','<','>','>'},     {'>','>','>','>','<','>','>'},     {'>','>','>','>','<','>','>'},     {'<','<','<','<','<','=',' '},     {'>','>','>','>',' ','>','>'},     {'<','<','<','<','<',' ','='} };  char OP[7]={'+','-','*','/','(',')','#'};  typedef struct{     SElemType *base;     SElemType *top;     int stacksize; }SqStack;  Status InitStack(SqStack *S) {     S->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));     if(!S->base)         exit(ERROR);     S->top = S->base;     S->stacksize = STACK_INIT_SIZE;      return OK; }   Status Push(SqStack *S, SElemType e) {     if(S->top - S->base >= S->stacksize) {         S->base = (SElemType *)realloc(S->base,                 (S->stacksize + STACKINCRENMENT) * sizeof(SElemType));         if(!S->base)             exit(ERROR);         S->top = S->base + S->stacksize;         S->stacksize += STACKINCRENMENT;     }     *(S->top++) = e;      return OK; }  Status Pop(SqStack *S, SElemType *e) {     if(S->top == S->base)         return ERROR;      *e = *(S->top - 1);     S->top--;      return OK; }  Status GetTop(SqStack S) {     if(S.top == S.base)         return ERROR;     return *(S.top - 1); }  Status EmptyStack(SqStack S) {     if(S.top == S.base)         return OK;     else         return ERROR; }  Status Priority(int c1, int c2) {     int i,j;      switch(c1) {         case'+':             i = 0;             break;         case'-':             i = 1;             break;         case'*':             i = 2;             break;         case'/':             i = 3;             break;         case'(':             i = 4;             break;         case')':             i = 5;             break;         case'#':             i = 6;             break;     }     switch(c2)     {         case'+':             j = 0;             break;         case'-':             j = 1;             break;         case'*':             j = 2;             break;         case'/':             j=3;             break;         case'(':             j=4;             break;         case')':             j=5;             break;         case'#':             j=6;             break;     }      return a[i][j]; }  Status JudgeC(char c, char OP[]) {     int i,flag=0;     for(i=0;i<7;i++){         if(c == OP[i]){             flag=1;             break;         }     }     if(flag == 0)         return 0;     else         return 1; }  SElemType Calculate(SElemType a, char y, SElemType b) {     SElemType result;      switch(y) {         case'+':             result = a + b * 1.0;             break;         case'-':             result = a - b * 1.0;             break;         case'*':             result = a * b * 1.0;             break;         case'/':             result = a * 1.0 / b;             break;     }     //printf("a = %.2lf, b = %.2lf, result = %.lf\n", a, b, result);      return result; }  #define MAX_SIZE    32  int main() {     int num = 0;     SElemType a, b, d, x, y;     char* str = (char*)malloc(MAX_SIZE*sizeof(char));      SqStack OPTR;     SqStack OPND;     InitStack(&OPND);     InitStack(&OPTR);     Push(&OPTR,'#');     printf("请输入表达式:\n");     fgets(str, MAX_SIZE, stdin);     puts(str);     while(*str != '#' || GetTop(OPTR)!='#'){         if(*str>='0' && *str<='9'){             num = 0;             do{                 num = num * 10 + (*str - '0');                 str++;             } while(*str >= '0' && *str <= '9');             Push(&OPND, num);         }         else {             switch(Priority((int)GetTop(OPTR), *str)) {                 case'<':                     Push(&OPTR, *str);                     str++;                     break;                 case'=':                     Pop(&OPTR, &x);                     break;                 case'>':                     Pop(&OPND, &b);                     Pop(&OPTR, &y);                     Pop(&OPND, &a);                     Push(&OPND, Calculate(a, y, b));                     break;                  case ' ':                     str++;                     break;             }         }     }     d = GetTop(OPND);     printf("result = %.2lf\n", d);      return 0; }  在这个基础上继续优化吧， 这个程序是修改你的部分，但是对于多个括号嵌套还是有问题，希望你继续修改一下。


Question: 关于stc可仿真芯片用keil debug调试

引用 1楼赵4老师 的回复:有源代码改源代码，没源代码改设置，改不了设置加ahk脚本，加ahk脚本无效就Hook，Hook不了就Crack，…… ahk脚本参考http://www.autohotkey.com……不懂你说的啊


Question: Visual Studio 2017编译可以运行的程序在运行过程中出现停止工作

贴这么长代码给谁看呢？你自己就不能定位一下问题？这么多代码全都是有问题的？？  而且你都不知道调试一下吗？

贴这么长代码给谁看呢？你自己就不能定一下问题？这么多代码全都是有问题的？？

崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处，看不懂时双击下一行，直到能看懂为止。

void chatting_client(SOCKET sc) { 	system("cls"); 	system("color 0a"); 	int receiveLength; 	char SMess[1000];			//发送消息的缓存 	char RMess[1000];			//接收消息的缓存 	char SName[200];			//服务端用户的姓名 	char CName[200];			//客户端用户的姓名 	int nResult;  	nResult = recv(sc, RMess, strlen(RMess), 0);     //确认文件传送模块连接成功 	if (nResult == -1)           //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return; 	} 	printf("%s\n", RMess);  	printf("请输入你的名字：");      //客户端用户的姓名 	gets_s(CName);  	while (strlen(CName) == 0) 	{ 		printf("用户名不能为空! 请输入你的名字：\n"); 		gets_s(CName); 	}  	send(sc, CName, strlen(CName) + 1, 0);   //向服务端发送姓名 	receiveLength = recv(sc, SName, 200, 0); //接收服务端用户的姓名 	if (receiveLength == -1)                //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return; 	} 	printf("你已和%s取的连接……\n", SName); 	printf("开始聊天(输入exit退出聊天程序)……\n");  	while (1) 	{ 		struct tm *local; 		time_t t;						//调用时间函数，显示用户的操作时间 		t = time(NULL); 		local = localtime(&t); 		nResult = recv(sc, RMess, M, 0);		 //接收服务端发送过来的消息 		if (nResult == -1)                //判断服务端是否关闭 		{ 			printf("\n服务端已断开\n"); 			system("pause"); 			return; 		}  		if (strcmp(RMess, "exit") == 0) 		{ 			printf("服务端已退出聊天程序,本程序也即将退出!\n"); 			system("pause"); 			break; 		} 		printf("%s\t%d:%d:%d  \n    %s\n", SName, local->tm_hour, local->tm_min, local->tm_sec, RMess);  		printf("\n请输入信息：");      //客户端用户输入消息 		gets_s(SMess); 		if (strcmp(SMess, "exit") == 0) 		{ 			send(sc, SMess, strlen(SMess) + 1, 0); 			printf("你已退出聊天程序!\n"); 			system("pause"); 			break; 		} 		//服务端显示自己的消息 		t = time(NULL); 		local = localtime(&t); 		printf("\r%s\t%d:%d:%d  \n    %s\n", CName, local->tm_hour, local->tm_min, local->tm_sec, SMess); 		send(sc, SMess, strlen(SMess) + 1, 0); 	} }  void sendFile(SOCKET ss) { 	char *str1 = "....确认成功...."; 	send(ss, str1, strlen(str1) + 1, 0);			//向客户端发送验证信息  	FILE *fp; 	long i;									//文件分的的块数  	char fileAddr[300]; 	char fileName[100]; 	char file_name[FILE_NAME_MAX_SIZE + 1]; 	memset(file_name, 0, FILE_NAME_MAX_SIZE + 1); 	printf("Please Input File Name On Server: "); 	scanf("%s", &file_name);  	char buffer[BUFFER_SIZE]; 	memset(buffer, 0, BUFFER_SIZE); 	strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name)); dmm: 	printf("请输入要传送的文件绝对地址(含文件名)：");  	gets_s(fileAddr);  	if ((fp = fopen(fileAddr, "rb")) == NULL)   //打开文件 	{ 		printf("文件地址输入错误!\n"); 		goto dmm; 	} 	getW_name(fileAddr, fileName); 	send(ss, fileName, strlen(fileName) + 1, 0);  //发送文件名  	fseek(fp, 0L, 2); 	long fileLength = ftell(fp);				//取得文件的长度 	fseek(fp, 0L, 0);  	char Length[100]; 	LongToChar(fileLength, Length); 	send(ss, Length, strlen(Length) + 1, 0);		//发送文件大小到客户端   	if (0 == fileLength%M)					//对文件进行分块 	{ 		i = fileLength / M; 	} 	else 	{ 		i = fileLength / M + 1; 	}  	char mess[M]; 	long readLength;						//从文件读取的长度 	long sendLength;						//发送文件的长度 	int k = 1;								//正在传送的模块号  	char *temp = "开始接收文件";				//向客户端开始传送，确认同步开始 	int nResult; 	nResult = recv(ss, mess, M, 0); 	if (nResult == -1)                   //判断客户端是否关闭 	{ 		printf("\n客户端已断开\n"); 		system("pause"); 		return; 	} 	send(ss, temp, strlen(temp) + 1, 0); 	printf("%s,共 %ld 模块：\n", mess, i); 	long total = 0; 	while (k <= i) 	{ 		Sleep((DWORD)800);			//此非常重要，降低了传输时间，保证了两边的同步 		readLength = fread(mess, sizeof(char), M, fp); 		sendLength = send(ss, mess, readLength, 0); 		total += sendLength; 		printf("\r第 %d 模块   读取：%ldB  发送：%ldB", k, readLength, sendLength); 		printf("  进度: %2.2f%c  模块：%ld / %ld", 100 * (total*1.0 / fileLength), 37, k, i); 		if (sendLength == SOCKET_ERROR) 		{ 			printf("失败!"); 		} 		k++; 	} 	fclose(fp); 	printf("\n文件发送完成!\n"); 	system("pause"); }   void chatting_server(SOCKET s_d) { 	system("color 0a"); 	char *str1 = "你同意了……"; 	send(s_d, str1, strlen(str1) + 1, 0);  	int receiveLength;			//接收消息的长度 	char SMess[1000];			//发送消息的缓存 	char RMess[1000];			//接收消息的缓存 	char SName[200];			//服务端用户的姓名 	char CName[200];			//客户端用户的姓名   	receiveLength = recv(s_d, CName, 200, 0); 	if (receiveLength == -1)		 //判断客户端是否关闭 	{ 		printf("客户端已断开\n"); 		system("pause"); 		return; 	} 	printf("你已和%s取的连接……\n", CName);  	printf("请输入你的名字："); 	gets_s(SName); 	while (strlen(SName) == 0)		//循环检测用户名是否合法 	{ 		printf("用户名不能为空!  请输入你的名字：\n"); 		getchar(); 		gets_s(SName); 	}  	send(s_d, SName, strlen(SName) + 1, 0);	//向客户端发送姓名 	printf("\n开始聊天(输入exit退出聊天程序)……\n"); 	while (1) 	{ 		struct tm *local; 		time_t t; 		t = time(NULL); 		local = localtime(&t); 		printf("\n\n请输入信息："); 		gets_s(SMess); 		if (strcmp(SMess, "exit") == 0)   //用户输入‘exit’退出程序 		{ 			send(s_d, SMess, strlen(SMess) + 1, 0); 			printf("你已退出聊天程序!\n"); 			system("pause"); 			break; 		} 		//在服务端显示自己的消息 		printf("\r%s\t%d:%d:%d\n    %s\n", SName, local->tm_hour, local->tm_min, local->tm_sec, SMess); 		send(s_d, SMess, strlen(SMess) + 1, 0);  		//在服务端显示客户端消息 		t = time(NULL); 		local = localtime(&t); 		receiveLength = recv(s_d, RMess, M, 0); 		if (receiveLength == -1)		 //判断客户端是否关闭 		{ 			printf("客户端已断开\n"); 			system("pause"); 			return; 		} 		if (strcmp(RMess, "exit") == 0) 		{ 			printf("\n客户端已退出聊天程序,本程序也即将退出!\n"); 			system("pause"); 			break; 		} 		printf("\n%s\t%d:%d:%d\n    %s\n", CName, local->tm_hour, local->tm_min, local->tm_sec, RMess); 	}  }  void getW_name(char waddr[], char wname[]) { 	int i, k = 0, j, w_len = strlen(waddr); 	for (i = w_len - 1; i >= 0; i--) 	{ 		if (waddr[i] == '\\') 			break; 		wname[k++] = waddr[i]; 	} 	wname[k++] = '\0'; 	i = strlen(wname); 	for (j = 0, k = i - 1; j<i / 2; j++, k--) 	{ 		char temp = wname[j]; wname[j] = wname[k]; wname[k] = temp; 	} }  int receiveFile(SOCKET sc) { 	system("color 0a"); 	int nResult; 	char mess[M]; 	nResult = recv(sc, mess, strlen(mess), 0);    //确认文件传送模块连接成功 	if (nResult == -1)                       //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return 0; 	} 	printf("%s\n", mess);   	char fileName[50]; 	nResult = recv(sc, fileName, 50, 0);       //接收文件名 	if (nResult == -1)                    //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return 0; 	} 	nResult = recv(sc, mess, M, 0);             //接受文件的大小 	if (nResult == 		804 		- 1)                    //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return 0; 	}  	long fileLength = StrToLong(mess);      //取的待传送文件的长度 	long i;	                              //存放文件块数  	if (0 == fileLength%M)				  //对文件按N单位进行分块 	{ 		i = fileLength / M; 	} 	else 	{ 		i = fileLength / M + 1; 	}   	FILE *fp;							//打开文件 	int k = 1;					    	//当前正在接收文件的块数 	long receiveLength;					//接收文件的长度 	long writeLength;					//已写到文件的字符长度 	fp = fopen(fileName, "wb"); 	char *temp = "开始传送文件"; 	send(sc, temp, strlen(temp) + 1, 0);		//向客户端开始传送，确认同步开始 	nResult = recv(sc, mess, M, 0);			//接收服务端的确认消息 	if (nResult == -1)                  //判断服务端是否关闭 	{ 		printf("\n服务端已断开\n"); 		system("pause"); 		return 0; 	} 	printf("%s,共 %ld 模块：\n", mess, i);  	long total = 0;						//已接收文件的长度 	while (k <= i)                         //循环的接收文件 	{ 		receiveLength = recv(sc, mess, M, 0); 		if (receiveLength == -1)        //判断服务端是否关闭 		{ 			printf("\n服务端已断开\n"); 			system("pause"); 			return 0; 		}  		writeLength = fwrite(mess, sizeof(char), receiveLength, fp); 		printf("\r第 %d 模块   接收：%ldB  写入：%ldB", k, receiveLength, writeLength); 		total += writeLength; 		printf("  进度: %2.2f%c  模块：%ld / %ld", 100 * (total*1.0 / fileLength), 37, k, i); 		k++; 	}   	fclose(fp); 	printf("\n文件接收完成!\n"); 	system("pause"); 	return 0; }   void LongToChar(long x, char a[]) { 	int count = 0; 	if (x == 0) 		return; 	while (x) 	{ 		a[count++] = x % 10 + '0'; 		x = x / 10; 	} 	a[count] = '\0'; 	for (int i = 0, j = count - 1; i<count / 2; i++, j--) 	{ 		char temp; 		temp = a[i]; 		a[i] = a[j]; 		a[j] = temp; 	} }  long StrToLong(char str[]) { 	long result; 	bool bEnd; 	bEnd = true; 	result = 0; 	for (int i = 0; bEnd; i++) 	{ 		if (str[i] != '\0' && str[i] >= '0' && str[i] <= '9') 		{ 			result = result * 10 + str[i] - '0'; 		} 		if (str[i] == '\0') 		{ 			bEnd = false; 		} 	} 	return result; } 我用Visual Studio 2017编译可以运行，这段源码的聊天部分是可用的，但是文件传送部分有问题，在客户端接受传输请求后程序会停止工作，求大神们帮忙看一下


Question: 数据结构，树的转换

引用 3 楼 赵4老师的回复:百度搜相关关键字。 谢谢

百度搜相关关键字。

引用 1 楼 赵4老师的回复: 谢谢


Question: 关于简单的c语言的问题，请各位大佬纠正一下，为什么循环只循环了一遍

#include"stdio.h" #include"stdlib.h"  struct student {     int number;     char name[20];     int brithyear;     struct student *next; }*a; FILE *fp;  void cage(struct student *a, int n, int nf) {     int aa,b,c,d;     aa = nf - a->brithyear;     printf("aa = %d, nf = %d, birthday = %d\n", aa, nf, a->brithyear);     if (aa>20)     {         fprintf(fp,"%d,%s,%d\n",a->number,a->name,a->brithyear);     }     a=a->next;     b=nf-a->brithyear;     printf("b = %d, nf = %d, birthday = %d\n", b, nf, a->brithyear);     if (b>20)     {         fprintf(fp,"%d,%s,%d\n",a->number,a->name,a->brithyear);     }     a=a->next;     c=nf-a->brithyear;     printf("c = %d, nf = %d, birthday = %d\n", c, nf, a->brithyear);     if (c>20)     {         fprintf(fp,"%d,%s,%d\n",a->number,a->name,a->brithyear);     }     a=a->next;     d=nf-a->brithyear;     printf("d = %d, nf = %d, birthday = %d\n", d, nf, a->brithyear);     if (d>20)     {         fprintf(fp,"%d,%s,%d\n",a->number,a->name,a->brithyear);     } };  int main() {     struct student a[4];     int m;     int num=15030521;     char studentname[]={"孙璐"};     printf("请输入4个学生的学号、姓名和出生年份\n");     int i=0;     for (i = 0; i < 4; i++)     {         scanf("%d%s%d", &a[i].number, a[i].name, &a[i].brithyear);         if (i <= 2)             a[i].next = &a[i+1];         else             a[i].next = NULL;      }     if((fp=fopen("bj1.txt","w"))==NULL)     {         printf("can't open file");         return -1;     }     printf("请输入年份\n");     scanf("%d",&m);     printf("下面是年龄大于20的学生信息\n");     cage(a,4,m);     fprintf(fp,"%d,%s\n",num,studentname);     fclose(fp);      return 0; } 链表知识还需要巩固一下，没有对next指针进行初始化，怎么在cage里直接运用呢？

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


Question: 想提个关于函数组合的问题

仅供参考：#include <stdio.h> double A[300][100]; double valuex[300]; double valuey[300]; int i; double fun00(double x,double y) {return x  +   y  ;}; double fun01(double x,double y) {return x*x+ 3*y  ;}; double fun02(double x,double y) {return x  + 2*y*x;}; //...  fun03(double x,double y) {return ...+...   ;}; //... //...  fun98(double x,double y) {return ...+...   ;}; double fun99(double x,double y) {return x/2+20*y  ;}; double (*funNN[100])(double,double)={     fun00,     fun01,     fun02, //  fun03, //  ... //  fun98,     fun99, }; int main() {     double x,y;     int f,FN;      for (i=0;i<300;i++) {         valuex[i]=(double)i;         valuey[i]=(double)i;     }     FN=3;     for (i=0;i<300;i++) {          x=valuex[i];          y=valuey[i];          for (f=0;f<FN;f++) A[i][f]=funNN[f](x,y);     }     for (i=0;i<3;i++) {         for (f=0;f<FN;f++) printf("%lg ",A[i][f]);         printf("\n");     } 	return 0; } //0 0 0 //2 4 3 //4 10 10  #include <stdio.h> #include <vector> #include <algorithm> using namespace std; int i; int L; void main(int argc,char **argv) { 	if (argc<2)	{ 		printf("%s 要排列的字符串\n",argv[0]); 		return; 	}     L=strlen(argv[1]);     vector<char> P(L);     vector<char>::iterator b,e,it;     b=P.begin();     e=P.end();     for (i=0;i<L;i++) P[i]=argv[1][i]; 	sort(b,e);     i=0;     do {         printf("%10d: ",++i);         for(it=b;it!=e;it++) printf("%c",*it);         printf("\n");     } while (next_permutation(b,e));     printf("The total: %d",i); }

建议用函数指针数组，将四个函数赋值到函数指针数组里，通过对数组元素（函数指针变量）进行排列组合，这样就可以把函数所有组合都执行一遍。


Question: 非正常结束的程序执行 UnhookWindowsHookEx 失败

引用 4 楼 Icy_Ybk 的回复:[quote=引用 3 楼 zhao4zhong1 的回复:] http://bbs.csdn.net/topics/390787357 这... 跟我的问题有什么关系..[/quote] 没必要追求正常结束。

引用 3 楼 zhao4zhong1 的回复:http://bbs.csdn.net/topics/390787357 这... 跟我的问题有什么关系..

估计与按 CTRL+C 的时候也会被钩子函数处理吧？是不是跟这个有关呢？

正常结束的意思是，按了 Q 键。程序里写了有在按 Q 键的时候发送一个退出消息。


Question: 怎样将函数内部的字符串数组通过函数参数传递出来？

引用 18 楼 seai 的回复:这个解比较靠谱。  补充问一句：如果里面不是字符串字面值，而是字符串变量，那么，其中每一个元素都要重新分配堆空间吧。   [quote=引用 17 楼 fjzqabx 的回复:]  #if 1  void get_ptr(char ***save) { 	//argv数组中的每个元素都是指向rodata段的指针,rodata段中数据的生命周期等同程序生命周期 	char *argv[] = {"hello", "C", "world"};  	*save = argv;//argv本身就是字符指针数组中元素的首地址,直接赋给二级字符指针即可 }  int main(void) { 	char **save = NULL; 	 	get_ptr(&save); 	 	//完全不必担心save数组中的元素出了get_ptr函数被释放,除非你的程序走到头了. 	printf("%s\t%s\t%s\n", save[0], save[1], save[2]);  	return 0; }  #endif [/quote]  引用 18 楼 seai 的回复:这个解比较靠谱。  补充问一句：如果里面不是字符串字面值，而是字符串变量，那么，其中每一个元素都要重新分配堆空间吧。   [quote=引用 17 楼 fjzqabx 的回复:]  #if 1  void get_ptr(char ***save) { 	//argv数组中的每个元素都是指向rodata段的指针,rodata段中数据的生命周期等同程序生命周期 	char *argv[] = {"hello", "C", "world"};  	*save = argv;//argv本身就是字符指针数组中元素的首地址,直接赋给二级字符指针即可 }  int main(void) { 	char **save = NULL; 	 	get_ptr(&save); 	 	//完全不必担心save数组中的元素出了get_ptr函数被释放,除非你的程序走到头了. 	printf("%s\t%s\t%s\n", save[0], save[1], save[2]);  	return 0; }  #endif [/quote]对的,因为字符指针数组的每个元素都只是一个4字节大小的指针,要给每个指针指定一个字符串(不论常量还是变量)的指向,按照你的意思字符串需要全局段的区域只有字符串常量区和堆区动态分配出来的内存.

这个解比较靠谱。  补充问一句：如果里面不是字符串字面值，而是字符串变量，那么，其中每一个元素都要重新分配堆空间吧。   引用 17 楼 fjzqabx 的回复: #if 1  void get_ptr(char ***save) { 	//argv数组中的每个元素都是指向rodata段的指针,rodata段中数据的生命周期等同程序生命周期 	char *argv[] = {"hello", "C", "world"};  	*save = argv;//argv本身就是字符指针数组中元素的首地址,直接赋给二级字符指针即可 }  int main(void) { 	char **save = NULL; 	 	get_ptr(&save); 	 	//完全不必担心save数组中的元素出了get_ptr函数被释放,除非你的程序走到头了. 	printf("%s\t%s\t%s\n", save[0], save[1], save[2]);  	return 0; }  #endif

引用 8 楼 seai 的回复:[quote=引用 7 楼 cfjtaishan 的回复:] [quote=引用 6 楼 seai 的回复:] [quote=引用 5 楼 cfjtaishan 的回复:] foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？[/quote] 为了能在main函数里得到字符串的地址，方法就是加static const char *s1[];原因是s1是局部变量，生命周期是函数内，函数调用结束，s1的生命就随着结束，加了static，那么它的生命周期就是整个程序，程序结束s1也随着释放。 当然也有其他方法，就是在堆栈上申请s1（2个指针大小空间），因为堆上的空间不会随着函数释放而释放，它可以在main函数里释放，前提是main函数尤其申请的堆上空间的首地址。[/quote]  静态方法不是很好的选择，说到底我要给这个C++接口做一个C的封装：  ============================================= int segmentor_segment(void *segmentor, const std::string &line, std::vector<std::string> &words) 功能：调用分词接口。  参数： 参数名	参数描述 void * segmentor	分词器的指针 const std::string & line	待分词句子 std::vector<std::string> & words	结果分词序列 返回值：  返回结果中词的个数。 =============================================  要把words的数据返回给C使用。words有可能很大，每个token空间都是static的话应该是不可行的。  [/quote]  你这个可以搞个局部变量的数组，传给函数作为函数的返回值额。比如 words[MAX_WORD_COUNT][MAX_WORD_LENGTH],一个句子的词的个数，和每个词的长度肯定是有上界的吧，就用这种数组传参进入接收函数的输出。

引用 12 楼 zhao4zhong1 的回复:这个世界上根本就没有那么多“不确定”。 在现实世界中，除时间和空间可能是无限的以外，其它任何事物都是有限的。 参考下面：//使用动态分配 #include <stdio.h> #include <stdlib.h> #include <malloc.h> int i,L; char *p; void main() {     for (i=0;i<20000;i++) {         L=rand();         p=malloc(L);         if (NULL==p) {             printf("malloc error!\n");             continue;         }         memset(p,0,L);         free(p);     } } //不使用动态分配 #include <stdio.h> #include <stdlib.h> #include <memory.h> #define MAXLEN 30000 int i,L; char buf[MAXLEN]; char *p; void main() {     p=&buf[0];     for (i=0;i<20000;i++) {         L=rand();         if (L>MAXLEN) {             printf("L>MAXLEN==%d, ignore spilth.\n",MAXLEN);             L=MAXLEN;         }         memset(p,0,L);     } }  个人倾向不使用动态分配。

引用 8 楼 seai 的回复:[quote=引用 7 楼 cfjtaishan 的回复:] [quote=引用 6 楼 seai 的回复:] [quote=引用 5 楼 cfjtaishan 的回复:] foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？[/quote] 为了能在main函数里得到字符串的地址，方法就是加static const char *s1[];原因是s1是局部变量，生命周期是函数内，函数调用结束，s1的生命就随着结束，加了static，那么它的生命周期就是整个程序，程序结束s1也随着释放。 当然也有其他方法，就是在堆栈上申请s1（2个指针大小空间），因为堆上的空间不会随着函数释放而释放，它可以在main函数里释放，前提是main函数尤其申请的堆上空间的首地址。[/quote]  静态方法不是很好的选择，说到底我要给这个C++接口做一个C的封装：  ============================================= int segmentor_segment(void *segmentor, const std::string &line, std::vector<std::string> &words) 功能：调用分词接口。  参数： 参数名	参数描述 void * segmentor	分词器的指针 const std::string & line	待分词句子 std::vector<std::string> & words	结果分词序列 返回值：  返回结果中词的个数。 =============================================  要把words的数据返回给C使用。words有可能很大，每个token空间都是static的话应该是不可行的。  [/quote] 不要把静态方法和静态变量混淆了，静态方法是static限制函数的，静态变量是在静态数据段上存放，对数组s1加static是改变s1的生命周期，这样可以在main函数里，在foo调用结束后s1没有被释放。

引用 10 楼 zhao4zhong1 的回复:在整个程序初始化时分配该程序将要用到的所有空间； 在整个程序退出前释放该程序在初始化时分配的所有空间。  但这样一来，接口会返回多少字符串是不确定的，所需的空间也就不确定的，和开始就分配好空间呢？

引用 6 楼 seai 的回复:[quote=引用 5 楼 cfjtaishan 的回复:] foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？[/quote] 比较保险的做法是   char * getstr() {  char * pret = new char[XXX]; ......; return pret; } void release(char *& ptr) { delete []ptr; ptr = NULL; }   这样跨DLL使用也没有问题

引用 3 楼 zhao4zhong1 的回复:业界的通行做法是传指向大量共享数据的指针。  所以，技术上，我上面的做法是没有问题的咯。在函数外部访问的时候，指针所指向的那些数据，我不需要担心被释放？

业界的通行做法是传指向大量共享数据的指针。

引用 1 楼 zhao4zhong1 的回复:请那些喜欢将数组作为函数参数传来传去或作为函数返回值的码农思考一下为什么不把整个互联网内容当作函数参数传来传去或作为函数返回值呢？   亲，谢谢你的回复。  首先，我最关注的还是我的上面的担心是否正确，还是说，可以技术上是可行可靠的。  此次，我demo的这段代码，之所以这样做，其实恰是因为，我调用的一个c++动态库接口，它的返回值表示成功与否，实际的数据是用参数传出的。我需要给它做一个C的封装，然后就有了上面的路子。如果有更好的方法，请明示。本人C／C++只能算业余的。  多谢了。

s1数组本身是局部变量，函数结束后就销毁了，结果正确只能说明运气好  字符串"abc"是在常量区，可以从函数返回指向常量字符串的指针  要限制函数外修改，可以限定指针类型，让指针指向的字符串为常量

引用 7 楼 cfjtaishan 的回复:[quote=引用 6 楼 seai 的回复:] [quote=引用 5 楼 cfjtaishan 的回复:] foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？[/quote] 为了能在main函数里得到字符串的地址，方法就是加static const char *s1[];原因是s1是局部变量，生命周期是函数内，函数调用结束，s1的生命就随着结束，加了static，那么它的生命周期就是整个程序，程序结束s1也随着释放。 当然也有其他方法，就是在堆栈上申请s1（2个指针大小空间），因为堆上的空间不会随着函数释放而释放，它可以在main函数里释放，前提是main函数尤其申请的堆上空间的首地址。[/quote]  静态方法不是很好的选择，说到底我要给这个C++接口做一个C的封装：  ============================================= int segmentor_segment(void *segmentor, const std::string &line, std::vector<std::string> &words) 功能：调用分词接口。  参数： 参数名	参数描述 void * segmentor	分词器的指针 const std::string & line	待分词句子 std::vector<std::string> & words	结果分词序列 返回值：  返回结果中词的个数。 =============================================  要把words的数据返回给C使用。words有可能很大，每个token空间都是static的话应该是不可行的。

引用 6 楼 seai 的回复:[quote=引用 5 楼 cfjtaishan 的回复:] foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？[/quote] 为了能在main函数里得到字符串的地址，方法就是加static const char *s1[];原因是s1是局部变量，生命周期是函数内，函数调用结束，s1的生命就随着结束，加了static，那么它的生命周期就是整个程序，程序结束s1也随着释放。 当然也有其他方法，就是在堆栈上申请s1（2个指针大小空间），因为堆上的空间不会随着函数释放而释放，它可以在main函数里释放，前提是main函数尤其申请的堆上空间的首地址。

引用 5 楼 cfjtaishan 的回复:foo的操作获得的s1的地址是没有意义的，得到的结果也是未定义的。因为s1是在foo函数栈上申请的局部变量指针数组，foo调用结束后，s1指针数组就会被释放，那么你得到的s1的地址自然就没有意义了，即使你得到的字符串是对的，因为可能foo释放之后的空间尚未被新的函数申请。所以，这个是未定义的。   你的解答比较清晰，我翻了翻网上文章，确实是这样的。  所以，正确的做法是：  a、在函数内分配堆空间，数据复制到对空间，由指针返回使用后释放吗？  还是，  b、在调用前分配好空间，函数内通过指针把数据写入到先前分配好的空间？  a的问题在于分配空间和释放空间不在一处，难免犯差错 b的问题在于不知道函数内的数据有多大、需要分配多少空间承载数据  这方面的“最佳实践”，有示范的代码展示一下吗？


Question: C语言一个结构体指针的问题

p=new TeSt


Question: 【求助】结构体变量不用malloc分配空间初始化，在函数里就没法运行

引用 6 楼 jianwen0529 的回复:[quote=引用 5 楼 trueJIMO 的回复:] 膜拜大佬..真的是如你所说... 但为什么我上面另一种写法用malloc分配过后就没有问题 还有就是“指向二维数组的指针，那么取值是三维写法”这句话该怎么理解啊。为什么从二维数组变成了三维数组... 我猜是：malloc是在堆上分配内存，越界修改其他内存导致崩溃的概率也许比在栈上的概率更小。 以上说法并没有什么根本，总而言之不管如何，这个越界读写都是一种错误的写法（除非是作者是明确在某些情况下进行）  指向二维数组的指针：因为这个近似于三级指针（近似而不是等价）[/quote] 明白了，谢大神

引用 5 楼 trueJIMO 的回复:膜拜大佬..真的是如你所说... 但为什么我上面另一种写法用malloc分配过后就没有问题 还有就是“指向二维数组的指针，那么取值是三维写法”这句话该怎么理解啊。为什么从二维数组变成了三维数组... 我猜是：malloc是在堆上分配内存，越界修改其他内存导致崩溃的概率也许比在栈上的概率更小。 以上说法并没有什么根本，总而言之不管如何，这个越界读写都是一种错误的写法（除非是作者是明确在某些情况下进行）  指向二维数组的指针：因为这个近似于三级指针（近似而不是等价）

引用 1 楼 jianwen0529 的回复:(*D)[v][w].vrtype.adj = 6; // *D 才是那个数组，否则应该写成D[0][v][w]，指向二维数组的指针，那么取值是三维写法  或者直接这样子 void ShortestPath_FLOYD(DistanceMatrix D) 我写的是D[v][w]->vrtype.adj=6这跟(*D)[v][w].vrtype.adj = 6是等效的啊，程序编译能通过运行的时候出现错误

引用 4 楼 jianwen0529 的回复:[quote=引用 3 楼 trueJIMO 的回复:] [quote=引用 1 楼 jianwen0529 的回复:] (*D)[v][w].vrtype.adj = 6; // *D 才是那个数组，否则应该写成D[0][v][w]，指向二维数组的指针，那么取值是三维写法  或者直接这样子 void ShortestPath_FLOYD(DistanceMatrix D) 我写的是D[v][w]->vrtype.adj=6这跟(*D)[v][w].vrtype.adj = 6是等效的啊，程序编译能通过运行的时候出现错误[/quote]  当然是不等效的，编译没问题只是说明语法没错。但是运行的时候越界了，是否运行正确以及能否正常运行这都是不可预料的 如同 int (*p)[3]; p[1]-> // p[0]地址是指向一个大小为3的一个数组，而p[1]是指向之后的下一个大小为3的一个数组 p[0][1]. 是不一样的   #include <stdio.h>  #define MAX_VERTEX_NUM 20  typedef struct{     int adj; }VRType;  typedef struct{ }InfoType;  typedef struct ArcCell{     VRType vrtype;     InfoType *info; }ArcCell, DistanceMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  // D的类型是 ArcCell (*)[MAX_VERTEX_NUM][MAX_VERTEX_NUM]  void ShortestPath_FLOYD(DistanceMatrix *D){     for (int v = 0; v < 3; ++v)     {         for (int w = 0; w < 3; ++w){             printf("%p\n", D[v][w]); // v一个步长的大小是 sizeof(ArcCell)*MAX_VERTEX_NUM*MAX_VERTEX_NUM             printf("%p\n", &D[v][w][0]); //上面等价于这个语句             printf("%p\n", &D[0][v][w]);             printf("\n");         }     } }  DistanceMatrix D; int main() {     ShortestPath_FLOYD(&D);     return 0; }[/quote] 膜拜大佬..真的是如你所说... 但为什么我上面另一种写法用malloc分配过后就没有问题 还有就是“指向二维数组的指针，那么取值是三维写法”这句话该怎么理解啊。为什么从二维数组变成了三维数组...

代码没有问题，D是一个数组的数组类型， 大小已定，无需重新分配内存。

引用 3 楼 trueJIMO 的回复:[quote=引用 1 楼 jianwen0529 的回复:] (*D)[v][w].vrtype.adj = 6; // *D 才是那个数组，否则应该写成D[0][v][w]，指向二维数组的指针，那么取值是三维写法  或者直接这样子 void ShortestPath_FLOYD(DistanceMatrix D) 我写的是D[v][w]->vrtype.adj=6这跟(*D)[v][w].vrtype.adj = 6是等效的啊，程序编译能通过运行的时候出现错误[/quote]  当然是不等效的，编译没问题只是说明语法没错。但是运行的时候越界了，是否运行正确以及能否正常运行这都是不可预料的 如同 int (*p)[3]; p[1]-> // p[0]地址是指向一个大小为3的一个数组，而p[1]是指向之后的下一个大小为3的一个数组 p[0][1]. 是不一样的   #include <stdio.h>  #define MAX_VERTEX_NUM 20  typedef struct{     int adj; }VRType;  typedef struct{ }InfoType;  typedef struct ArcCell{     VRType vrtype;     InfoType *info; }ArcCell, DistanceMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  // D的类型是 ArcCell (*)[MAX_VERTEX_NUM][MAX_VERTEX_NUM]  void ShortestPath_FLOYD(DistanceMatrix *D){     for (int v = 0; v < 3; ++v)     {         for (int w = 0; w < 3; ++w){             printf("%p\n", D[v][w]); // v一个步长的大小是 sizeof(ArcCell)*MAX_VERTEX_NUM*MAX_VERTEX_NUM             printf("%p\n", &D[v][w][0]); //上面等价于这个语句             printf("%p\n", &D[0][v][w]);             printf("\n");         }     } }  DistanceMatrix D; int main() {     ShortestPath_FLOYD(&D);     return 0; }


Question: 最大公约数a和b交换次数

引用 1楼幻夢之葉 的回复:http://blog.csdn.net/canhui_wang/article/details/50760510？？


Question: （新手）关于随机数

http://www.cnblogs.com/yeahgis/archive/2012/07/15/2592687.html  均匀分布使用最常规的就可以了。 指数分布可以参考上述链接，先使用均匀分布生成某随机数，然后进行某个算法改变它所生成的随机值，使这个随机算法看起来是指数分布的

搜“线性同余”

C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\rand.c /*** *rand.c - random number generator * *       Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *       defines rand(), srand() - random number generator * *******************************************************************************/  #include <cruntime.h> #include <mtdll.h> #include <stddef.h> #include <stdlib.h>  /*** *void srand(seed) - seed the random number generator * *Purpose: *       Seeds the random number generator with the int given.  Adapted from the *       BASIC random number generator. * *Entry: *       unsigned seed - seed to seed rand # generator with * *Exit: *       None. * *Exceptions: * *******************************************************************************/  void __cdecl srand (         unsigned int seed         ) {         _getptd()->_holdrand = (unsigned long)seed; }   /*** *int rand() - returns a random number * *Purpose: *       returns a pseudo-random number 0 through 32767. * *Entry: *       None. * *Exit: *       Returns a pseudo-random number 0 through 32767. * *Exceptions: * *******************************************************************************/  int __cdecl rand (         void         ) {         _ptiddata ptd = _getptd();          return( ((ptd->_holdrand = ptd->_holdrand * 214013L             + 2531011L) >> 16) & 0x7fff ); }

srand((unsigned)time(NULL));   rand();

random()*k + b  k = (N-M)/65536      b = M-0

下面这篇文章是关于随机数生成的，请多指教 http://blog.csdn.net/hou09tian/article/details/54630443

这个问题，建议楼主先写一个程序用random获取随机数。 然后执行几次，你会发现获取到的随机数都是一样，没有随机性。 想要获取不同的随机数据，就得设不一样的种子数才行.  常用设随机数种子的方法:   srand(getpid()); //以进程号作随机数种子， 每个进程号是唯一的   srand(time()); //以系统时间作随机数种子


Question: 小白求助 关于字符数组占内存的问题

可以参考一下这个资料 http://blog.csdn.net/libing403/article/details/72971863

http://edu.csdn.net/course/detail/2344 C语言指针与汇编内存地址-一.代码要素

因为变量是是在栈上，栈为其分配空间这个是不固定的。假如第一运行，栈分配了A地址开始的空间用于运行，运行结束后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执行停在该断点处的时候。

地址值由操作系统自动分配，并不是每次都一样的。

其实这个问题与换行符无关，是因c,d,e变量都是在栈里分配空间的，栈是重复用的。也就是说你现在程序执行分配的空间有可能是上一个进程刚用过的. c,d,e变量的值就是上次使用留下的值。


Question: 关于mysql_close()对mysql_real_connect()的断开连接

感谢您的指教，真是解决了我一个大问题，但是我还想更深入了解这个问题，能不能分析一下这个问题，或者在哪可以有相关的知识，因为我在网上找了很久都没找到有关的知识。谢谢！！！


Question: 【求助】为什么没有运行第一个gets直接运行第二个去了

引用 3楼自信男孩 的回复:gets调用前，如果有输入，建议见gets前加一句getchar();因为，gets是遇到回车符停止输入，然后返回。如果在gets前有输入，那么在输入缓冲区里就残留上次输入留下的回车符，所以，gets遇到这个回车符直接返回了。getchar()的作用就是接收输入缓存里残留的回车符，后面就会正常输入了。 gets是遇到回车就返回，这个是需要注意的。谢谢啦！

说错了     应该是在p1里gets（b1）用不了，但是引用过去后e=getchar（）用不了反到一直在运行gets（b1）

就是在p1里gets（比1）用不了，但是引用过去后e=getchar（）用不了反到一直在运行gets（p1）


Question: c  的scanf() 函数

感谢各位大佬，我以后会注意这个问题

//请今后要用 char c; scanf("%c",&c); //时，都改为 char s[2]; char c; scanf("%1s",s); c=s[0];

fflush(stdin); 刷新输入缓冲区，  scanf("%c",&(sample.vertexs[i])); 会读取回车。

引用 2 楼 lcqqcllcqqcl 的回复:你提的那个建议很好，也符合我输入的习惯； 我还有一个问题  printf("请输入各边的长度（权重），格式为：顶点号，顶点号，边长\n"); for(j=0;j<sample.amount_edges;j++) { scanf("%d,%d,%f",&i,&k,&(sample.edges[i][k]));      /*若是无向图，则edges[j][i]*=edges[i][j]*/ }; 这一段代码，为什么会错？而我换成  	float temp; 		scanf("%d,%d,%f",&i,&k,&temp); 		sample.edges[i][k]=temp; 就可以正常运行。。。。。。。 －－－循环里面，这里i,k的值还没有输入，所以不能实现取二维数组的地址 &(sample.edges[i][k])

scanf("%d,%d,%f", &i, &k, &(sample.edges[i][k])); 这里分成两条scanf来写  否则，&(sample.edges[i][k]) 这里的k还没初始化就使用了

但是通过scanf()函数不是给i,k,  sample.edges[i][k]值了吗？而i,k在数组元素之前；。。[size=24px]

引用 2 楼 lcqqcllcqqcl 的回复:你提的那个建议很好，也符合我输入的习惯； 我还有一个问题  printf("请输入各边的长度（权重），格式为：顶点号，顶点号，边长\n"); for(j=0;j<sample.amount_edges;j++) { scanf("%d,%d,%f",&i,&k,&(sample.edges[i][k]));      /*若是无向图，则edges[j][i]*=edges[i][j]*/ }; 这一段代码，为什么会错？而我换成  	float temp; 		scanf("%d,%d,%f",&i,&k,&temp); 		sample.edges[i][k]=temp; 就可以正常运行。。。。。。。 scanf("%d,%d,%f",&i,&k,&(sample.edges[i][k])); 时，i、k是什么值？还没有确定的值，就往sample.edges[i][k]中存东西，肯定出错了

getchar();    /*加这句，这句用于接收残留在输入缓冲区里的回车符（上一次输入留下的，就是因为接下来要用%c格式输入）*/ for(i=0;i<sample.amount_nodes;i++) { scanf("%c",&(sample.vertexs[i]));    /*去掉\n*/  }    /*去掉这儿的分号，因为不需要*/ 如果还是按照你的目前输入方式，for循环里的输入每输入一次就一次回车，建议在每次输入vertex[i]之后都要加一句getchar();像这样   getchar(); for(i=0;i<sample.amount_nodes;i++) { scanf("%c",&(sample.vertexs[i])); getchar();  } 原因和第一次没有输入一样； 如果for循环里的数据是在不换行的情况下，一次输入（每次都以空格隔开）则不需要getchar();


Question: for循环中scanf函数使用出错！！请大神赐教！

在每个最后不带\n的printf后面加fflush(stdout); 在每个不想受接收缓冲区旧内容影响的scanf前面加rewind(stdin); 另外请检查scanf的返回值。 //请今后要用 char c; scanf("%c",&c); //时，都改为 char s[2]; char c; scanf("%1s",s); c=s[0];

引用 3 楼 自信男孩的回复:[quote=引用 2 楼 TFLiu666 的回复:] [quote=引用 1 楼 cfjtaishan 的回复:] 把fflush(stdin);用getchar();替换；第一个没有输入是因为第一个输入是上一个循环的回车符；即scanf_s的 原因是fflush(stdin);对标准输出还可以，但是对于标准输入stdin，操作是不可预知的。所以，用getchar();可以吸收scanf_s输入之后残留在输入缓冲区里的回车符   谢谢大神，这个问题解决掉了。但是又出现了一个,还请大神在帮帮忙 问题： 就是在利用for循环建立边表的时候，程序无条件总是中断，即进行不了《i，j》的录入。这又是为什么啊？  	printf("读入边《i，j》的顶点对应序号:\n");      //建立边表          	for (k = 0;k < G->EdgeNum;k++) 	{ 		printf("请输入（vi，vj）的顶点序号："); 	//	fflush(stdin);//清除标准输入输出缓冲区  		scanf_s("%d,%d", &i, &j);//读入边《i，j》的顶点对应序号      //问题出现在此处                            	//	getchar(); 		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = j; 		p->next = G->adjlist[i].firstedge; 		G->adjlist[i].firstedge = p;  		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = i;                    //邻接序号为i 		G->adjlist[j].firstedge = p; 	}[/quote] 在这个地方scanf_s就不要加getchar();了，因为加getchar();是针对下一个输入是以%c的。[/quote] 还想请教最后一个问题：是不是以后遇到这种情况都要用getchar()吞掉回车符？？

引用 2 楼 TFLiu666 的回复:[quote=引用 1 楼 cfjtaishan 的回复:] 把fflush(stdin);用getchar();替换；第一个没有输入是因为第一个输入是上一个循环的回车符；即scanf_s的 原因是fflush(stdin);对标准输出还可以，但是对于标准输入stdin，操作是不可预知的。所以，用getchar();可以吸收scanf_s输入之后残留在输入缓冲区里的回车符   谢谢大神，这个问题解决掉了。但是又出现了一个,还请大神在帮帮忙 问题： 就是在利用for循环建立边表的时候，程序无条件总是中断，即进行不了《i，j》的录入。这又是为什么啊？  	printf("读入边《i，j》的顶点对应序号:\n");      //建立边表          	for (k = 0;k < G->EdgeNum;k++) 	{ 		printf("请输入（vi，vj）的顶点序号："); 	//	fflush(stdin);//清除标准输入输出缓冲区  		scanf_s("%d,%d", &i, &j);//读入边《i，j》的顶点对应序号      //问题出现在此处                            	//	getchar(); 		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = j; 		p->next = G->adjlist[i].firstedge; 		G->adjlist[i].firstedge = p;  		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = i;                    //邻接序号为i 		G->adjlist[j].firstedge = p; 	}[/quote] 在这个地方scanf_s就不要加getchar();了，因为加getchar();是针对下一个输入是以%c的。

引用 1 楼 cfjtaishan 的回复:把fflush(stdin);用getchar();替换；第一个没有输入是因为第一个输入是上一个循环的回车符；即scanf_s的 原因是fflush(stdin);对标准输出还可以，但是对于标准输入stdin，操作是不可预知的。所以，用getchar();可以吸收scanf_s输入之后残留在输入缓冲区里的回车符   谢谢大神，这个问题解决掉了。但是又出现了一个,还请大神在帮帮忙 问题： 就是在利用for循环建立边表的时候，程序无条件总是中断，即进行不了《i，j》的录入。这又是为什么啊？  	printf("读入边《i，j》的顶点对应序号:\n");      //建立边表          	for (k = 0;k < G->EdgeNum;k++) 	{ 		printf("请输入（vi，vj）的顶点序号："); 	//	fflush(stdin);//清除标准输入输出缓冲区  		scanf_s("%d,%d", &i, &j);//读入边《i，j》的顶点对应序号      //问题出现在此处                            	//	getchar(); 		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = j; 		p->next = G->adjlist[i].firstedge; 		G->adjlist[i].firstedge = p;  		p = (EdgeNode*)malloc(sizeof(EdgeNode)); 		p->adjvertex = i;                    //邻接序号为i 		G->adjlist[j].firstedge = p; 	}


Question: c语言中素数的判断问题

Finding prime numbers - Kenneth Haugland  Different schemas for finding prime numbers explained with code http://www.codeproject.com/Articles/429694/Finding-prime-numbers

引用 8 楼 cfjtaishan 的回复:[quote=引用 6 楼 lzw2016 的回复:] [quote=引用 5 楼 cfjtaishan 的回复:] #include <stdio.h> #include <math.h>  int main() {     int m;     int i;     int k;      printf("输入一个整数：");     scanf("%d",&m);     k = (int)sqrt( (double)m );     for(i = 2; i <= k; i++) {         if(m%i == 0) {             break;         }     }     if(i > k)         printf("%d是素数。\n",m);     else         printf("%d不是素数。\n", m);     printf("%d",i);      return 0; } 逻辑有问题，判断m取余i为0时，就直接退出循环为0时不就是找到了一个可能是素数的m吗[/quote] 如果为0，可以确切的判定，它一定不是素数。素数是除了1和它本身能被整除[/quote]额，对，是我当时没表示清。但逻辑没问题 ，不是素数自然不就要跳出循环吗

引用 9 楼 lzw2016 的回复:[quote=引用 8 楼 cfjtaishan 的回复:] [quote=引用 6 楼 lzw2016 的回复:] [quote=引用 5 楼 cfjtaishan 的回复:] #include <stdio.h> #include <math.h>  int main() {     int m;     int i;     int k;      printf("输入一个整数：");     scanf("%d",&m);     k = (int)sqrt( (double)m );     for(i = 2; i <= k; i++) {         if(m%i == 0) {             break;         }     }     if(i > k)         printf("%d是素数。\n",m);     else         printf("%d不是素数。\n", m);     printf("%d",i);      return 0; } 逻辑有问题，判断m取余i为0时，就直接退出循环为0时不就是找到了一个可能是素数的m吗[/quote] 如果为0，可以确切的判定，它一定不是素数。素数是除了1和它本身能被整除[/quote]额，对，是我当时没表示清。但逻辑没问题 ，不是素数自然不就要跳出循环吗[/quote] 如果不是素数，就应该break出去，如果是素数那么i自然会大于k

引用 3 楼 destroyrap 的回复:你的if(i>k)的判断是在for循环里面，printf在for循环外面， 是printf("%d",i);在for循环外面

你的if(i>k)的判断是在for循环里面，printf在for循环外面，

你的if(i>k)的判断是在for循环里面

25为什么会是素数？？？难道它不能被5整除吗？？？

引用 6 楼 lzw2016 的回复:[quote=引用 5 楼 cfjtaishan 的回复:] #include <stdio.h> #include <math.h>  int main() {     int m;     int i;     int k;      printf("输入一个整数：");     scanf("%d",&m);     k = (int)sqrt( (double)m );     for(i = 2; i <= k; i++) {         if(m%i == 0) {             break;         }     }     if(i > k)         printf("%d是素数。\n",m);     else         printf("%d不是素数。\n", m);     printf("%d",i);      return 0; } 逻辑有问题，判断m取余i为0时，就直接退出循环为0时不就是找到了一个可能是素数的m吗[/quote] 如果为0，可以确切的判定，它一定不是素数。素数是除了1和它本身能被整除

25不是素数，i=k=5时，for循环中i还要自增一次

引用 5 楼 cfjtaishan 的回复:#include <stdio.h> #include <math.h>  int main() {     int m;     int i;     int k;      printf("输入一个整数：");     scanf("%d",&m);     k = (int)sqrt( (double)m );     for(i = 2; i <= k; i++) {         if(m%i == 0) {             break;         }     }     if(i > k)         printf("%d是素数。\n",m);     else         printf("%d不是素数。\n", m);     printf("%d",i);      return 0; } 逻辑有问题，判断m取余i为0时，就直接退出循环为0时不就是找到了一个可能是素数的m吗


Question: 在windows上使用dir命令获取的文件绝对路径，在linux上无法加载该文件

linux路径里用的是斜杠/ win路径用的是反斜杠\

"/home/pic/000001.jpg"→"//home//pic//000001.jpg" 试一试

\替换为/ ？

“发现报错，找不到这些文件” 具体报什么错，加载图片的代码可否贴出

是不是权限的问题，在/home/pic/下存放文件和读取文件是需要root的权限的


Question: 二叉树插入时这一行什么意思，还有最后的返回值为什么是树根节点，不是插入的结点吗

仅供参考：#include <iostream> #include <stack> #include <queue> #include <locale.h> using namespace std; typedef struct BiTNode {//二叉树结点     char data;                      //数据     struct BiTNode *lchild,*rchild; //左右孩子指针 } BiTNode,*BiTree; int CreateBiTree(BiTree &T) {//按先序序列创建二叉树     char data;     scanf("%c",&data);//按先序次序输入二叉树中结点的值（一个字符），‘#’表示空树     if (data == '#') {         T = NULL;     } else {         T = (BiTree)malloc(sizeof(BiTNode));         T->data = data;         //生成根结点         CreateBiTree(T->lchild);//构造左子树         CreateBiTree(T->rchild);//构造右子树     }     return 0; } void Visit(BiTree T) {//输出     if (T->data != '#') {         printf("%c ",T->data);     } } void PreOrder(BiTree T) {//先序遍历     if (T != NULL) {         Visit(T);               //访问根节点         PreOrder(T->lchild);    //访问左子结点         PreOrder(T->rchild);    //访问右子结点     } } void InOrder(BiTree T) {//中序遍历     if (T != NULL) {         InOrder(T->lchild);     //访问左子结点         Visit(T);               //访问根节点         InOrder(T->rchild);     //访问右子结点     } } void PostOrder(BiTree T) {//后序遍历     if (T != NULL) {         PostOrder(T->lchild);   //访问左子结点         PostOrder(T->rchild);   //访问右子结点         Visit(T);               //访问根节点     } } void PreOrder2(BiTree T) {//先序遍历(非递归) //访问T->data后，将T入栈，遍历左子树；遍历完左子树返回时，栈顶元素应为T，出栈，再先序遍历T的右子树。     stack<BiTree> stack;     BiTree p = T;//p是遍历指针     while (p || !stack.empty()) {   //栈不空或者p不空时循环         if (p != NULL) {             stack.push(p);          //存入栈中             printf("%c ",p->data);  //访问根节点             p = p->lchild;          //遍历左子树         } else {             p = stack.top();        //退栈             stack.pop();             p = p->rchild;          //访问右子树         }     } } void InOrder2(BiTree T) {//中序遍历(非递归) //T是要遍历树的根指针，中序遍历要求在遍历完左子树后，访问根，再遍历右子树。 //先将T入栈，遍历左子树；遍历完左子树返回时，栈顶元素应为T，出栈，访问T->data，再中序遍历T的右子树。     stack<BiTree> stack;     BiTree p = T;//p是遍历指针     while (p || !stack.empty()) {   //栈不空或者p不空时循环         if (p != NULL) {             stack.push(p);          //存入栈中             p = p->lchild;          //遍历左子树         } else {             p = stack.top();        //退栈，访问根节点             printf("%c ",p->data);             stack.pop();             p = p->rchild;          //访问右子树         }     } }  typedef struct BiTNodePost{     BiTree biTree;     char tag; } BiTNodePost,*BiTreePost; void PostOrder2(BiTree T) {//后序遍历(非递归)     stack<BiTreePost> stack;     BiTree p = T;//p是遍历指针     BiTreePost BT;     while (p != NULL || !stack.empty()) {//栈不空或者p不空时循环         while (p != NULL) {//遍历左子树             BT = (BiTreePost)malloc(sizeof(BiTNodePost));             BT->biTree = p;             BT->tag = 'L';//访问过左子树             stack.push(BT);             p = p->lchild;         }         while (!stack.empty() && (stack.top())->tag == 'R') {//左右子树访问完毕访问根节点             BT = stack.top();             stack.pop();//退栈             printf("%c ",BT->biTree->data);         }         if (!stack.empty()) {//遍历右子树             BT = stack.top();             BT->tag = 'R';//访问过右子树             p = BT->biTree;             p = p->rchild;         }     } }  void LevelOrder(BiTree T) {//层次遍历     if (T == NULL) return;     BiTree p = T;     queue<BiTree> queue;//队列     queue.push(p);//根节点入队     while (!queue.empty()) {    //队列不空循环         p = queue.front();      //对头元素出队         printf("%c ",p->data);  //访问p指向的结点         queue.pop();            //退出队列         if (p->lchild != NULL) {//左子树不空，将左子树入队             queue.push(p->lchild);         }         if (p->rchild != NULL) {//右子树不空，将右子树入队             queue.push(p->rchild);         }     } } int main() {     BiTree T;      setlocale(LC_ALL,"chs");     CreateBiTree(T);      printf("先序遍历        ：");PreOrder  (T);printf("\n");     printf("先序遍历(非递归)：");PreOrder2 (T);printf("\n");                                                printf("\n");     printf("中序遍历        ：");InOrder   (T);printf("\n");     printf("中序遍历(非递归)：");InOrder2  (T);printf("\n");                                                printf("\n");     printf("后序遍历        ：");PostOrder (T);printf("\n");     printf("后序遍历(非递归)：");PostOrder2(T);printf("\n");                                                printf("\n");     printf("层次遍历        ：");LevelOrder(T);printf("\n");      return 0; } //ABC##DE#G##F### //先序遍历        ：A B C D E G F //先序遍历(非递归)：A B C D E G F // //中序遍历        ：C B E G D F A //中序遍历(非递归)：C B E G D F A // //后序遍历        ：C G E F D B A //后序遍历(非递归)：C G E F D B A // //层次遍历        ：A B C D E F G //  ///       A ///      / ///     B ///    / \ ///   C   D ///      / \ ///     E   F ///      \ ///       G  “给定一个小点的输入，完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门！ 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出

引用 2 楼 whwsy521 的回复:这是一个有序的二叉树，是在此基础上进行结点的插入，我的疑问是每次递归为什么都要t->rchild=insert(x,t->rchild)，等号前面的去掉可否，还有最后return 的t是根节点吗，为什么不是最后插入的结点 插入一个数值X，如果它大于当前节点则往左子树插入。如果当前节点的左子树是NULL,也就是说当前节点是叶节点，则根据x形成一个新的节点并返回，同时把当前节点左子树指向返回的节点，也就是说插入了 同理右节点

这个递归创建二叉树，建议着重看一下递归的原理。 第一次进入insert是，是对t申请了空间，然后接下来的节点穿件都是t->左右节点；所以t是根节点。


Question: c语言小白求助，小黑框秒退，看不到结果

代码没有错误，顺利执行完成， 所以直接退出了 在return 0之前加上getchar()

按照1楼的做法，窗口不会闪退的

现在的码农竟然99%都不会在cmd窗口中输入cd命令设置当前目录为程序所在目录，输入程序名运行程序了！

最简单的办法，在return 0前面加几个getchar() 我就不解释了  慢慢的你就懂了

应该是环境问题，程序逻辑和语法都没有问题。建议检查一下编译和运行环境是不是有问题。（比如，打印一个helloworld看是否有问题）。

加头文件 #include<iostream> 再在return前加 system("pause");


Question: 一个程序，折腾了很久，来个大神看看

#include <stdio.h> #include <stdlib.h> #include <time.h>  int i,j,r,c; int s_a1[11],c_a1[5];  void s_a(int a[][5]); void c_a(int a[][5]); int  search_(int a[][5]); double jariance(void);  int main() {     int s[11][5];      srand(time(NULL));     for(i=1;i<=10;i++)     {         printf("student %d:\n",i);         for(j=0;j<=4;j++)         {             //scanf("%d",&s[i][j]);             s[i][j] = rand() % 100;         }     }     s_a(s);     c_a(s);     printf("\n");     printf("class     \t1\t2\t3\t4\t5\taverage\n");     for(i=1;i<=10;i++)     {         printf("student %d\t",i);         for(j=0;j<=4;j++)         {             printf("%d\t",s[i][j]);         }         printf("%d\n", s_a1[i]);     }     printf("\t\t");     for(j=0;j<=4;j++)     {         printf("%d", c_a1[j]);     }     printf("\n");      printf("the student: %d\t the class: %d\t, the highest: %d\n", r, c, search_(s));    /*根据参数压栈顺序：从右向左压栈，所以改变一下输出顺序，否则r c的值一直为0*/     printf("the jariance: %.2lf\n",jariance());    /*输出格式：double应用%lf,.2表示保留2位有效数字*/     return 0; }  /* aver col */ void s_a(int a[][5]) {     int sum;     for(i = 1; i <= 10; i++)     {         sum=0;         for(j=0;j<=4;j++)         {             sum=sum+a[i][j];         }         s_a1[i]=sum/5;     }  }  /* aver row */ void c_a(int a[][5]) {     int sum;     for(j = 0; j <= 4; j++)     {         sum = 0;         for(i = 1; i <= 10; i++)    /*这儿改一下，j++改成i++，手误吧*/         {             sum = sum + a[i][j];         }         c_a1[j] = sum/10;     }  }  int  search_(int a[][5]) {     int x=0;     for(i=1;i<=10;i++)     {         for(j=0;j<=4;j++)         {             if(x<a[i][j])             {                 x=a[i][j];                 r = i;                 c = j + 1;    /*如果上面是手误，这个地方就说不过去了，我想应该是将值赋值给全局变量c*/             }         }     }     return(x); }   double jariance(void) {     double sum=0,sum2=0,x;     for(i=1;i<=10;i++)     {         sum+=s_a1[i];         sum2+=s_a1[i]*s_a1[i];     }     x=sum2/10-(sum/10)*(sum/10);     return(x); }  有问题的地方，上面已一一描述了。 最后，建议函数声明不要放在main函数里，这个习惯不好。

void c_a(int a[][5]) { int sum; for(j=0;j<=4;j++) {  sum=0;  for(i=1;i<=10;j++)  {  sum=sum+a[i][j];  }   c_a1[j]=sum/10; }    细看这一行 for(i=1;i<=10;j++)


Question: Huffman编码树！！！

引用 4 楼 zhao4zhong1 的回复:百度搜相关关键字。 谢谢

引用 3 楼 cfjtaishan 的回复:for(j=0;j<n;j++)         {             scanf("%d", &w[j]); /*这儿需要加一个&，因为scanf要求的是地址*/         }  错了，错了，刚才我发的是下面这个题目的程序，但是测试答案很多组都是对的，但是交到openjudge上就是wrong answer，麻烦帮我看一下，谢谢 题目是这样子的： 树的转换  描述 我们都知道用“左儿子右兄弟”的方法可以将一棵一般的树转换为二叉树，如：       0                             0   /   |  \                         /  1  2  3       ===>     1     / \                           \   4   5                           2                                    / \                                  4   3                                   \                                    5  现在请你将一些一般的树用这种方法转换为二叉树，并输出转换前和转换后树的高度。 输入输入包括多行，最后一行以一个#表示结束。 每行是一个由“u”和“d”组成的字符串，表示一棵树的深度优先搜索信息。比如，dudduduudu可以用来表示上文中的左树，因为搜索过程为：0 Down to 1 Up to 0 Down to 2 Down to 4 Up to 2 Down to 5 Up to 2 Up to 0 Down to 3 Up to 0。 你可以认为每棵树的结点数至少为2，并且不超过10000。输出对于每棵树，按如下格式输出转换前和转换后树的高度： Tree t: h1 => h2 其中t是树的编号（从1开始），h1是转换前树的高度，h2是转换后树的高度。 样例输入 dudduduudu ddddduuuuu dddduduuuu dddduuduuu #  样例输出 Tree 1: 2 => 4 Tree 2: 5 => 5 Tree 3: 4 => 5 Tree 4: 4 => 4

引用 3 楼 cfjtaishan 的回复:for(j=0;j<n;j++)         {             scanf("%d", &w[j]); /*这儿需要加一个&，因为scanf要求的是地址*/         }  这道题测试答案对了之后交到openjudge上是wrong answer，差不多找到哪里错了之后，又重新写了一个程序，测了很多组数据之后都对，但是还是错了，能麻烦给我看一下么，谢谢  这是重写的： #include<stdio.h> #include<string.h> #define N 2000 int h,len; int forest(char a[],int num_d,int num_u,int i) { 	num_d=0; 	while(a[i]=='d') {num_d++; i++;} 	if(num_d-num_u>=0) h+=num_d-num_u; 	num_u=0; 	while(a[i]=='u') {num_u++; i++;} 	if(i!=len) return forest(a,num_d,num_u,i); 	return h; } int tree(char a[],int depth,int num_d,int num_u,int i) { 	num_u=0; num_d=0; 	while(a[i]=='u') {num_u++; i++;} 	while(a[i]=='d') {num_d++; i++;} 	if(num_d-num_u>=0) depth+=1; 	if(i!=len) return tree(a,depth,num_d,num_u,i); 	return depth; } int main() { 	char a[N]; 	int i,j,k,t; 	int h1[N],h2[N]; 	for(i=0;;i++) 	{ 		scanf("%s",a); 		len=strlen(a);	 		for(j=0;j<len;j++) 		{ 			if(a[j]=='u')  			{ 				t=j; 				break; 			} 		} 		if(a[0]=='#') break; 		else 		{ 			h1[i]=forest(a,0,0,0); 			h=0; 			k=h1[i]; 			h2[i]=tree(a,k,0,0,t); 		} 	} 	for(j=0;j<i;j++) 	{ 		printf("Tree %d: %d => %d\n",j+1,h1[j],h2[j]); 	} 	return 0; }

百度搜相关关键字。

交到openjudge上一直是wrong answer

我的错找出来了，运行结果也对了，但是交上去显示wrong answer，请各位大神看看，谢谢


Question: 用VS编程，Stack overflow，求大神帮忙，百度搜到的方法都不行

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

建议贴出你的源码~

建立project

有个网站叫stackoverflow,你去那儿问绝对有答案

调试的时候还自动生成了一个.asm文件，如下      page    ,132         title   chkstk - C stack checking routine ;*** ;chkstk.asm - C stack checking routine ; ;       Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ;       Provides support for automatic stack checking in C procedures ;       when stack checking is enabled. ; ;*******************************************************************************  .xlist         include cruntime.inc .list  ; size of a page of memory  _PAGESIZE_      equ     1000h           CODESEG  page ;*** ;_chkstk - check stack upon procedure entry ; ;Purpose: ;       Provide stack checking on procedure entry. Method is to simply probe ;       each page of memory required for the stack in descending order. This ;       causes the necessary pages of memory to be allocated via the guard ;       page scheme, if possible. In the event of failure, the OS raises the ;       _XCPT_UNABLE_TO_GROW_STACK exception. ; ;       NOTE:  Currently, the (EAX < _PAGESIZE_) code path falls through ;       to the "lastpage" label of the (EAX >= _PAGESIZE_) code path.  This ;       is small; a minor speed optimization would be to special case ;       this up top.  This would avoid the painful save/restore of ;       ecx and would shorten the code path by 4-6 instructions. ; ;Entry: ;       EAX = size of local frame ; ;Exit: ;       ESP = new stackframe, if successful ; ;Uses: ;       EAX ; ;Exceptions: ;       _XCPT_GUARD_PAGE_VIOLATION - May be raised on a page probe. NEVER TRAP ;                                    THIS!!!! It is used by the OS to grow the ;                                    stack on demand. ;       _XCPT_UNABLE_TO_GROW_STACK - The stack cannot be grown. More precisely, ;                                    the attempt by the OS memory manager to ;                                    allocate another guard page in response ;                                    to a _XCPT_GUARD_PAGE_VIOLATION has ;                                    failed. ; ;*******************************************************************************  public  _alloca_probe  _chkstk proc  _alloca_probe    =  _chkstk          push    ecx  ; Calculate new TOS.          lea     ecx, [esp] + 8 - 4      ; TOS before entering function + size for ret value         sub     ecx, eax                ; new TOS  ; Handle allocation size that results in wraparound. ; Wraparound will result in StackOverflow exception.          sbb     eax, eax                ; 0 if CF==0, ~0 if CF==1         not     eax                     ; ~0 if TOS did not wrapped around, 0 otherwise         and     ecx, eax                ; set to 0 if wraparound          mov     eax, esp                ; current TOS         and     eax, not ( _PAGESIZE_ - 1) ; Round down to current page boundary  cs10:         cmp     ecx, eax                ; Is new TOS         jb      short cs20              ; in probed page?         mov     eax, ecx                ; yes.         pop     ecx         xchg    esp, eax                ; update esp         mov     eax, dword ptr [eax]    ; get return address         mov     dword ptr [esp], eax    ; and put it at new TOS         ret  ; Find next lower page and probe cs20:         sub     eax, _PAGESIZE_         ; decrease by PAGESIZE         test    dword ptr [eax],eax     ; probe page.         jmp     short cs10  _chkstk endp          end

调试的结果是这个样子的： “helloo.exe”: 已加载“E:\中国大学mooc\helloo\Debug\helloo.exe”，已加载符号。 “helloo.exe”: 已加载“C:\Windows\System32\ntdll.dll”，已加载符号(去除源信息)。 “helloo.exe”: 已加载“C:\Windows\System32\kernel32.dll”，已加载符号(去除源信息)。 “helloo.exe”: 已加载“C:\Windows\System32\KernelBase.dll”，已加载符号(去除源信息)。 “helloo.exe”: 已加载“C:\Windows\System32\msvcr100d.dll”，已加载符号。 程序“[9364] helloo.exe: 本机”已退出，返回值为 1 (0x1)。 真的看不懂

在占用内存空间较大的局部数组声明的前面加static将其从堆栈数据段挪到全局数据段即可避开因局部数组大小超过默认堆栈大小1MB造成程序不能正常运行的问题。 #include<stdio.h>//定义输入／输出函数 #include<stdlib.h>//定义杂项函数及内存分配函数 #include<string.h>//字符串处理 #include<math.h>//定义数学函数  #define N 2   //2列 #define L 1000  //100行     int main(int argc, char *argv[]) {     int i,j,t,c,p,q; 	static int	zm[40][36]={0};//初水位 	static int	zn[40][36]={0};//末水位 	//int cq[p][c];//水位库容 //	double E[80][36];//余留期效益值 //	double n[i][t];//t-1到t阶段的最优出力期望   const char file_name[50] = "data.txt";       FILE *fp;     int data[N][L] = {0};   //二维数组     int index[N] = {0};   //二维数组列下标     double temp;     int v, u;     int count = 0;  //计数器，记录已读出的浮点数     if((fp=fopen(file_name, "r")) == NULL) {         //printf("请确认文件(%s)是否存在!\n", file_name);         exit(1);     }     while(1==fscanf(fp, "%lf", &temp)) {         data[count%N][(index[count%N])++] = temp;         count++;     }     for(v = 0; v < N; v++) {         for(u = 0; u < index[v]; u++) {     // printf("%d",data[v][u]) ;  //data[v][u];         }       //  printf("\n");     }     fclose(fp);  const char file[50] = "xiayou.txt";     FILE* lfp;     if((lfp=fopen(file, "r")) == NULL)     {         printf("Cannot open this filefp1\n");         exit(0);     }    int res=0;     static double  Y[2][851];     for (i = 0; i < 2; i++)     {         for (j = 0; j < 851; j++)         {             res = fscanf(lfp, "%lf", &Y[i][j]);          //    printf("%lf \n", Y[i][j]);          }      }     fclose(lfp);       int a=0,num[36]={0};         for(u = 0; u < 36; u++) { 		   // printf("%d\t",data[0][u]); 			//printf("%d\t",data[1][u]); 			//printf("\n"); 		  num[a]=data[0][u]-data[1][u]; 		  a++;          }  // for(a= 0; a < 36; a++)    //printf("%d\n",num[a]);     for(t= 0; t < 36; t++){         for(i=0;i <=num[t] ;i++){ 		zn[i][t] =data[0][t]; 		data[0][t]--; 	//	printf("%d\t",zn[i][t]); 		 			//	printf("%d\t",data[0][t]); 			//	printf("\n"); 		  } 	// printf("\n");   }  //	for(t= 0; t	< 36; t++){   //      for(i=0;i <=num[t] ;i++){ 		//	printf("%d\t",zn[i][t]); //		   } 	//	 printf("\n"); //	}       zm[0][0]=175;     for(t= 1; t < 36; t++){   //	printf("%d\t",num[t]);    //printf("%d\t",data[0][t]); //	printf("\n");         for(i=0;i <=num[t-1] ;i++){ 		zm[i][t] =zn[i][t-1]; 			//	 printf("%d\t",zn[i][t]); 			//	printf("%d\t",zm[i][t]); 		 			//	printf("%d\t",data[0][t]); 			//	printf("\n"); 		  } 	// printf("\n");   }  //  for(t= 0; t < 36; t++){ //     for(i=0;i <40 ;i++){ //      printf("%d\t",zm[i][t]); //		 }  //      printf("\n"); //	}     int cq[2][31]={0};    for(v=0;v<2;v++){     for(c=0;c<31;c++){ 		  cq[v][c]=data[v][36+c]; 			//printf("%d\t",data[p][36+c]); 			//printf("%d\t",cq[p][c]); 	   } 	 //	printf("\n");    }     static int vm[40][36]={0};    static int vn[40][36]={0}; //t阶段的初始库容和末库容    double Q[36]={5490.99,5167.74,4979.09,4479.39,4215.9,4972.32,5394.8,5715.45,5782.01,6036.54,8384.3,7269.1,10933.5,11231.05,15756.86,21060.24,16434.75,15703.82,22083.76,30670.07,29849.66,26963.16,37566.78,37049.67,31318.89,21285.04,16822.32,25209.31,17203.41,15313.36,12055.05,8785.44,8863.48,6668.28,6108.31,5249.94};       static double R[40][40][36]={0.0};//下泄流量    static double Rr[40][40][36]={0.0};     for(t= 0; t < 36; t++){         for(i=0;i <40 ;i++){ 			for(q=0;q<31;q++){ 				if(zm[i][t]	== cq[0][q]){ 				vm[i][t]=cq[1][q]; 	  //		 printf("%d\t",vm[i][t]); 				} 				continue; 			} 		 		} 	//	 printf("\n");     }      for(t= 0; t < 36; t++){         for(i=0;i <40 ;i++){ 			for(q=0;q<31;q++){ 				if(zn[i][t]	== cq[0][q]){ 				vn[i][t]=cq[1][q]; 			//	 printf("%d\t",vn[i][t]); 				} 			 				continue; 			} 		 		} 	 //	 printf("\n");     }      //	double y[40][40][36]={0.0};//弃水    //  double ***y;   double ***y = (double***)malloc(40* sizeof(double**));     for(i=0; i<40; i++)     {         y[i] = (double**)malloc(40*sizeof(double*));         for(j=0; j<40; j++)         {             y[i][j] = (double*)malloc(36*sizeof(double));         }     }      //finish creating use p[i][j][k] to access the data       //free the memory      // double *Qse=(double*)malloc(sizeof(double)*57600); 	for(t= 0; t	< 36; t++){          for(i=0;i <40 ;i++){ 			for(c=0;c<40;c++){             R[c][i][t]=vm[i][t]/10.0-vn[c][t]/10.0+Q[t];             if( 98800.0-R[c][i][t]<0.0){ 	//		 Qse[c]= R[c][i][t]-98800.0;             Rr[c][i][t]=90000.0; 			}            else  if(R[c][i][t]-5000.0>=0.0 &&98800.0-R[c][i][t]>=0.0)Rr[c][i][t]=R[c][i][t];             else continue;         //   n[c][i][t]=8.8*Rr[c][i][t]; 	//		printf("%.2f\t",R[c][i][0]); 	//		printf("%.2f\t",Qse[c] ); 			} 	//	 printf("\n"); 		}     // printf("\n");     }   	//	for(c=0;c<40;c++) 	//	{ 	//	 printf("%d\t",vm[0][0]); 	//	  printf("%d\t",vn[c][0]); 	//		printf("%.2f\n",R[c][0][0]);}   		for(t= 0; t	< 36; t++){          for(i=0;i <40 ;i++){ 			for(c=0;c<40;c++){ 				for(j=0;j<851;j++){ 			 				if((int)Rr[c][i][t]==Y[0][j])y[c][i][t]=Y[1][t]; 			 else continue;} 			}          }      }  	static double	n[40][40][36]={0.0}; 	static double	nr[40][40][36]={0.0}; 		for(t= 0; t	< 36; t++){          for(i=0;i <=num[t] ;i++){ 			for(c=0;c<=num[t];c++){ 			n[c][i][t]=8.8*Rr[c][i][t]*((zm[i][t]+zn[c][t])/2-y[c][i][t])*0.0001; 	 		//	printf("%.2f\t",nr[c][i][t] ); 		//	printf("%.2f\t",n[c][i][t] ); 		} 	//	printf("\n"); 	} //	 printf("\n");   } //  printf("%.2f\t",n[c][i][0] );  for(i=0; i<40; i++)     {         for(j=0; j<40; j++)         {             free(y[i][j]);         }     }     for(i=0; i<40; i++)     {         free(y[i]);     }     free(y);   int w,e,r,o,s,d,f,l,m,k,qw,we,er,rt,ty,yu,ui,io,op,pa; int QQ=0,W=0,E=0,RR=0,T=0,YY=0,U=0,I=0,O=0,P=0,A=0,S=0,D=0,F=0,LL=0,M=0,QW=0,WE=0,ER=0,RT=0,TY=0,YU=0,UI=0,IO=0,OP=0,PA=0; double val,valu; double max1=0; double max2=0; double max; for(pa=0;pa<=num[35];pa++){ 	for(op=0;op	<=num[34]; op++){ 		for( io=0; io<=num[33];	io++){ 			for(ui =0;ui <=num[32];	ui++){ 				for(yu =0; yu<=num[31];yu ++){ 					for( ty=0;ty <=num[30];ty ++){ 						for(rt =0;rt <=num[29];rt ++){ 							for(er =0;er <=num[28];	er++){ 								for( we=0;we <=num[27];	we++){ 									for(qw =0;qw <=num[26];qw ++){ 										for(m =0;m <=num[25]; m++){ 										val=n[m][0][25]+n[qw][m][26]+n[we][qw][27]+n[er][we][28]+n[rt][er][29]+n[ty][rt][30]+n[yu][ty][31]+n[ui][yu][32]+n[io][ui][33]+n[op][io][34]+n[pa][op][35]; 											if(val-max1>0.1){ 													max1=val; 													M=m; 													QW=qw; 													WE=we; 													ER=er; 													RT=rt; 													TY=ty; 													YU=yu; 													UI=ui; 													IO=io; 													OP=op; 													PA=pa; 											} 									 										} 									} 								} 							} 						} 					} 				} 			} 		} 	} }   for(f=0;f<=num[14];f++){   for(d=0;d<=num[13];d++){ 	for(s=0;s<=num[12];s++){ 		for(a=0;a<=num[11];a++){ 			for(p=0;p<=num[10];p++){ 				for(o=0;o<=num[9];o++){ 					for(i=0;i<=num[8];i++){ 						for(u=0;u<=num[7];u++){ 							for(k=0;k<=num[6];k++){ 								for(t=0;t<=num[5];t++){ 									for(r=0;r<=num[4];r++){ 										for(e=0;e<=num[3];e++){ 											for(w=0;w<=num[2];w++){ 												for(q=0;q<=num[1];q++){ 													for(l=0;l<=num[0];l++){ 												 													valu=n[l][0][0]+n[q][l][1]+n[w][q][2]+n[e][w][3]+n[r][e][4]+n[t][r][5]+n[k][t][6]+n[u][k][7]+n[i][u][8]+n[o][i][9]+n[p][o][10]+n[a][p][11]+n[s][a][12]+n[d][s][13]+n[f][d][14]; 													if(valu-max2>0.1) { 														max2=valu; 														LL=l; 														QQ=q; 														W=w; 														E=e; 														RR=r; 														T=t; 														YY=k; 														U=u; 														I=i; 														O=o; 														P=p; 														A=s; 														S=s; 														D=d; 														F=f; 													} 										 														} 													} 												} 											} 										} 									} 								} 							} 						} 					} 				} 			} 		} 	}  }   max=max2+n[0][F][15]+n[0][0][16]+n[0][0][17]+n[0][0][18]+n[0][0][19]+n[0][0][20]+n[0][0][21]+n[0][0][22]+n[0][0][23]+n[0][0][24]+max1; printf("%.2f\n",max); printf("%d %d %d %d %d %d %d %d %d %d\n",LL,QQ,W,E,RR,T,YY,U,I,O); printf("%d %d %d %d %d\n",P,A,S,D,F); printf("%d %d %d %d %d %d %d %d %d %d\n",M,QW,WE,ER,RT,TY,YU,UI,IO,OP); printf("%d\n",PA);  }

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

45400	70.92 45500	70.94 45600	70.96 45700	70.98 45800	71 45900	71.02 46000	71.04 46100	71.06 46200	71.08 46300	71.1 46400	71.12 46500	71.14 46600	71.17 46700	71.19 46800	71.21 46900	71.23 47000	71.25 47100	71.27 47200	71.29 47300	71.31 47400	71.33 47500	71.36 47600	71.38 47700	71.4 47800	71.42 47900	71.44 48000	71.46 48100	71.48 48200	71.5 48300	71.52 48400	71.54 48500	71.56 48600	71.59 48700	71.61 48800	71.63 48900	71.65 49000	71.67 49100	71.69 49200	71.71 49300	71.73 49400	71.75 49500	71.77 49600	71.79 49700	71.81 49800	71.83 49900	71.85 50000	71.87 50100	71.89 50200	71.91 50300	71.93 50400	71.95 50500	71.98 50600	72 50700	72.02 50800	72.04 50900	72.06 51000	72.08 51100	72.1 51200	72.12 51300	72.14 51400	72.16 51500	72.18 51600	72.2 51700	72.22 51800	72.24 51900	72.26 52000	72.28 52100	72.3 52200	72.32 52300	72.34 52400	72.36 52500	72.39 52600	72.41 52700	72.43 52800	72.45 52900	72.47 53000	72.49 53100	72.51 53200	72.53 53300	72.55 53400	72.57 53500	72.59 53600	72.61 53700	72.63 53800	72.65 53900	72.67 54000	72.69 54100	72.71 54200	72.73 54300	72.75 54400	72.77 54500	72.79 54600	72.81 54700	72.83 54800	72.85 54900	72.87 55000	72.89 55100	72.91 55200	72.93 55300	72.95 55400	72.97 55500	72.99 55600	73.01 55700	73.03 55800	73.05 55900	73.07 56000	73.09 56100	73.11 56200	73.13 56300	73.15 56400	73.17 56500	73.19 56600	73.21 56700	73.23 56800	73.25 56900	73.27 57000	73.29 57100	73.31 57200	73.33 57300	73.35 57400	73.37 57500	73.39 57600	73.41 57700	73.43 57800	73.45 57900	73.47 58000	73.49 58100	73.51 58200	73.53 58300	73.55 58400	73.57 58500	73.6 58600	73.62 58700	73.64 58800	73.66 58900	73.68 59000	73.7 59100	73.72 59200	73.74 59300	73.76 59400	73.78 59500	73.8 59600	73.82 59700	73.84 59800	73.86 59900	73.88 60000	73.9 60100	73.92 60200	73.94 60300	73.96 60400	73.98 60500	74 60600	74.02 60700	74.04 60800	74.06 60900	74.08 61000	74.1 61100	74.12 61200	74.14 61300	74.16 61400	74.19 61500	74.21 61600	74.23 61700	74.25 61800	74.28 61900	74.3 62000	74.32 62100	74.34 62200	74.36 62300	74.38 62400	74.4 62500	74.42 62600	74.44 62700	74.46 62800	74.48 62900	74.5 63000	74.52 63100	74.54 63200	74.56 63300	74.58 63400	74.6 63500	74.62 63600	74.65 63700	74.67 63800	74.69 63900	74.71 64000	74.73 64100	74.75 64200	74.77 64300	74.79 64400	74.82 64500	74.84 64600	74.86 64700	74.88 64800	74.9 64900	74.92 65000	74.94 65100	74.96 65200	74.98 65300	75 65400	75.02 65500	75.04 65600	75.06 65700	75.08 65800	75.1 65900	75.12 66000	75.14 66100	75.16 66200	75.18 66300	75.2 66400	75.22 66500	75.24 66600	75.26 66700	75.28 66800	75.3 66900	75.32 67000	75.34 67100	75.36 67200	75.38 67300	75.4 67400	75.42 67500	75.44 67600	75.46 67700	75.49 67800	75.51 67900	75.53 68000	75.55 68100	75.57 68200	75.59 68300	75.61 68400	75.63 68500	75.66 68600	75.68 68700	75.7 68800	75.72 68900	75.74 69000	75.76 69100	75.78 69200	75.8 69300	75.82 69400	75.84 69500	75.87 69600	75.89 69700	75.91 69800	75.93 69900	75.95 70000	75.97 70100	75.99 70200	76.01 70300	76.03 70400	76.05 70500	76.07 70600	76.09 70700	76.11 70800	76.13 70900	76.15 71000	76.17 71100	76.19 71200	76.21 71300	76.23 71400	76.25 71500	76.27 71600	76.29 71700	76.31 71800	76.33 71900	76.35 72000	76.37 72100	76.39 72200	76.41 72300	76.43 72400	76.45 72500	76.47 72600	76.49 72700	76.51 72800	76.53 72900	76.55 73000	76.57 73100	76.59 73200	76.61 73300	76.63 73400	76.65 73500	76.67 73600	76.69 73700	76.71 73800	76.73 73900	76.75 74000	76.77 74100	76.79 74200	76.81 74300	76.83 74400	76.85 74500	76.88 74600	76.9 74700	76.92 74800	76.94 74900	76.96 75000	76.98 75100	77 75200	77.02 75300	77.04 75400	77.06 75500	77.08 75600	77.1 75700	77.12 75800	77.14 75900	77.16 76000	77.18 76100	77.2 76200	77.22 76300	77.24 76400	77.26 76500	77.28 76600	77.3 76700	77.32 76800	77.34 76900	77.36 77000	77.38 77100	77.4 77200	77.42 77300	77.44 77400	77.46 77500	77.48 77600	77.5 77700	77.52 77800	77.54 77900	77.56 78000	77.58 78100	77.6 78200	77.62 78300	77.64 78400	77.66 78500	77.68 78600	77.7 78700	77.72 78800	77.74 78900	77.76 79000	77.78 79100	77.8 79200	77.82 79300	77.84 79400	77.86 79500	77.88 79600	77.9 79700	77.92 79800	77.94 79900	77.96 80000	77.98 80100	78 80200	78.02 80300	78.04 80400	78.06 80500	78.08 80600	78.1 80700	78.12 80800	78.14 80900	78.16 81000	78.18 81100	78.2 81200	78.22 81300	78.24 81400	78.26 81500	78.28 81600	78.3 81700	78.32 81800	78.34 81900	78.36 82000	78.38 82100	78.4 82200	78.42 82300	78.44 82400	78.46 82500	78.48 82600	78.5 82700	78.52 82800	78.54 82900	78.56 83000	78.58 83100	78.6 83200	78.62 83300	78.64 83400	78.66 83500	78.68 83600	78.7 83700	78.72 83800	78.74 83900	78.76 84000	78.78 84100	78.8 84200	78.82 84300	78.84 84400	78.86 84500	78.88 84600	78.9 84700	78.92 84800	78.94 84900	78.96 85000	78.98 85100	79 85200	79.02 85300	79.04 85400	79.06 85500	79.08 85600	79.1 85700	79.12 85800	79.14 85900	79.16 86000	79.18 86100	79.2 86200	79.22 86300	79.24 86400	79.26 86500	79.28 86600	79.3 86700	79.32 86800	79.34 86900	79.36 87000	79.38 87100	79.4 87200	79.42 87300	79.44 87400	79.46 87500	79.48 87600	79.5 87700	79.52 87800	79.54 87900	79.56 88000	79.58 88100	79.6 88200	79.62 88300	79.64 88400	79.66 88500	79.68 88600	79.7 88700	79.72 88800	79.74 88900	79.76 89000	79.78 89100	79.8 89200	79.82 89300	79.84 89400	79.86 89500	79.88 89600	79.9 89700	79.92 89800	79.94 89900	79.96 90000	79.98

程序看着一个感觉比较乱： 1. for循环层数也是见过的出现最多的（我想可以通过其他算法或策略减少循环次数，循环出现最多3层为宜），循环层数多了会降低程序的运行效率。 2. 如果注释加多了，反而会起到反作用--不利于代码的阅读和理解，头文件不建议再加注释，将变量定义成见名知义，也可以省略了注释等等； 最后建议分步验证，即要验证最后的结果，就要验证前一步的正确性，如此递归。

这个是 xiayou.txt文件的内容 5000	64.59 5100	64.6 5200	64.6 5300	64.61 5400	64.62 5500	64.62 5600	64.63 5700	64.64 5800	64.65 5900	64.65 6000	64.66 6100	64.67 6200	64.67 6300	64.68 6400	64.69 6500	64.7 6600	64.7 6700	64.71 6800	64.72 6900	64.72 7000	64.73 7100	64.74 7200	64.74 7300	64.75 7400	64.76 7500	64.76 7600	64.77 7700	64.78 7800	64.79 7900	64.79 8000	64.8 8100	64.81 8200	64.81 8300	64.82 8400	64.83 8500	64.84 8600	64.84 8700	64.85 8800	64.86 8900	64.86 9000	64.87 9100	64.88 9200	64.88 9300	64.89 9400	64.9 9500	64.9 9600	64.91 9700	64.92 9800	64.93 9900	64.93 10000	64.94 10100	64.95 10200	64.96 10300	64.97 10400	64.98 10500	64.99 10600	65 10700	65.02 10800	65.03 10900	65.04 11000	65.05 11100	65.06 11200	65.07 11300	65.08 11400	65.09 11500	65.1 11600	65.11 11700	65.12 11800	65.13 11900	65.14 12000	65.15 12100	65.16 12200	65.17 12300	65.18 12400	65.2 12500	65.21 12600	65.22 12700	65.24 12800	65.25 12900	65.26 13000	65.27 13100	65.28 13200	65.29 13300	65.3 13400	65.31 13500	65.32 13600	65.33 13700	65.34 13800	65.35 13900	65.36 14000	65.37 14100	65.381 14200	65.392 14300	65.403 14400	65.414 14500	65.42 14600	65.43 14700	65.44 14800	65.45 14900	65.47 15000	65.48 15100	65.495 15200	65.511 15300	65.52 15400	65.542 15500	65.557 15600	65.573 15700	65.58 15800	65.604 15900	65.62 16000	65.63 16100	65.64 16200	65.66 16300	65.68 16400	65.69 16500	65.7 16600	65.72 16700	65.74 16800	65.75 16900	65.76 17000	65.78 17100	65.8 17200	65.81 17300	65.83 17400	65.84 17500	65.86 17600	65.88 17700	65.89 17800	65.91 17900	65.92 18000	65.94 18100	65.96 18200	65.97 18300	65.98 18400	66 18500	66.02 18600	66.03 18700	66.04 18800	66.06 18900	66.08 19000	66.09 19100	66.1 19200	66.12 19300	66.14 19400	66.15 19500	66.16 19600	66.18 19700	66.2 19800	66.21 19900	66.22 20000	66.24 20100	66.26 20200	66.27 20300	66.29 20400	66.3 20500	66.32 20600	66.33 20700	66.35 20800	66.37 20900	66.38 21000	66.4 21100	66.42 21200	66.43 21300	66.45 21400	66.47 21500	66.48 21600	66.5 21700	66.52 21800	66.54 21900	66.55 22000	66.57 22100	66.59 22200	66.6 22300	66.62 22400	66.63 22500	66.64 22600	66.66 22700	66.67 22800	66.69 22900	66.7 23000	66.72 23100	66.74 23200	66.75 23300	66.77 23400	66.79 23500	66.8 23600	66.82 23700	66.84 23800	66.86 23900	66.87 24000	66.89 24100	66.91 24200	66.92 24300	66.94 24400	66.95 24500	66.97 24600	66.99 24700	67 24800	67.02 24900	67.03 25000	67.05 25100	67.07 25200	67.08 25300	67.1 25400	67.12 25500	67.14 25600	67.15 25700	67.17 25800	67.19 25900	67.2 26000	67.22 26100	67.24 26200	67.25 26300	67.27 26400	67.28 26500	67.3 26600	67.32 26700	67.33 26800	67.35 26900	67.36 27000	67.38 27100	67.4 27200	67.41 27300	67.43 27400	67.44 27500	67.46 27600	67.48 27700	67.49 27800	67.51 27900	67.52 28000	67.54 28100	67.56 28200	67.57 28300	67.59 28400	67.6 28500	67.62 28600	67.64 28700	67.65 28800	67.67 28900	67.68 29000	67.7 29100	67.72 29200	67.73 29300	67.75 29400	67.77 29500	67.78 29600	67.8 29700	67.82 29800	67.83 29900	67.85 30000	67.87 30100	67.89 30200	67.91 30300	67.93 30400	67.94 30500	67.96 30600	67.98 30700	68 30800	68.02 30900	68.04 31000	68.06 31100	68.08 31200	68.1 31300	68.12 31400	68.14 31500	68.16 31600	68.18 31700	68.2 31800	68.22 31900	68.24 32000	68.26 32100	68.28 32200	68.3 32300	68.32 32400	68.34 32500	68.36 32600	68.37 32700	68.39 32800	68.41 32900	68.43 33000	68.45 33100	68.47 33200	68.49 33300	68.51 33400	68.53 33500	68.54 33600	68.56 33700	68.58 33800	68.6 33900	68.62 34000	68.64 34100	68.66 34200	68.68 34300	68.7 34400	68.72 34500	68.74 34600	68.75 34700	68.77 34800	68.79 34900	68.81 35000	68.83 35100	68.85 35200	68.87 35300	68.89 35400	68.91 35500	68.93 35600	68.95 35700	68.97 35800	68.99 35900	69.01 36000	69.03 36100	69.05 36200	69.07 36300	69.09 36400	69.11 36500	69.12 36600	69.14 36700	69.16 36800	69.18 36900	69.2 37000	69.22 37100	69.24 37200	69.26 37300	69.28 37400	69.3 37500	69.32 37600	69.33 37700	69.35 37800	69.37 37900	69.39 38000	69.41 38100	69.43 38200	69.45 38300	69.47 38400	69.49 38500	69.51 38600	69.53 38700	69.55 38800	69.57 38900	69.59 39000	69.61 39100	69.63 39200	69.65 39300	69.67 39400	69.68 39500	69.7 39600	69.72 39700	69.74 39800	69.76 39900	69.78 40000	69.8 40100	69.82 40200	69.84 40300	69.86 40400	69.88 40500	69.9 40600	69.93 40700	69.95 40800	69.97 40900	69.99 41000	70.01 41100	70.03 41200	70.05 41300	70.07 41400	70.09 41500	70.12 41600	70.14 41700	70.16 41800	70.18 41900	70.2 42000	70.22 42100	70.24 42200	70.26 42300	70.28 42400	70.3 42500	70.32 42600	70.34 42700	70.36 42800	70.38 42900	70.4 43000	70.42 43100	70.44 43200	70.46 43300	70.48 43400	70.5 43500	70.52 43600	70.55 43700	70.57 43800	70.59 43900	70.61 44000	70.63 44100	70.65 44200	70.67 44300	70.69 44400	70.71 44500	70.74 44600	70.76 44700	70.78 44800	70.8 44900	70.82 45000	70.84 45100	70.86 45200	70.88 45300	70.9

这个是data.txt里面的内容 175 155 175 155 175 155 175 155 175 155 175 155 175 145 175 145 175 145 175 145 175 145 175 145 170 145 165 145 155 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 145 155 145 165 145 175 155 175 155 175 155 175 155 175 155 175 155 175 155 175 155 175 155 145 171500  146 176446  147 181428  148 186477  149 191624  150 196900  151 202510  152 208553  153 214902  154 221427  155 228000  156 234597  157 241285  158 248076  159 254977  160 262000  161 269206  162 276641  163 284294  164 292151  165 300200  166 308463  167 316973  168 325732  169 334740  170 344000  171 353483  172 363146  173 372967  174 382925  175 393000

#include<stdio.h>//定义输入／输出函数  #include<stdlib.h>//定义杂项函数及内存分配函数  #include<string.h>//字符串处理  #include<math.h>//定义数学函数   #define N 2   //2列 #define L 1000  //100行      int main(int argc, char *argv[]) {        int i,j,t,c,p,q; 	int zm[40][36]={0};//初水位  	int zn[40][36]={0};//末水位  	//int cq[p][c];//水位库容  //	double E[80][36];//余留期效益值 //	double n[i][t];//t-1到t阶段的最优出力期望 	  const char file_name[50] = "data.txt"; 	      FILE *fp;     int data[N][L] = {0};   //二维数组     int index[N] = {0};   //二维数组列下标     double temp;       int v, u;     int count = 0;  //计数器，记录已读出的浮点数     if((fp=fopen(file_name, "rb")) == NULL) {         //printf("请确认文件(%s)是否存在!\n", file_name);         exit(1);     }     while(1==fscanf(fp, "%lf", &temp)) {         data[count%N][(index[count%N])++] = temp;         count++;     }     for(v = 0; v < N; v++) {                for(u = 0; u < index[v]; u++) {     // printf("%d",data[v][u]) ;  //data[v][u];         }       //  printf("\n");     }     fclose(fp);      const char file[50] = "xiayou.txt";      FILE* lfp;     if((lfp=fopen(file, "rb")) == NULL)     {         printf("Cannot open this filefp1\n");         exit(0);     }    int res=0;     double  Y[2][851];     for (i = 0; i < 2; i++)     {         for (j = 0; j < 851; j++)         {             res = fscanf_s(lfp, "%lf", &Y[i][j]);                     //    printf("%lf \n", Y[i][j]);                       }              }     fclose(lfp);               int a=0,num[36]={0};         for(u = 0; u < 36; u++) { 		   // printf("%d\t",data[0][u]);		     		    //printf("%d\t",data[1][u]); 			//printf("\n"); 		  num[a]=data[0][u]-data[1][u]; 		  a++; 		          }  // for(a= 0; a < 36; a++)    //printf("%d\n",num[a]);        for(t= 0; t < 36; t++){         for(i=0;i <=num[t] ;i++){   		zn[i][t] =data[0][t];   		data[0][t]--; 	//	printf("%d\t",zn[i][t]); 				 			//	printf("%d\t",data[0][t]);	 			//	printf("\n");   	      }      	// printf("\n");   }	      //	for(t= 0; t < 36; t++){    //      for(i=0;i <=num[t] ;i++){      	//  printf("%d\t",zn[i][t]); //		   } 	//	 printf("\n"); //	} 	 	      zm[0][0]=175;     for(t= 1; t < 36; t++){   //	printf("%d\t",num[t]);      //printf("%d\t",data[0][t]);	 //	printf("\n");         for(i=0;i <=num[t-1] ;i++){   		zm[i][t] =zn[i][t-1];   		    //   printf("%d\t",zn[i][t]); 			//	printf("%d\t",zm[i][t]); 				 			//	printf("%d\t",data[0][t]);	 			//	printf("\n");   	      }      	// printf("\n");   }	    //  for(t= 0; t < 36; t++){  //     for(i=0;i <40 ;i++){ //     	printf("%d\t",zm[i][t]); //		 }  //    	 printf("\n"); //  }	       int cq[2][31]={0};    for(v=0;v<2;v++){    	for(c=0;c<31;c++){    		  cq[v][c]=data[v][36+c];    			//printf("%d\t",data[p][36+c]);	 			//printf("%d\t",cq[p][c]); 	   } 	 // printf("\n");    }        	int vm[40][36]={0}; 	int vn[40][36]={0};	//t阶段的初始库容和末库容	    double Q[36]={5490.99,5167.74,4979.09,4479.39,4215.9,4972.32,5394.8,5715.45,5782.01,6036.54,8384.3,7269.1,10933.5,11231.05,15756.86,21060.24,16434.75,15703.82,22083.76,30670.07,29849.66,26963.16,37566.78,37049.67,31318.89,21285.04,16822.32,25209.31,17203.41,15313.36,12055.05,8785.44,8863.48,6668.28,6108.31,5249.94};             double R[40][40][36]={0.0};//下泄流量     double Rr[40][40][36]={0.0};     for(t= 0; t < 36; t++){         for(i=0;i <40 ;i++){         	for(q=0;q<31;q++){         		if(zm[i][t] == cq[0][q]){         		vm[i][t]=cq[1][q];	       //  		 printf("%d\t",vm[i][t]);  				}	 				continue; 			}         	   		} 	//   printf("\n");       }          for(t= 0; t < 36; t++){         for(i=0;i <40 ;i++){         	for(q=0;q<31;q++){         		if(zn[i][t] == cq[0][q]){         		vn[i][t]=cq[1][q];	         	//	 printf("%d\t",vn[i][t]); 				} 				 				continue; 			}         	   		} 	 //  printf("\n");       }        	   //	double y[40][40][36]={0.0};//弃水     //  double ***y;      double ***y = (double***)malloc(40* sizeof(double**));        for(i=0; i<40; i++)        {              y[i] = (double**)malloc(40*sizeof(double*));            for(j=0; j<40; j++)            {                y[i][j] = (double*)malloc(36*sizeof(double));            }        }          //finish creating use p[i][j][k] to access the data                  //free the memory                  // double *Qse=(double*)malloc(sizeof(double)*57600);   	for(t= 0; t < 36; t++){           for(i=0;i <40 ;i++){          	for(c=0;c<40;c++){             R[c][i][t]=vm[i][t]/10.0-vn[c][t]/10.0+Q[t];             if( 98800.0-R[c][i][t]<0.0){     //   	 Qse[c]= R[c][i][t]-98800.0;            	Rr[c][i][t]=90000.0; 			}            else  if(R[c][i][t]-5000.0>=0.0 &&98800.0-R[c][i][t]>=0.0)Rr[c][i][t]=R[c][i][t];             else continue;         //   n[c][i][t]=8.8*Rr[c][i][t]; 	//		printf("%.2f\t",R[c][i][0]); 	//		printf("%.2f\t",Qse[c] ); 			}     //   printf("\n");  	   		}     // printf("\n");     }                   //	for(c=0;c<40;c++)     //	{  	//	 printf("%d\t",vm[0][0]); 	//	  printf("%d\t",vn[c][0]);     //		printf("%.2f\n",R[c][0][0]);}               	for(t= 0; t < 36; t++){           for(i=0;i <40 ;i++){          	for(c=0;c<40;c++){          		for(j=0;j<851;j++){ 				         		if((int)Rr[c][i][t]==Y[0][j])y[c][i][t]=Y[1][t];          	 else continue;}          	}          }      }        	double n[40][40][36]={0.0};   	double nr[40][40][36]={0.0};     	for(t= 0; t < 36; t++){           for(i=0;i <=num[t] ;i++){          	for(c=0;c<=num[t];c++){          	n[c][i][t]=8.8*Rr[c][i][t]*((zm[i][t]+zn[c][t])/2-y[c][i][t])*0.0001; 		 		//	printf("%.2f\t",nr[c][i][t] );	 		//	printf("%.2f\t",n[c][i][t] );	 		}  	//	printf("\n");  	} //	 printf("\n");    } //  printf("%.2f\t",n[c][i][0] );    for(i=0; i<40; i++)      {         for(j=0; j<40; j++)          {                free(y[i][j]);            }        }            for(i=0; i<40; i++)        {                free(y[i]);        }        free(y);         int w,e,r,o,s,d,f,l,m,k,qw,we,er,rt,ty,yu,ui,io,op,pa; int QQ=0,W=0,E=0,RR=0,T=0,YY=0,U=0,I=0,O=0,P=0,A=0,S=0,D=0,F=0,LL=0,M=0,QW=0,WE=0,ER=0,RT=0,TY=0,YU=0,UI=0,IO=0,OP=0,PA=0; double val,valu; double max1=0; double max2=0; double max; for(pa=0;pa<=num[35];pa++){ 	for(op=0;op <=num[34]; op++){ 		for( io=0; io<=num[33]; io++){ 			for(ui =0;ui <=num[32]; ui++){ 				for(yu =0; yu<=num[31];yu ++){ 					for( ty=0;ty <=num[30];ty ++){ 						for(rt =0;rt <=num[29];rt ++){ 							for(er =0;er <=num[28]; er++){ 								for( we=0;we <=num[27]; we++){ 									for(qw =0;qw <=num[26];qw ++){ 										for(m =0;m <=num[25]; m++){ 										val=n[m][0][25]+n[qw][m][26]+n[we][qw][27]+n[er][we][28]+n[rt][er][29]+n[ty][rt][30]+n[yu][ty][31]+n[ui][yu][32]+n[io][ui][33]+n[op][io][34]+n[pa][op][35]; 											if(val-max1>0.1){ 													max1=val; 									             	M=m; 									             	QW=qw; 									             	WE=we; 									             	ER=er; 									             	RT=rt; 									             	TY=ty; 									             	YU=yu; 									             	UI=ui; 									             	IO=io; 									               	OP=op; 									             	PA=pa; 											} 										 										} 									} 								} 							} 						} 					} 				} 			} 		} 	} }   for(f=0;f<=num[14];f++){   for(d=0;d<=num[13];d++){ 	for(s=0;s<=num[12];s++){ 		for(a=0;a<=num[11];a++){ 			for(p=0;p<=num[10];p++){ 				for(o=0;o<=num[9];o++){ 					for(i=0;i<=num[8];i++){ 						for(u=0;u<=num[7];u++){ 							for(k=0;k<=num[6];k++){ 								for(t=0;t<=num[5];t++){ 									for(r=0;r<=num[4];r++){ 										for(e=0;e<=num[3];e++){ 											for(w=0;w<=num[2];w++){ 												for(q=0;q<=num[1];q++){ 													for(l=0;l<=num[0];l++){ 												        													valu=n[l][0][0]+n[q][l][1]+n[w][q][2]+n[e][w][3]+n[r][e][4]+n[t][r][5]+n[k][t][6]+n[u][k][7]+n[i][u][8]+n[o][i][9]+n[p][o][10]+n[a][p][11]+n[s][a][12]+n[d][s][13]+n[f][d][14]; 												    if(valu-max2>0.1) { 												    	max2=valu; 													    LL=l; 												      	QQ=q; 													    W=w; 												     	E=e; 												        RR=r; 												     	T=t; 												    	YY=k; 												    	U=u; 												    	I=i; 												     	O=o; 												     	P=p; 												     	A=s; 												     	S=s; 												     	D=d; 												     	F=f;		 													}    												 														} 													} 												} 											} 										} 									} 								} 							} 						} 					} 				} 			} 		} 	}  }   max=max2+n[0][F][15]+n[0][0][16]+n[0][0][17]+n[0][0][18]+n[0][0][19]+n[0][0][20]+n[0][0][21]+n[0][0][22]+n[0][0][23]+n[0][0][24]+max1; printf("%.2f\n",max); printf("%d %d %d %d %d %d %d %d %d %d\n",LL,QQ,W,E,RR,T,YY,U,I,O); printf("%d %d %d %d %d\n",P,A,S,D,F); printf("%d %d %d %d %d %d %d %d %d %d\n",M,QW,WE,ER,RT,TY,YU,UI,IO,OP); printf("%d\n",PA);  }   程序之前运行到259行都是正确的，可以输出n[][][]的值，但是加上后面两个循环以后就不能输出了


Question: 得到函数的机器码，用函数指针执行的问题

现在的系统下， 一般都开了 DEP， 栈啊， 数据段啊啥的通常都是不可运行的， 你 mprotect  改下内存保护应该就可以了。

我认为是不可以的，你用mmap试一下，如果能够实现，那我也学习了。

引用 4 楼 Wang_926498 的回复:[quote=引用 3 楼 cfjtaishan 的回复:] [quote=引用 2 楼 Wang_926498 的回复:] [quote=引用 1 楼 cfjtaishan 的回复:] 指针变量占用的字节数是固定的，比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针，那么也应该是4个字节才对。 正确的做法是，将函数的地址赋值给fp，即在栈上给你要执行的函数的栈地址赋值给fp. 那个数组是我用objdump反汇编swap函数得到的机器码，我想用那个函数指针执行数组里面的机器码，请问这种情况下需要改什么呢？unsigned char改为unsigned int？我改过了，还是一样的错误……[/quote] 指向函数不会像执行输出数组那么简单吧。  fp = (void (*)(int *,int *))machineCode; 这句就是将数组的前4个字节的值赋值给了fp。[/quote] 我看书发现了错误，machineCode位于数据段，没有执行权限，需要用mmap分配空间，然后把机器码复制过去，这样便能够执行了，并不是您提到的格式问题，谢谢您的回答。[/quote] 直接把数组以强制类型转换的形式赋值给函数指针变量，这样就是类型就是不对的。 函数是在堆栈上执行的，你是用mmap是不行的，我的理解mmap是申请共享内存，并且这个内存是在内核空间里申请的。 建议这个问题最好看一下，编译，加载的过程。

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

引用 3 楼 cfjtaishan 的回复:[quote=引用 2 楼 Wang_926498 的回复:] [quote=引用 1 楼 cfjtaishan 的回复:] 指针变量占用的字节数是固定的，比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针，那么也应该是4个字节才对。 正确的做法是，将函数的地址赋值给fp，即在栈上给你要执行的函数的栈地址赋值给fp. 那个数组是我用objdump反汇编swap函数得到的机器码，我想用那个函数指针执行数组里面的机器码，请问这种情况下需要改什么呢？unsigned char改为unsigned int？我改过了，还是一样的错误……[/quote] 指向函数不会像执行输出数组那么简单吧。  fp = (void (*)(int *,int *))machineCode; 这句就是将数组的前4个字节的值赋值给了fp。[/quote] 我看书发现了错误，machineCode位于数据段，没有执行权限，需要用mmap分配空间，然后把机器码复制过去，这样便能够执行了，并不是您提到的格式问题，谢谢您的回答。

引用 2 楼 Wang_926498 的回复:[quote=引用 1 楼 cfjtaishan 的回复:] 指针变量占用的字节数是固定的，比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针，那么也应该是4个字节才对。 正确的做法是，将函数的地址赋值给fp，即在栈上给你要执行的函数的栈地址赋值给fp. 那个数组是我用objdump反汇编swap函数得到的机器码，我想用那个函数指针执行数组里面的机器码，请问这种情况下需要改什么呢？unsigned char改为unsigned int？我改过了，还是一样的错误……[/quote] 指向函数不会像执行输出数组那么简单吧。  fp = (void (*)(int *,int *))machineCode; 这句就是将数组的前4个字节的值赋值给了fp。

引用 1 楼 cfjtaishan 的回复:指针变量占用的字节数是固定的，比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针，那么也应该是4个字节才对。 正确的做法是，将函数的地址赋值给fp，即在栈上给你要执行的函数的栈地址赋值给fp. 那个数组是我用objdump反汇编swap函数得到的机器码，我想用那个函数指针执行数组里面的机器码，请问这种情况下需要改什么呢？unsigned char改为unsigned int？我改过了，还是一样的错误……