Question: 分别统计字母 数字 空格和其他的个数

将 if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) 写成这样 if(('a'<=c&&c<='z')||('A'<=c&&c<='Z')) 是不是可读性更好更不易出错呢？

出不来是因为循环条件的问题，当没有遇到空字符时，循环是不会停下来的，键盘上输的都是有字符的，所以程序一直在等待输入，停不下来，所以出不来。你可以改成别的不能显示的ASCII字符当作停止条件，例如’\t‘(水平制表符)、'\n'(换行符)。   引用 1 楼 qq423399099 的回复:两个错误： 1.while((c=getchar())!='\0')应该是while((c=getchar())!='\n') 2.if(c>='a'&&c<='z'||c>='A'&&c<='Z')应该是if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))  #include<stdio.h> int main() { 	char c; 	int m=0,n=0,k=0,q=0; 	printf("请输入一串字符\n"); 	while((c=getchar())!='\n') 	{ 		if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) 			m++; 		else 			if(c>='0'&&c<='9') 				n++; 			else 				if(c==' ') 					k++; 				else 					q++; 	} 	printf("%d %d %d %d\n",m,n,k,q); 	return 0; }  if(c>='a'&&c<='z'||c>='A'&&c<='Z')这条语句没有错误，>=、<=的优先级大于&&，&&的优先级大于||

引用 1 楼 qq423399099 的回复:两个错误： 1.while((c=getchar())!='\0')应该是while((c=getchar())!='\n') 2.if(c>='a'&&c<='z'||c>='A'&&c<='Z')应该是if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))  #include<stdio.h> int main() { 	char c; 	int m=0,n=0,k=0,q=0; 	printf("请输入一串字符\n"); 	while((c=getchar())!='\n') 	{ 		if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) 			m++; 		else 			if(c>='0'&&c<='9') 				n++; 			else 				if(c==' ') 					k++; 				else 					q++; 	} 	printf("%d %d %d %d\n",m,n,k,q); 	return 0; }   版主为什么(c=getchar())!='\n'不是'\0'’呢？


Question: 关于交换节点的问题

_DEBUG_ASSERT_可以不要 VAR_FILL_VALUE表示一定不正确的下标，指针版本改为NULL

对于双向链表，交换位置最高需要写入6个指针，交换值需要写入3倍值长度的字节 所以当你的元素大于8字节的时候，交换位置更好  	void swap (INDEX index1 ,INDEX index2) { 		_DEBUG_ASSERT_ (index1 != VAR_FILL_VALUE && index2 != VAR_FILL_VALUE) ; 		if (mList[index2].next == index1) 			_SWAP_ (index1 ,index2) ; 		if (mList[index1].next == index2) { 			(mList[index1].prev != VAR_FILL_VALUE ? mList[mList[index1].prev].next : mFirst) = index2 ; 			(mList[index2].next != VAR_FILL_VALUE ? mList[mList[index2].next].prev : mLast) = index1 ; 			mList[index1].next = mList[index2].next ; 			mList[index2].prev = mList[index1].prev ; 			mList[index1].prev = index2 ; 			mList[index2].next = index1 ; 		} else { 			(mList[index1].prev != VAR_FILL_VALUE ? mList[mList[index1].prev].next : mFirst) = index2 ; 			(mList[index2].prev != VAR_FILL_VALUE ? mList[mList[index2].prev].next : mFirst) = index1 ; 			(mList[index1].next != VAR_FILL_VALUE ? mList[mList[index1].next].prev : mLast) = index2 ; 			(mList[index2].next != VAR_FILL_VALUE ? mList[mList[index2].next].prev : mLast) = index1 ; 			_SWAP_ (mList[index1].prev ,mList[index2].prev) ; 			_SWAP_ (mList[index1].next ,mList[index2].next) ; 		} 	}  如果你是要用指针的话，比如mList[index1].prev改成pointer1->prev就行了


Question: 如何将TXT文件里面的数据存入BIN文件？

不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！

引用 1 楼 zhao4zhong1 的回复:仅供参考：#include <stdio.h> #include <string.h> #include <conio.h> FILE *fi,*fo; unsigned int n; int c; //------------------------------------------------------- void main(int argc,char *argv[]) {     if (argc<3) {         cprintf("Bin2Hex srcfile desfile");         return;     }     if ((fi=fopen(argv[1],"rb"))==NULL) {         cprintf("Can not find file %s",argv[1]);         return;     }     if ((fo=fopen(argv[2],"w"))==NULL) {         fclose(fi);         cprintf("Can not create file %s",argv[2]);         return;     }     n=0;     while (1) {         c=fgetc(fi);         if (EOF==c) break;         n++;         if (1==n)        fprintf(fo,  "0x%02X",c);         else {             if (1==n%16) fprintf(fo,"\n0x%02X",c);             else         fprintf(fo, ",0x%02X",c);         }     }     fcloseall();     cprintf("OK to Bin2Hex %u bytes.",n); }  #include <stdio.h> #include <string.h> #include <conio.h> FILE *fi,*fo; int r; unsigned int n,c; long offset; //------------------------------------------------------- void main(int argc,char *argv[]) {     if (argc<3) {         cprintf("Hex2Bin srcfile desfile");         return;     }     if ((fi=fopen(argv[1],"rb"))==NULL) {         cprintf("Can not find file %s",argv[1]);         return;     }     if ((fo=fopen(argv[2],"wb"))==NULL) {         fclose(fi);         cprintf("Can not create file %s",argv[2]);         return;     }     n=0;     while (1) {         offset=ftell(fi);         r=fscanf(fi,"%2x",&c);         if (EOF==r) break;//         if (1==r) {             fputc(c,fo);             n++;         } else {//0==r             fseek(fi,offset,SEEK_SET);//因为VC6的Release版及其VC7,8,9,10,...版的fscanf未按约定保持offset不变，所以此处必须恢复offset             r=fgetc(fi);             if (EOF==r) break;//         }     }     fcloseall();     cprintf("OK to Hex2Bin %d bytes.",n); }  谢谢您赵老师！如果我增加TXT里面的数据，程序需要改吗？是不是这样写也可以啊？

再供参考：#include <stdio.h> #include <stdlib.h> char s[]="00000000000000000000000000000001"          "00000000000000000000000000000010"          "00000000000000000000000000000011"; char *p; char *ep; char c; unsigned long v; FILE *f; void main() {     f=fopen("data.bin","wb");     p=s;     while (1) {         if (0==*p) break;         ep=p+32;         c=*ep;         *ep=0;         v=strtoul(p,&ep,2);         fwrite(&v,sizeof(v),1,f);         *ep=c;         p+=32;     }     fclose(f); }


标准就这么规定的  同理，一个int*指针+1移动的距离是4而不是1

Pointer Arithmetic Additive operations involving a pointer and an integer give meaningful results only if the pointer operand addresses an array member and the integer value produces an offset within the bounds of the same array. When the integer value is converted to an address offset, the compiler assumes that only memory positions of the same size lie between the original address and the address plus the offset.  This assumption is valid for array members. By definition, an array is a series of values of the same type; its elements reside in contiguous memory locations. However, storage for any types except array elements is not guaranteed to be filled by the same type of identifiers. That is, blanks can appear between memory positions, even positions of the same type. Therefore, the results of adding to or subtracting from the addresses of any values but array elements are undefined.  Similarly, when two pointer values are subtracted, the conversion assumes that only values of the same type, with no blanks, lie between the addresses given by the operands.

引用 1楼小灸舞 的回复:因为C语言的标准中规定了 加法与减法运算对于地址的操作和对于值的操作是不同的，标准中有这样一段话： When two pointers to members of the same array object are subtracted, the difference is divided by the size of a member. The result represents the difference of the subscripts of the two array members.  翻译过来就是：当同一个数组的两个成员的指针相减时，其差值为：地址值的差，再除以一个数组成员的size。这个结果代表了两个指针对应元素的下标之差。涨知识

不管什么数组这个结果固定为1

引用 1 楼 小灸舞的回复:因为C语言的标准中规定了 加法与减法运算对于地址的操作和对于值的操作是不同的，标准中有这样一段话： When two pointers to members of the same array object are subtracted, the difference is divided by the size of a member. The result represents the difference of the subscripts of the two array members.  翻译过来就是：当同一个数组的两个成员的指针相减时，其差值为：地址值的差，再除以一个数组成员的size。这个结果代表了两个指针对应元素的下标之差。 原来如此。讲得很好，我懂了


Question: c语言编写有限元程序，二维数组指针问题和总体矩阵合成问题，见100,101行标注

搜“内存池”

引用 11 楼 lm_whales的回复:建议不释放内存，而是重新利用上次分配的 最好循环外边分配释放 把二级指针传递到函数里面使用就好 你这里，没有必要反复分配释放 除非每次分配的内存大小不一致，不建议反复分配释放 您的意思是说每个循环指针分配的地址相同，就是改变了存储的数值，这样一个指针一共占用了5*5个double，循环一次重新赋值一次所以不用释放，是这样理解吗

引用 4 楼 user-3 的回复:检查使用分配的内存有没越界，否则可能破坏了堆，在释放时会出错指针的释放函数调用有没有问题呢 deleteptd(T1,rows);

引用 9 楼 lm_whales 的回复:1）内存分配，可以一次分配，永久使用 2）考虑到你的代码中很多1，2，3，4 建议 保留1234 只是要多份配 一个数组，这样改动最小，代码一致性好  建议改成这样吧： ptd = (double **)malloc(5 * sizeof(double *));     if (NULL == ptd) exit(1);     for (i = 0; i <5; i++)     {         ptd[i] = (double *)malloc(5 * sizeof(double));         if (NULL == ptd[i]) exit(1);     } 谢谢，每循环一次释放一次内存要怎样做呢，现在我可以出某一次的4*4矩阵，我希望在循环一次后重新利用这个指针再返回下一个4*4矩阵，释放T1[p][q]一共16个放在101行到119行后面可以吗，这16行编译还是出错,是不是不是因为没有释放内存引起的

检查使用分配的内存有没越界，否则可能破坏了堆，在释放时会出错

引用 2 楼 lm_whales 的回复:第18～22 行 for (i = 1; i <= 4; i++) //为何是1～4 不应该是 0～4吗？     {         ptd[i] = (double *)malloc(5 * sizeof(double));         if (NULL == ptd[i]) exit(1);     } 引用 2 楼 lm_whales 的回复:第18～22 行 for (i = 1; i <= 4; i++) //为何是1～4 不应该是 0～4吗？     {         ptd[i] = (double *)malloc(5 * sizeof(double));         if (NULL == ptd[i]) exit(1);     } 恩，这个我刚刚检查也发现了，掌握的知识很少，没有定义i=0返回值为1是不是就是说这一行全都是1。因为我为了四节点看着方便都从1开始计的，改过了还是不行呀出现了“ 0xC0000005:  读取位置 0xFEEEFEF6 时发生访问冲突。”

double **function(double b1, double c1, double d1, double a2, double b2, double c2, double d2, double xi, double eta) { 	double **ptd; 	int m, n; 	int i; 	double pi = 3.1415926; 	double y = 0.25*(a2 + b2*xi + c2*eta + d2*xi*eta); 	double jacobi[3][3] = { 0 }; 	double partial_xi[5] = { 0 }; 	double partial_eta[5] = { 0 }; 	double partial_x[5] = { 0 }; 	double partial_y[5] = { 0 }; 	double deter; 	double phi[5] = { 0, 0.25*(1 - xi)*(1 - eta), 0.25*(1 + xi)*(1 - eta), 0.25*(1 + xi)*(1 + eta), 0.25*(1 - xi)*(1 + eta) }; 	double fun[5][5]; 	ptd = (double **)malloc(5 * sizeof(double *)); 	if (NULL == ptd) exit(1); 	for (i = 1; i <= 4; i++) 	{ 		ptd[i] = (double *)malloc(5 * sizeof(double)); 		if (NULL == ptd[i]) exit(1); 	} 	jacobi[1][1] = 0.25*(b1 + d1*eta); 	jacobi[1][2] = 0.25*(b2 + d2*eta); 	jacobi[2][1] = 0.25*(c1 + d1*xi); 	jacobi[2][2] = 0.25*(c2 + d2*xi); 	deter = jacobi[1][1] * jacobi[2][2] - jacobi[1][2] * jacobi[2][1];  	partial_xi[1] = -1.0 / 4 * (1 - eta); 	partial_xi[2] = 1.0 / 4 * (1 - eta); 	partial_xi[3] = 1.0 / 4 * (1 + eta); 	partial_xi[4] = -1.0 / 4 * (1 + eta); 	partial_eta[1] = -1.0 / 4 * (1 - xi); 	partial_eta[2] = -1.0 / 4 * (1 + xi); 	partial_eta[3] = 1.0 / 4 * (1 + xi); 	partial_eta[4] = 1.0 / 4 * (1 - xi); 	partial_x[1] = 1.0 / deter*(jacobi[2][2] * partial_xi[1] - jacobi[1][2] * partial_eta[1]); 	partial_x[2] = 1.0 / deter*(jacobi[2][2] * partial_xi[2] - jacobi[1][2] * partial_eta[2]); 	partial_x[3] = 1.0 / deter*(jacobi[2][2] * partial_xi[3] - jacobi[1][2] * partial_eta[3]); 	partial_x[4] = 1.0 / deter*(jacobi[2][2] * partial_xi[4] - jacobi[1][2] * partial_eta[4]); 	partial_y[1] = 1.0 / deter*(jacobi[1][1] * partial_eta[1] - jacobi[2][1] * partial_xi[1]); 	partial_y[2] = 1.0 / deter*(jacobi[1][1] * partial_eta[2] - jacobi[2][1] * partial_xi[2]); 	partial_y[3] = 1.0 / deter*(jacobi[1][1] * partial_eta[3] - jacobi[2][1] * partial_xi[3]); 	partial_y[4] = 1.0 / deter*(jacobi[1][1] * partial_eta[4] - jacobi[2][1] * partial_xi[4]); 	for (m = 1; m <= 4; m++) 	for (n = 1; n <= 4; n++) 	{ 		fun[m][n] = 2 * pi*((partial_x[m] * partial_x[n] + partial_y[m] * partial_y[n])*y + 2 * phi[m] * partial_y[n])*deter; 		ptd[m][n] = fun[m][n];  	} 	return(ptd); }  void deleteptd(double **ptd, int rows) { 	int i;  	for (i = 0; i <= rows; i++) 	{ 		free(ptd[i]); 	} 	free(ptd); }

引用 7 楼 lm_whales 的回复:指针，有必要初始化为0（nullptr） 除非你知道怎么回事 初始化为nullptr的指针，在应用中，如果不检查是否空指针。 等于事情只作了一半，跟没初始化为零区别不大（除了释放内存） 野指针固然不可访问（指向的对象），空指针也不应该去胡乱访问 我改变了长度ptd = (double **)malloc(4 * sizeof(double *)); 	if (NULL == ptd) exit(1); 	for (i = 0; i < 4; i++) 	{ 		ptd[i] = (double *)malloc(4 * sizeof(double)); 		if (NULL == ptd[i]) exit(1); 	} 这样是不是不存在野指针了，还是说要进行 指针初始化，这个指针我希望循环使用，每次获得一个4*4数组，烦请您明示

for (i = 0; i <= rows; i++)     {         free(ptd[i]);     }   引用 3 楼 sbl0911 的回复:[quote=引用 2 楼 lm_whales 的回复:] 第18～22 行 for (i = 1; i <= 4; i++) //为何是1～4 不应该是 0～4吗？     {         ptd[i] = (double *)malloc(5 * sizeof(double));         if (NULL == ptd[i]) exit(1);     } 引用 2 楼 lm_whales 的回复:第18～22 行 for (i = 1; i <= 4; i++) //为何是1～4 不应该是 0～4吗？     {         ptd[i] = (double *)malloc(5 * sizeof(double));         if (NULL == ptd[i]) exit(1);     } 恩，这个我刚刚检查也发现了，掌握的知识很少，没有定义i=0返回值为1是不是就是说这一行全都是1。因为我为了四节点看着方便都从1开始计的，改过了还是不行呀出现了“ 0xC0000005:  读取位置 0xFEEEFEF6 时发生访问冲突。”[/quote]    ptd[i] 没分配，是个野指针 然而 释放的时候，没有分配，也释放了 （ptd[0]）是个野指针，释放会出问题的 同样 第二行，也可能涉及野指针问题


Question: 关于EasyX中一些函数不能使用的问题

winbgi不错。收藏待用。

引用 3 楼 ipqtjmqj 的回复:在2011年版之后被删了http://www.easyx.cn/downloads/View.aspx?id=5 解决办法,下载2010年版http://www.suxiazai.com/tuwenchuli/tuxianguanli/11385.html#download 或使用winbgi,http://csci.biola.edu/csci105/using_winbgi.html  谢谢你的回答！很有帮助！

谷歌搜索了下,原来EasyX是个图形库,在帮助里搜索setviewport还真没找到这个函数


Question: 程序运行出现| program abort -- Invalid Memory Access问题

引用 6 楼 zhao4zhong1 的回复:有时不将“调用函数名字＋各参数值，进入函数后各参数值，中间变量值，退出函数前准备返回的值，返回函数到调用处后函数名字＋各参数值＋返回值”这些信息写日志到文件中是无论如何也发现不了问题在哪里的，包括捕获各种异常、写日志到屏幕、单步或设断点或生成core文件、……这些方法都不行！ 写日志到文件参考下面： //循环向a函数每次发送200个字节长度（这个是固定的）的buffer, //a函数中需要将循环传进来的buffer，组成240字节（也是固定的）的新buffer进行处理， //在处理的时候每次从新buffer中取两个字节打印 #ifdef _MSC_VER     #pragma warning(disable:4996) #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _MSC_VER     #include <windows.h>     #include <process.h>     #include <io.h>     #define  MYVOID             void     #define  vsnprintf          _vsnprintf #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  MYVOID             void * #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef _MSC_VER void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } void sleep_ms(int ms) {     Sleep(ms); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } void sleep_ms(int ms) {     usleep(ms*1000); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} #define ASIZE    200 #define BSIZE    240 #define CSIZE      2 char Abuf[ASIZE]; char Cbuf[CSIZE]; CRITICAL_SECTION cs_HEX ; CRITICAL_SECTION cs_BBB ; struct FIFO_BUFFER {     int  head;     int  tail;     int  size;     char data[BSIZE]; } BBB; int No_Loop=0; void HexDump(int cn,char *buf,int len) {     int i,j,k;     char binstr[80];      Lock(&cs_HEX);     for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%03d %04x -",cn,i);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             Log("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         Log("%s\n",binstr);     }     Unlock(&cs_HEX); } int GetFromRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      lent=0;     Lock(cs);     if (fbuf->size>=len) {         lent=len;         if (fbuf->head+lent>BSIZE) {             len1=BSIZE-fbuf->head;             memcpy(buf     ,fbuf->data+fbuf->head,len1);             len2=lent-len1;             memcpy(buf+len1,fbuf->data           ,len2);             fbuf->head=len2;         } else {             memcpy(buf     ,fbuf->data+fbuf->head,lent);             fbuf->head+=lent;         }         fbuf->size-=lent;     }     Unlock(cs);     return lent; } MYVOID thdB(void *pcn) {     char        *recv_buf;     int          recv_nbytes;     int          cn;     int          wc;     int          pb;      cn=(int)pcn;     Log("%03d thdB              thread begin...\n",cn);     while (1) {         sleep_ms(10);         recv_buf=(char *)Cbuf;         recv_nbytes=CSIZE;         wc=0;         while (1) {             pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);             if (pb) {                 Log("%03d recv %d bytes\n",cn,pb);                 HexDump(cn,recv_buf,pb);                 sleep_ms(1);             } else {                 sleep_ms(1000);             }             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef _MSC_VER     pthread_exit(NULL); #endif } int PutToRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {     int lent,len1,len2;      Lock(cs);     lent=len;     if (fbuf->size+lent>BSIZE) {         lent=BSIZE-fbuf->size;     }     if (fbuf->tail+lent>BSIZE) {         len1=BSIZE-fbuf->tail;         memcpy(fbuf->data+fbuf->tail,buf     ,len1);         len2=lent-len1;         memcpy(fbuf->data           ,buf+len1,len2);         fbuf->tail=len2;     } else {         memcpy(fbuf->data+fbuf->tail,buf     ,lent);         fbuf->tail+=lent;     }     fbuf->size+=lent;     Unlock(cs);     return lent; } MYVOID thdA(void *pcn) {     char        *send_buf;     int          send_nbytes;     int          cn;     int          wc;     int           a;     int          pa;      cn=(int)pcn;     Log("%03d thdA              thread begin...\n",cn);     a=0;     while (1) {         sleep_ms(100);         memset(Abuf,a,ASIZE);         a=(a+1)%256;         if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop         send_buf=(char *)Abuf;         send_nbytes=ASIZE;         Log("%03d sending %d bytes\n",cn,send_nbytes);         HexDump(cn,send_buf,send_nbytes);         wc=0;         while (1) {             pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);             Log("%03d sent %d bytes\n",cn,pa);             HexDump(cn,send_buf,pa);             send_buf+=pa;             send_nbytes-=pa;             if (send_nbytes<=0) break;//             sleep_ms(1000);             if (No_Loop) break;//             wc++;             if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);         }         if (No_Loop) break;//     } #ifndef _MSC_VER     pthread_exit(NULL); #endif } int main() { #ifdef _MSC_VER     InitializeCriticalSection(&cs_log);     InitializeCriticalSection(&cs_HEX );     InitializeCriticalSection(&cs_BBB ); #else     pthread_t threads[2];     int threadsN;     int rc;     pthread_mutex_init(&cs_log,NULL);     pthread_mutex_init(&cs_HEX,NULL);     pthread_mutex_init(&cs_BBB,NULL); #endif     Log("Start===========================================================\n");      BBB.head=0;     BBB.tail=0;     BBB.size=0;  #ifdef _MSC_VER     _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);     _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2); #else     threadsN=0;     rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);     rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1); #endif      if (!access("No_Loop",0)) {         remove("No_Loop");         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     while (1) {         sleep_ms(1000);         if (No_Loop) break;//         if (!access("No_Loop",0)) {             No_Loop=1;         }     }     sleep_ms(3000);     Log("End=============================================================\n"); #ifdef _MSC_VER     DeleteCriticalSection(&cs_BBB );     DeleteCriticalSection(&cs_HEX );     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_BBB);     pthread_mutex_destroy(&cs_HEX);     pthread_mutex_destroy(&cs_log); #endif     return 0; }  问题已解决，谢谢

崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处，看不懂时双击下一行，直到能看懂为止。  判断是否越界访问，可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断，可将数组多声明一个元素，并设置数据读写断点在该多出元素对应的地址上。 #include <time.h> #include <stdlib.h> #include <windows.h> int main() {     int a,b[11];//本来是b[10]，为判断哪句越界，故意声明为b[11]      srand((unsigned int)time(NULL));//按两次F11，等黄色右箭头指向本行时，调试、新建断点、新建数据断点，地址：&b[10]，字节计数：4，确定。     while (1) {//按F5，会停在下面某句，此时a的值为10，b[10]已经被修改为对应0..4之一。         b[(a=rand()%11)]=0;         Sleep(100);         b[(a=rand()%11)]=1;         Sleep(100);         b[(a=rand()%11)]=2;         Sleep(100);         b[(a=rand()%11)]=3;         Sleep(100);         b[(a=rand()%11)]=4;         Sleep(100);     }     return 0; }

引用 2 楼 apple_v1 的回复:/* destroy the packet if the information is saved */                 op_pk_destroy(pkptr);  //这里释放了 跟这个没有关系，进程收到包，得到包指针后先取得type,LLID,code值如果和本地值匹配就执行if语句下的程序，最后是通过 op_intrpt_schedule_self(op_sim_time (),TIME_INTRPT); 语句跳出if语句，等待下一个包的到来， 如果type,LLID,code值和本地值不匹配，就丢弃该报，执行else里的语句  else              {                 /* destroy the packet if the gate packet is not mine */                  op_pk_destroy (pkptr);              }       但现在收到的就是本地包，执行的也是if里的语句，最后没有通过 op_intrpt_schedule_self(op_sim_time (),TIME_INTRPT);跳出该进程， 报错是program abort -- Invalid Memory Access

引用 1 楼 caozhy 的回复:是多线程方式下调用的么？ 不是多线程，就是顺序执行的。

是多线程方式下调用的么？


Question: 如何用C语言输出一个超级长的小数到TXT文本中？

电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,ftell,fread,fwrite,fgetc,fclose //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

还有就是 我现在用fprintf把一个char变量写入到文本中，发现它竟然占用了5个字节，char不是只占用一个字节的吗？ fprintf(ofp,"%c",sym[j]);   sym[j]是一个char数组 将这个字符数组输出后，我删掉一个字符，发现整个文本减少了5个字节，不过继续删的话每次减少1个字节，这是什么原因？

引用 3 楼 sprawling 的回复:按数据结构存也可以啊，够简单吧。 虽然稍微查了一下，但还是不太懂你说的什么意思，能详细说一下吗？

引用 4 楼 paschen 的回复:用字符串来存储这个“超级长”的小数 这样的话占用的字节数就是字符串长度吧，和我用数组效果一样

用字符串来存储这个“超级长”的小数

按数据结构存也可以啊，够简单吧。

请问你说的是用fwrite吗？如果是，只能说占的字节数更多了。。。

按字节写不就行了吗？


Question: 2*3矩阵转置

谢谢版主  真好  我的问题解决了

1.申请的数组应当是 int a[3][3];否则会越界 2.输出的时候应该是输出3行2列，而不是2行3列  #include<stdio.h> int main() {     void sort(int x[][3],int n);     int a[3][3];     int i,j;     printf("请输入一个2*3矩阵\n");     for(i=0;i<2;i++)         for(j=0;j<3;j++)             scanf("%d",&a[i][j]);         sort(a,2);         for(i=0;i<3;i++)         {             for(j=0;j<2;j++)                 printf("%d ",a[i][j]);             printf("\n");         } } void sort(int x[][3],int n) {     int i,j,t;     for(i=0;i<n;i++)         for(j=0;j<3;j++)             if(i<j)             {                 t=x[i][j];                 x[i][j]=x[j][i];                 x[j][i]=t;             } }


Question: 稀疏矩阵转化成三元组写入速度文件太慢了，怎么优化？

在文件大小相同的前提下：  读刚读过的文件比头次读没读过的文件快  读转速快的硬盘上的文件比读转速慢的硬盘上的文件快  读没有磁盘碎片的文件比读有磁盘碎片的文件快  读文件不处理比边读边处理快  单线程从头到尾一次读文件比多线程分别读文件各部分快（非固态硬盘上）  读固态硬盘上的文件比读普通硬盘上的文件快 写类似。

fseek的原因，怎么弄？

请无视注释..


Question: 发起多个非阻塞connect，然后用epoll来监听它们，怎样判断连接的状态

感觉楼主可以参考下这篇博客 http://www.cnblogs.com/yuxingfirst/archive/2013/03/08/2950281.html 作者提到  “使用非阻塞 connect 需要注意的问题是： 1. 很可能 调用 connect 时会立即建立连接（比如，客户端和服务端在同一台机子上），必须处理这种情况。 2. Posix 定义了两条与 select 和 非阻塞 connect 相关的规定： 1）连接成功建立时，socket 描述字变为可写。（连接建立时，写缓冲区空闲，所以可写） 2）连接建立失败时，socket 描述字既可读又可写。 （由于有未决的错误，从而可读又可写） 不过我同时用epoll也做了实验(connect一个无效端口，errno=110, errmsg=connect refused)，当连接失败的时候，会触发epoll的EPOLLERR与EPOLLIN，不会触发EPOLLOUT。 当用select检测连接时，socket既可读又可写，只能在可读的集合通过getsockopt获取错误码。 当用epoll检测连接时，socket既可读又可写，只能在EPOLLERR中通过getsockopt获取错误码。”  关于非阻塞connect时判断套接字是否连接成功，《unix网络编程卷1》中提到：   我觉得可以在epollin 中通过调用read来判断。


Question: 被代码虐成狗了，求救啊啊啊

引用 1 楼 小灸舞的回复:undefined reference都是只有函数声明而找不到函数实现 检查你的附加包含目录和附加依赖项 看描述，没定义那个结构体的话是可以编译过的。不知道怎么跟那个结构体有冲突，在开源项目做开发的。。

看不清你的图片，如果没定义没问题那问题就在你定义的这个结构体是否重名了等等，检查一下


Question: c语言程序问题

long fun (long s) { 	long lResult = 0, lANum, lNumCount = 0; 	char arNumber[128] = {0};  	while(s > 0) 	{ 		lANum = s % 10;		// 取得末尾一位数 		s /= 10;			// 删掉末尾一位数  		if ( lANum % 2 == 0)// 判断是偶数 		{ 			arNumber[lNumCount] = lANum;	// 记录一位符合条件的数 			lNumCount++; 		} 	}  	// 利用数组构建新数字 	while(lNumCount > 0) 	{ 		lNumCount--; 		lResult = lResult * 10 + arNumber[lNumCount]; 	}  	return lResult;    直接拿走

int func(int s) { 	int tmp = 0; 	int t = 0; 	int count = 0; 	while(s > 0) 	{ 		tmp = s % 10; 		if((tmp % 2) == 0){ 			if(count == 0) 				t = tmp; 			else{ 				tmp *= pow(10,count); 				t += tmp; 			} 			count++; 		} 		s /=10; 	} 	return t; }

int func(int s) {      /*********begin************/ 	int tmp = 0; 	int t = 0; 	int count = 0; 	while(s > 0) 	{ 		tmp = s % 10; 		if((tmp % 2) == 0){ 			if(count == 0) 				t = tmp; 			else{ 				tmp *= pow(10,count); 				t += tmp; 			} 			count++; 		} 		s /=10; 	} 	return t;         /******************end*****************/ }

参考：  #include<stdio.h> long fun (long s)  { 	long sl=10, t; 	s /= 10;  	t = s % 10;  	while(s> 0) 	{  		s = s/100; 		t = t+s%10*sl ; 		sl = sl * 10; 	} 	return t; } void main()      { 	long s,m; 	//void TestFunc(); 	printf("\nPlease enter s:"); 	scanf("%ld", &s);      	m=fun(s); 	printf("The result is: %ld\n", m); 	//TestFunc(); }

long fun (long s) { 	/*********Begin**********/ 	long t = 0; 	long k = 1; 	while (s >= 10) 	{ 		s /= 10; 		t += s % 10 * k; 		k *= 10; 		s /= 10; 	} 	return t; 	/**********  End  **********/ }

如果单纯取偶数位的数字,也可以先转成字符串； sprintf或者snprintf, 然后按照字符串下标依次取出对应的数值；


Question: 继续请教指针基本问题。

引用 8 楼 qq_16774199 的回复:引用操作系统，编译器 以及使用API，调用驱动，写驱动 凡是涉及底层的往往需要指针 不用指针，绕的弯子太大，还不好用  凡是，涉及底层，不需要指针的语言，都是对指针做了某种封装的 没有这些封装就只好用汇编实现了，  要么提供指针或引用，要么用汇编，甚至直接写二进制代码，不然的话，封装一下 。。。。引用其实是指针的某种封装  谢谢回复。 我在想不能直接操作指针的语言，为什么不提供指针？真的是好心怕程序员弄错？ 没有指针功能卖100元，现在有指针功能得卖200，因为指针很强大嘛。但也许增加指针功能只花了20成本。 你似乎只是看到了硬件成本， 而没有考虑人力的开发成本。调试的成本会成倍提高，而且对程序员的要求也高，这都是成本。最后折算下来，使用指针的成本会很高。只有在非常计较硬件成本的地方，才会不计较人力成本。

因为以前（几十年前）计算机只有专业人员使用，搞编程的都很专业，所以C语言、C++之类都是全功能的，包含指针功能。 后来，电脑人人都有，很多非科班的或者只是爱好者也想编程，所以有的编程语言就比较“傻瓜相机”型，比如VB，没有指针，好比就不能（不需要）手动对焦、调光圈、快门等，普通的事情也能做。

因为指令集里面有一种间接寻址的方式，抽象出来就是指针了

引用 4 楼 qq_16774199 的回复:[quote=引用 3 楼 jiqiang01234 的回复:] 因为指针太灵活，可以指向任何地址，这就要求程序员对内存的控制十分精准才行，无形中增大了程序出错的概率。而指针出错调试起来会更加麻烦，因为不见得崩溃的地方就是真正出错的地方，很可能是很多代码之前的指针的操作错误导致的。所以，以后的高级语言把“操作指针”这种对程序员要求太高的功能由编译器或虚拟机来完成了。 指针只是提供便利对吧，没有，程序员也能完成工作？ 有没有情况是非指针不可？[/quote] 操作系统，编译器 以及使用API，调用驱动，写驱动 凡是涉及底层的往往需要指针 不用指针，绕的弯子太大，还不好用  凡是，涉及底层，不需要指针的语言，都是对指针做了某种封装的 没有这些封装就只好用汇编实现了，  要么提供指针或引用，要么用汇编，甚至直接写二进制代码，不然的话，封装一下 。。。。引用其实是指针的某种封装

为什么怕程序员搞错就不给指针功能呢？用销售的话来说，产品多一个功能就多一个卖点。 程序员用不好指针又不是高级语言的错。

引用 3 楼 jiqiang01234 的回复:因为指针太灵活，可以指向任何地址，这就要求程序员对内存的控制十分精准才行，无形中增大了程序出错的概率。而指针出错调试起来会更加麻烦，因为不见得崩溃的地方就是真正出错的地方，很可能是很多代码之前的指针的操作错误导致的。所以，以后的高级语言把“操作指针”这种对程序员要求太高的功能由编译器或虚拟机来完成了。 指针只是提供便利对吧，没有，程序员也能完成工作？ 有没有情况是非指针不可？

引用 1 楼 jiqiang01234 的回复:c语言的指针，是对汇编指令的自然延伸，汇编中无所谓变量，变量无非是内存地址中的一些数据而已。只要是找对内存地址，对地址中的数据操作，就可以认为是对变量进行了操作。所以，不是c语言发明了指针，而是指针将汇编语言直接操作内存地址的概念稍微抽象了一下。 指针不仅仅能是操作简单变量，在c语言中，几乎任何东西都可以用指针来操作。结构体指针，函数指针，数组指针....  谢谢。 那为什么在许多高级语言里没有或不推荐直接操作地址？比如VB6这种。

除此指针可以很方便的建立链表，另外你动态申请的内存也是返回指向那片内存的指针  指针总的来说可以使你写程序更灵活，但也有特别仔细

引用顺便说下，VB6也能指针操作，需要SafeArray绕弯。码农创造力是无穷的。

代码引用自： en.wikipedia.org/wiki/Opaque_pointer  看看这个例子，在C工程中用指针来封装变化。struct obj可以任意修改。 C中没指针，基本没法进行设计了，比方FILE*，隐藏了不必关心的细节。  不提供指针操作的语言，一般提供了其他封装手段。 顺便说下，VB6也能指针操作，需要SafeArray绕弯。码农创造力是无穷的。  /* obj.h */  struct obj;  /*  * The compiler considers struct obj an incomplete type. Incomplete types  * can be used in declarations.  */  size_t obj_size(void);  void obj_setid(struct obj *, int);  int obj_getid(struct obj *);  /* obj.c */  #include "obj.h"  struct obj {     int id; };  /*  * The caller will handle allocation.  * Provide the required information only  */  size_t obj_size(void) {     return sizeof(struct obj); }  void obj_setid(struct obj *o, int i) {     o->id = i; }  int obj_getid(struct obj *o) {     return o->id; }


Question: 调不对 啊，关于吸收输入后的回车键

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

scanf("%d",&n)  后面不需要用getchar

我给个建议，用switch 和case，这样好一点 结构也清晰，你的思路没有错！估计一点小错误 调试一下就估计OK了！


Question: 为什么用fread读取二进制文件数据前面能正常显示后面就全是0

在占用内存空间较大的局部数组声明的前面加static将其从堆栈数据段挪到全局数据段即可避开因局部数组大小超过默认堆栈大小1MB造成程序不能正常运行的问题。

引用 8 楼 sds428 的回复:学习，学习，赵4老师的讲解太好了

学习，学习，赵4老师的讲解太好了

多维数组，很容易忽略  栈溢出的情况，因为每一维都很小 但是乘积很大  建议略微大一点的多维数组， 采用动态分配和全局变量这两种方式处理 以免，跟直觉发生冲突

1、数组太大应该用动态分配内存  2、单步跟踪程序运行很容易找到问题原因

引用 3 楼 qq423399099 的回复:你的int x[2800][2500];会导致栈溢出 2800*2500*4/1024/1024=26.7M我把后面数据的类型弄错了， short 弄成int了,现在解决了，谢谢~

这样可以吗...

int x[2800][2500]; fseek(fp2, 1028L, SEEK_SET); 	fread(x, sizeof(int), 1, fp2); 	for (int row = 0; row < 2800; row++) 	{ 		for (int col =0; col < 2500; col++) 		{ 			if (x[row][col]) { 				cout << x[row][col]; 			} 			 		} 		cout << endl; 	}


Question: 为什么删除函数再删除编号1的货物时出错还有删除编号2的货物时把编号3的货物也删除了

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


Question: 指针++的问题。

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

0012ff4c是变量a地址对吧。  对  b=b+1000000，是否告诉指针继续移动40万个字节？  是  那么005004c储存着什么东西呢？ 不知道  此时再来一句*b=20;，应该是在005004c写入20。我试了，出错，但没出现电脑死机等问题啊，不是说指针在错误位置写入不合适东西会很严重嘛？ 这种情况是否出错一种不确定行为，但每个程序的内存空间都是独自的，并不会影响到其他程序，只可能造成该程序崩溃  若是b=b+1，应该是指针移动4个字节对吧？那也到达其它程序的地盘了吧，怎么就没出错？ 同上，地址空间都是虚拟独立的，你程序不会写到其他进程内，除非你使用专门API，至于没出错，上面也说了，是一t  引用 5 楼 qq_16774199 的回复:[quote=引用 4 楼 paschen 的回复:]  能否简单介绍如何看到0050048c储存的信息？ 假如把内存中一段信息取出来分析，不就能看出它属于哪个程序，修改信息不就能控制程序。我知道实际没那么简单，但是不是这个理？就是帮我理一下思路，加深对电脑的了解。谢谢。[/quote]  你先去理解进程空间虚拟内存，我都没明白你说的0050048c是什么内存，你的程序可以有一个0050048c，别的程序也可以有一个0050048c，他们并不是同一个0050048c

楼主了解一下进程、虚拟内存地址空间。

引用 4 楼 paschen 的回复:  能否简单介绍如何看到0050048c储存的信息？ 假如把内存中一段信息取出来分析，不就能看出它属于哪个程序，修改信息不就能控制程序。我知道实际没那么简单，但是不是这个理？就是帮我理一下思路，加深对电脑的了解。谢谢。

分段机制让每个程序都处在不同的段,各程序之间一般无法直接通信.应用程序特权级为3(最低),而系统级程序都是属于0(最高),特权级低的访问特权级高的会导致处理器异常.

0012ff4c是变量a地址对吧。  对  b=b+1000000，是否告诉指针继续移动40万个字节？  是  那么005004c储存着什么东西呢？ 不知道  此时再来一句*b=20;，应该是在005004c写入20。我试了，出错，但没出现电脑死机等问题啊，不是说指针在错误位置写入不合适东西会很严重嘛？ 这种情况是否出错一种不确定行为，但每个程序的内存空间都是独自的，并不会影响到其他程序，只可能造成该程序崩溃  若是b=b+1，应该是指针移动4个字节对吧？那也到达其它程序的地盘了吧，怎么就没出错？ 同上，地址空间都是虚拟独立的，你程序不会写到其他进程内，除非你使用专门API，至于没出错，上面也说了，是一种不确定行为

0012ff4c是变量a地址对吧。 对，是a的地址 b=b+1000000，是否告诉指针继续移动40万个字节？ 应该是400万吧，呵呵 那么005004c储存着什么东西呢？ 400万个字节约等于4M，八成已经超出你的栈区了，到达其他区了，里面存的东西是未知的 此时再来一句*b=20;，应该是在005004c写入20。我试了，出错，但没出现电脑死机等问题啊，不是说指针在错误位置写入不合适东西会很严重嘛？ 电脑死机太严重了，它说的严重还不至于到那个程度 若是b=b+1，应该是指针移动4个字节对吧？那也到达其它程序的地盘了吧，怎么就没出错？ b+1应该还没有到其他程序地盘，还在你当前的工作栈内，这部分内存现在没有任何保护，你可以随便写，这也是C语言的缺点吧

如果写入保护内存，抱歉，会报错，而不是死机之类的 因为写，读，执行 都会可能产生异常 如果读写保护内存，那么就是异常处理就是回报错误 如果读写的内存，有权读写，那么内存在真实内存中，会直接读写 不在，会产生缺页中断，然后，操作系统执行页面调度，完成后继续执行 这回就可以正确执行了 总之，没那么容易死机啥的了 当年死机，是因为 Win98这类的操作系统不稳定

电脑死机。。。 你太高估你写的这个程序了。 005004c这种都是虚拟内存。 严重的后果是指程序崩溃（这还不严重？）

005004c并非是你自己开的内存，自然不能随你写。肯定出错了，报不报出来就不知道了


Question: 函数形参与实参问题

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

函数中的main、print、sort三个函数中的name都不是同一个！  你参数传过去的只是一个复制器而已

指针这个东西别人讲很多你也不一定能明白。 看多了自然就清楚了。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。

引用 1 楼 cfjtaishan 的回复:   1   #include<stdio.h>                                                                                1 #include<string.h>     2       3 void sort(char *name[],int n);     4 void print(char *name[],int n);     5 int main()     6 { >>  7     char *name[]={"Follow","BASIC","Greart Wall","FORTRAN","Computer desigh"};     8     int n=5;     9     sort(name,n);    10     print(name,n);    11     return 0;    12 }    13      14 void sort(char **name,int n)    //二重指针    15 {    16     char *temp;    17     int i,j,k;    18     for (i=0;i<n-1;i++)    19     {    20     |   k=i;    21     |   for (j=i+1;j<n;j++)    22     |   |   if(strcmp(name[k],name[j])>0)     23     |   |   |   |   k=j;     24     |   |   if(k!=i)    25     |   |   {    26     |   |   |   temp = name[i];    27     |   |   |   name[i] = name[k];    28     |   |   |   name[k] = temp;    29     |   |   }    30     }    31 }    32      33 void print(char **name, int n)    //二重指针    34 {    35     int i;    36     for (i=0;i<n;i++)    37     |   printf("%s\n",name[i]);    38 }   因为传递的是name的地址进去,所以对name的修改,也是对指针数组的修改； 我是照书上打的代码，因为不明白，但是我没有学到二重指针啊，为什么就我打上去的那代码能实现这样的排序？？


Question: 问题是：为什么单词you会出现在结果中？我用了一个循环来判断它啊？

不是添加，是把上一行的m=0移到括号外面来。

#include <stdio.h>  2   #include <ctype.h>                                                                                1 #include <string.h>   2     3 char WORD[10][10]={"you","for","your","on","no","if","the","in","to","all"};   4 char xx[][50]={"you are a student.,","He am NOT a  student."};   5     6 int maxline=2;        7     8 void DelWord()        9 {  10     int i,j,k,m,len,s,t;  11     char ww[20], yy[20], line[80];  12       13     for(i=0;i<maxline;i++)  14     {  15     |   m = 0;       16     |   line[0] = 0;  17     |   len = strlen(xx[i]);  18     |   for(j = 0; j <= len; j++)  19     |   |   if(isalpha(xx[i][j]))  20     |   |   |   ww[m++] = xx[i][j];  21     |   |   else  22     |   |   {  23     |   |   |   ww[m] = 0;  24     |   |   |   if(m) {   25     |   |   |   |   for(k=0;k<10;k++)  26     |   |   |   |   |   if(strcmp(ww,WORD[k]) == 0)  27     |   |   |   |   |   |   break;  28     |   |   |   |   if(k >= 10)  29     |   |   |   |   {  30     |   |   |   |   |   //puts(ww);  31     |   |   |   |   |   s=0;  32     |   |   |   |   |   for(t=m-1;t>=0;t--)  33     |   |   |   |   |   |   yy[s++]=ww[t];  34     |   |   |   |   |   yy[s]=0;  35     |   |   |   |   |   strcat(line,yy);  36     |   |   |   |   |   m=0;  37     |   |   |   |   }     38     |   |   |   |   m = 0;    //add this sentence  39     |   |   |   }    40     |   |   }     41     |   strcpy(xx[i],line);  42     }     43 }     44 int main(void)       45 {  46     int i;           47     DelWord();       48       49     for(i=0;i<maxline;i++)  50     |   printf("%s\n",xx[i]);  51       52     return 0;        53 }

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

引用 1 楼 user-3 的回复:好长啊，自己调试一下吧。  是只是 you 么，其它的那个单词有好用的么，如果其它的也没有好用的就要考虑语法问题了。  如果只是you 就要看看you有啥特殊的了，除了是第一个没看出有啥特殊的。  建议在  if(strcmpi(ww,WORD[k])==0) break; 位置，把比较用的两个字符串打印出来看看是不是你想要的，就应该能找到问题了。 其它的都ok，break这条语句是不区分大小写判断是否有一样的单词，如果有，则不连接到line数组中，相当于删除该单词。


Question: 新人求助，子函数如何返回二维数组

简单的看看C语言书上关于指针和函数返回值部分的内容吧，不然记不住的。

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

double function(double b1, double c1, double d1, double a2, double b2, double c2, double d2, double xi, double eta) { 	int m, n; 	int i, j; 	double pi = 3.1415926; 	double y = 0.25*(a2 + b2*xi + c2*eta + d2*xi*eta); 	double jacobi[3][3] = { 0 }; 	double partial_xi[5] = { 0 }; 	double partial_eta[5] = { 0 }; 	double partial_x[5] = { 0 }; 	double partial_y[5] = {0}; 	double deter; 	double phi[5] = { 0, 0.25*(1 - xi)*(1 - eta), 0.25*(1 + xi)*(1 - eta), 0.25*(1 + xi)*(1 + eta), 0.25*(1 - xi)*(1 + eta) }; 	double fun[5][5]; 	jacobi[1][1] = 0.25*(b1 + d1*eta); 	jacobi[1][2] = 0.25*(b2 + d2*eta); 	jacobi[2][1] = 0.25*(c1 + d1*xi); 	jacobi[2][2] = 0.25*(c2 + d2*xi); 	deter = jacobi[1][1] * jacobi[2][2] - jacobi[1][2] * jacobi[2][1];  	partial_xi[1] = -1.0 / 4 * (1 - eta); 	partial_xi[2] = 1.0 / 4 * (1 - eta); 	partial_xi[3] = 1.0/ 4 * (1 + eta); 	partial_xi[4] = -1.0 / 4 * (1 + eta); 	partial_eta[1] = -1.0 / 4 * (1 - xi); 	partial_eta[2] = -1.0 / 4 * (1 + xi); 	partial_eta[3] = 1.0 / 4 * (1 + xi); 	partial_eta[4] = 1.0 / 4 * (1 - xi); 	partial_x[1] = 1.0 / deter*(jacobi[2][2] * partial_xi[1] - jacobi[1][2] * partial_eta[1]); 	partial_x[2] = 1.0 / deter*(jacobi[2][2] * partial_xi[2] - jacobi[1][2] * partial_eta[2]); 	partial_x[3] = 1.0 / deter*(jacobi[2][2] * partial_xi[3] - jacobi[1][2] * partial_eta[3]); 	partial_x[4] = 1.0 / deter*(jacobi[2][2] * partial_xi[4] - jacobi[1][2] * partial_eta[4]); 	partial_y[1] = 1.0 / deter*(jacobi[1][1] * partial_eta[1] - jacobi[2][1] * partial_xi[1]); 	partial_y[2] = 1.0 / deter*(jacobi[1][1] * partial_eta[2] - jacobi[2][1] * partial_xi[2]); 	partial_y[3] = 1.0 / deter*(jacobi[1][1] * partial_eta[3] - jacobi[2][1] * partial_xi[3]); 	partial_y[4] = 1.0 / deter*(jacobi[1][1] * partial_eta[4] - jacobi[2][1] * partial_xi[4]); 	for (m = 1; m <= 4; m++) 	for (n = 1; n <= 4; n++) 	{ 		fun[m][n] = 2 * pi*((partial_x[m] * partial_x[n] + partial_y[m] * partial_y[n])*y + 2 * phi[m] * partial_y[n])*deter; 		a[m][n] = fun[m][n]; 		//printf("%f\n", fun[m][n]); 		return(a[m][n]); 	}  	return(a[1][1]); }

非常感谢赵4老师，问题解决了


Question: 如何学习C语言编程

我感觉就跟着一本经典的书籍学习，边学理论，边敲代码，做做习题，感觉是真的会很乏味，有空去网上搜搜有趣的应用调节一下吧。。。

不是搞嵌入式,不要学C语言了.学其它的吧.

程序错了，用搜索引擎搜索错误码。  你碰到的错误，在网上基本都能找到对应的案例。  一个好的学习方法就是看别人的经典代码，认真理解，在此基础上修改，做出自己的东西。

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

基础语法是必须的，否则看别人简单代码都有疑惑的，从别人简单片段理解，接着理解网络上的能运行的代码，弄到自己电脑跑跑，能跑起来的，就尝试添加打印信息如printf来理解程序运行到哪一步的结果，为什么会变成这样。一步一步来，

我学C的过程是，一边看"21天学通C++"一边做上面的部分习题(当然我没学C++) --> http://c-faq.com/ --> 翻阅 stackoverflow "highest voted c questions" --> leetcode oj --> 翻阅 C99 标准草案 --> 翻阅 c99 rationale

语言只是一门工具，关键在于实践，还是多打代码吧！

我觉得还是多练习吧，普通人用砖砌墙都砌不直，师傅可以用砖盖房子，都是有个过程，只不过现在的人都比较急功近利，忽视了很多东西而已（比如练武功要蹲马步。。） 用直观的数据，有的学生大学四年的代码量不超过一千行，有的牛人可以达到几万行，那最后的水平是肯定的。 书上主要是为了教学，除非是专门案例的书，一般都只是介绍技术点和核心代码。完整实用的程序网络上也有很多，不过一般都是基于某些API或者框架。

对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后，就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。

这个得需要多练习了；对于语法错误,多次遇到就知道哪儿出错了,就是"久病成医"； 练习先从简单程序开始,一点一点的学习复杂的程序； 平时也可以遇到问题多百度,自己去查错误问题； 总之,不能懒,不能退缩, 遇到问题解决问题~


Question: Debug的时候 return *p一步出现30xC0000005: 读取位置 0x00000000 时发生访问冲突

你对NULL指针进行了操作 稍微调试了下发现Add函数要返回的时候，此时p3已经是NULL了，你还*p3就出现异常了 同时你的Compare里面也不对else {if(a=b)是什么鬼，多了个{少了个=  Windows： 崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 Linux： 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令  代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。


Question: 蔡勒公式有问题

计算某一天星期几的几个公式 蔡勒公式：W = ([C/4] - 2C + y + [y/4] + [13 * (M+1) / 5] + d - 1) mod 7． 吉姆拉尔森公式：W =((Y-1)+[(Y-1)/4]-[(Y-1)/100]+[(Y-1)/400]+[13*(M+1)/5 ]+d) mod 7． 蔡农公式：W = (C%4*5+Y+Y/4+(13*M+8)/5+D)%7

y=year;改成ty=year;试试  #include<stdio.h> int main() {     int year,month,day,ty,m,y,c,d,weeks;     scanf("%d%d%d",&year,&month,&day);     ty=year;     m=month;     if(m<3)     {         m=12+m;         ty--;     }     y=ty%100;     c=ty/100;     d=day;     weeks=(y+y/4+c/4-2*c+(26*(m+1))/10+d-1)%7;     printf("%d\n",weeks); }

蔡勒公式 公式中的符号含义如下： w：星期（计算所得的数值对应的星期：0-星期日；1-星期一；2-星期二；3-星期三；4-星期四；5-星期五；6-星期六）[1] c：年份前两位数 y：年份后两位数 m：月（m的取值范围为3至14，即在蔡勒公式中，某年的1、2月要看作上一年的13、14月来计算，比如2003年1月1日要看作2002年的13月1日来计算） d：日 [　]：称作高斯符号，代表向下取整，即，取不大于原数的最大整数。 mod：同余（这里代表括号里的答案除以7后的余数）


Question: 初学指针疑问，为什么不用普通变量储存地址，要专门发明指针变量来储存呢？

引用 12 楼 贫僧博企的回复:3楼说得对啊. 看样子,LZ没学过汇编啊. 我没学过，但是从下往上学会不会太久太难。

它们不都是“变量”么？

3楼说得对啊. 看样子,LZ没学过汇编啊.

引用 楼主 qq_16774199 的回复:初学指针疑问，为什么不用普通变量储存地址，要专门发明指针变量来储存呢？  在某些方面用起来方便吧， 其实指针存的也是数字，也有个别人，用来和数字间转来转去， 不过很少见。  就像有了刀子，还发明了锯子一样吧。（不知道刀子和锯子是哪个在先）

引用 9 楼 DelphiGuy 的回复:如果指针扩展到1024位，那么必然会有相应的整数类型，诸如int1024之类的，就像现在指针64位，但是__int64、long long出现得比64位指针还早。 那还真不一定。

引用 7 楼 DelphiGuy 的回复:[quote=引用 4 楼 zhao4zhong1 的回复:] 万一将来CPU的寻址范围达到2^1024……  这个应该没有可能，超过2^64的可能性都很小，可观测宇宙范围内的基本粒子总数大约是10^80级别，也就是2^265多一点，所以2^512已经超过所需了。 [/quote] 我的意思是到那时任何一个普通变量都存不下一个指针值了。

引用 4 楼 zhao4zhong1 的回复:万一将来CPU的寻址范围达到2^1024……  这个应该没有可能，超过2^64的可能性都很小，可观测宇宙范围内的基本粒子总数大约是10^80级别，也就是2^265多一点，所以2^512已经超过所需了。

指针就是普通变量

因为32位的cpu，不知对不对，哈哈 32/8 = 4字节。  现在都有64位了，所以有长指针了。

万一将来CPU的寻址范围达到2^1024……

因为指令集里面有一种间接寻址的方式，抽象出来就是指针了

普通变量存储不了地址，比如你定义一个变量给他赋值一个看起来像地址的数据 const int a = 0x000000c0； 这时a只是等于这么一个十六进制的值，你无法操作0x000000c0这个地址的内存（当然，即使是指针，如果这么定义，你们无法修改这个地址中的数据） 另外，最主要的，指针可以从堆上动态申请内存

指针也是基本类型，和char、int之类的一样。


Question: 请教，指针无非就储存个地址，为什么还要指定类型？

没用类型，那->符号怎么用？ 指针++怎么计算？

++ptr内存到底加多少, array[4]难道是指偏移4个字节？

引用 楼主 qq_16774199 的回复:请教，指针无非就储存个地址，为什么还要指定类型？ 方便程序员啊，也方便编译器做检查。提前发现错误。

我是这样理解的，指针确定这个数据的起点，而这个数据多大，占几个字节，以什么方式读取，这都是数据类型来决定的

强类型的语言， 编译器可以在编译期间检查程序有效性。 跟弱类型语言比较下。

类型就是内存结构， 指针的值规定了起点， 类型规定了大小和组分。

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

你不定义类型怎么区分这块内存存的是什么类型的数据？

你买个房还要分户型呢？

不指定类型，那我要以哪种方式解析出这个地址对应的值呢？

这个。。。微机原理学了吗？简单的说，请思考16位程序、32位程序、64位程序的区别。。。


Question: 有没有人知道什么语句能让运行cmd的程序直接最大化运行？

最大化了，但还是同屏显示不下要显示的内容。 此时可以试试使用4楼的代码。

Windows 平台的确是这样做： HWND hwnd = GetConsoleWindow(); ShowWindow(hwnd, SW_HIDE); // 不加这一句会看到最大化的动作 ShowWindow(hwnd, SW_MAXIMIZE);

标准库没有这种函数，因为标准库中没有 GUI 函数

直接修改注册表。让cmd命令缺省就是最大化的。  [HKEY_CURRENT_USER\Console]  "FullScreen"=dword:00000001

system("mode con cols=80 lines=80");//窗口宽度高度

没啥要求吧。

引用 3 楼 lm_whales 的回复:HWND hwnd =::GetConsoleWindow(); SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);最大化 ///SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); // 最小化 ///SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); // 关闭 ///SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // 最大最小化化状态还原  这些窗口句柄 使用上有什么要求吗？

再供参考： C:\>mode /? 配置系统设备。  串行口:　　　   MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]                              [to=on|off] [xon=on|off] [odsr=on|off]                              [octs=on|off] [dtr=on|off|hs]                              [rts=on|off|hs|tg] [idsr=on|off]  设备状态:       MODE [device] [/STATUS]  打印重定向:　　 MODE LPTn[:]=COMm[:]  选定代码页:　　 MODE CON[:] CP SELECT=yyy  代码页状态:　　 MODE CON[:] CP [/STATUS]  显示模式:　　   MODE CON[:] [COLS=c] [LINES=n]  击键率:　       MODE CON[:] [RATE=r DELAY=d]  mode con cols=120 lines=9999

仅供参考：//控制台的字体大小是可以改变的。系统为我们提供了许多的API，能更改字体大小的API正隐身其中。网上没有控制台字体大小的相关资料， //关于控制台字体大小的教程是本博客独家放出。本文将教会你如何使用这些API，达到修改控制台字体大小的目的。 //一般控制台中每个输出缓冲区都有一个固定的字体。系统中的字体，每一种都有对应的序号，每种字体大小不同。想要修改为一种新的字体， //就将这种字体的序号赋值给控制台缓冲区即可。一般来说，系统所有的字体总数不超过40个，因此循环获取信息时可以以这个为上限。 //首先放出需要用到的API列表： //（如下大部分API都没有公布，至最近才公布了其中几个的详细信息）  //bool SetConsoleFont(HANDLE,DWORD) //注意了，这个函数一旦调用，所有文字字体大小全部变化，窗口大小也变了。这个是用于设置字体大小 //第一个参数为输出句柄，第二个参数为新字体大小序号  //bool GetConsoleFontInfo(HANDLE,BOOL,DWORD,CONSOLE_FONT*) //这个是用于获取字体信息 //第一个参数为输出句柄，第二个参数应设为0，第三个参数为欲获取信息的字体序号，第四个参数为CONSOLE_FONT结构体的指针，API将返回的信息放置在这个结构体里  //COORD GetConsoleFontSize(HANDLE,DWORD) //这个是用于获取字体大小 //第一个参数为输出句柄，第二个参数为欲获取大小的字体序号，返回的COORD的两个成员就是字体的大小  //DWORD GetNumberOfConsoleFonts() //这个是用于获取可用字体数 //返回可用字体总数  //bool GetCurrentConsoleFont(HANDLE,BOOL,CONSOLE_FONT*) //这个是用于获取当前字体的信息 //第一个参数为输出句柄，第二个参数应设为0，第三个参数为CONSOLE_FONT结构体的指针，API将返回的信息放置在这个结构体里  //结构体CONSOLE_FONT： //struct CONSOLE_FONT{ DWORD index; COORD dim;}; //第一个成员是字体的序号，第二个成员是字体的大小 //这是些未公布的API，所以需要动态载入，首先在全局声明： #pragma comment(lib,"user32") #pragma comment(lib,"gdi32") #pragma comment(lib,"shell32") #include <windows.h> #include <Shlwapi.h> #include <shlobj.h> #include <stdio.h> struct CONSOLE_FONT{ DWORD index; COORD dim;}; typedef BOOL  (WINAPI *PROCSETCONSOLEFONT         )(HANDLE, DWORD); typedef BOOL  (WINAPI *PROCGETCONSOLEFONTINFO     )(HANDLE,BOOL,DWORD,CONSOLE_FONT*); typedef COORD (WINAPI *PROCGETCONSOLEFONTSIZE     )(HANDLE,DWORD); typedef DWORD (WINAPI *PROCGETNUMBEROFCONSOLEFONTS)(); typedef BOOL  (WINAPI *PROCGETCURRENTCONSOLEFONT  )(HANDLE,BOOL,CONSOLE_FONT*); PROCSETCONSOLEFONT          SetConsoleFont; PROCGETCONSOLEFONTINFO      GetConsoleFontInfo; PROCGETCONSOLEFONTSIZE      GetConsoleFontSize; PROCGETNUMBEROFCONSOLEFONTS GetNumberOfConsoleFonts; PROCGETCURRENTCONSOLEFONT   GetCurrentConsoleFont; extern "C" HWND WINAPI GetConsoleWindow(); int main(int argc, char *argv[]) {     //然后在程序启动的时候进行载入：     HMODULE hKernel32 = GetModuleHandle("kernel32");     SetConsoleFont          = (PROCSETCONSOLEFONT         )GetProcAddress(hKernel32,"SetConsoleFont"         );     GetConsoleFontInfo      = (PROCGETCONSOLEFONTINFO     )GetProcAddress(hKernel32,"GetConsoleFontInfo"     );     GetConsoleFontSize      = (PROCGETCONSOLEFONTSIZE     )GetProcAddress(hKernel32,"GetConsoleFontSize"     );     GetNumberOfConsoleFonts = (PROCGETNUMBEROFCONSOLEFONTS)GetProcAddress(hKernel32,"GetNumberOfConsoleFonts");     GetCurrentConsoleFont   = (PROCGETCURRENTCONSOLEFONT  )GetProcAddress(hKernel32,"GetCurrentConsoleFont"  );     //载入完毕之后，就可以进行编程对字体大小控制了。      int NumOfFont,i,X=0,Y=0,IconIndex=0;     char *IconFile=NULL;     NumOfFont = GetNumberOfConsoleFonts();     CONSOLE_FONT *fonts = new CONSOLE_FONT[NumOfFont];     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);     GetConsoleFontInfo(hConsole, 0, NumOfFont, fonts);     if (argc==1) {         printf("Set Console FontSize and Icon. Designed by zhao4zhong1@163.com 2015-07-10\n");         printf("Usage: %s [XxY] [IconFile] [IconIndex]\n",argv[0]);         printf("May availible Font Size:\n X x  Y\n-- x --\n");     }     if (argc==2) {         if (2!=sscanf(argv[1],"%dx%d",&X,&Y))         IconFile=argv[1];     } else if (argc==3) {         if (2!=sscanf(argv[1],"%dx%d",&X,&Y)) {             IconFile=argv[1];             sscanf(argv[2],"%d",&IconIndex);         } else {             IconFile=argv[2];         }     } else if (argc==4) {         sscanf(argv[1],"%dx%d",&X,&Y);         IconFile=argv[2];         sscanf(argv[3],"%d",&IconIndex);     }     if (IconFile) {         HWND hwnd=GetConsoleWindow();         if (hwnd) {             HICON hIconS=NULL;             if (1<=ExtractIconEx(IconFile,IconIndex,NULL,&hIconS,1)) {                 if (hIconS) {                     SendMessage(hwnd,WM_SETICON,ICON_SMALL,(LPARAM)hIconS); //                  DestroyIcon(hIconS);                 }                 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, NULL, NULL);//更新任务栏上的图标             }         }     }     for (i=0;i<NumOfFont;i++) {         fonts[i].dim = GetConsoleFontSize(hConsole, fonts[i].index); //      if (argc==1) printf("%2d x %2d %d %d\n",fonts[i].dim.X,fonts[i].dim.Y,i,fonts[i].index);         if (argc==1) printf("%2d x %2d\n",fonts[i].dim.X,fonts[i].dim.Y);         if (fonts[i].dim.X == X && fonts[i].dim.Y == Y) {             SetConsoleFont(hConsole, fonts[i].index);             break;         }     }     delete[] fonts;     return 0; } //BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);//设置前景背景颜色  //SetCurrentConsoleFontEx function // //Sets extended information about the current console font. // //BOOL WINAPI SetCurrentConsoleFontEx( //  _In_ HANDLE               hConsoleOutput, //  _In_ BOOL                 bMaximumWindow, //  _In_ PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx //); // //Parameters //hConsoleOutput [in] //    A handle to the console screen buffer. The handle must have the GENERIC_WRITE access right. For more information, see Console Buffer Security and Access Rights. //bMaximumWindow [in] //    If this parameter is TRUE, font information is set for the maximum window size. If this parameter is FALSE, font information is set for the current window size. //lpConsoleCurrentFontEx [in] //    A pointer to a CONSOLE_FONT_INFOEX structure that contains the font information. //Return value //    If the function succeeds, the return value is nonzero. //    If the function fails, the return value is zero. To get extended error information, call GetLastError. //Remarks //    To compile an application that uses this function, define _WIN32_WINNT as 0x0500 or later. For more information, see Using the Windows Headers. //Requirements //    Minimum supported client //    Windows Vista [desktop apps only] //    Minimum supported server //    Windows Server 2008 [desktop apps only] //Header //    Wincon.h (include Windows.h) //Library //    Kernel32.lib //DLL //    Kernel32.dll //See also //    Console Functions //    CONSOLE_FONT_INFOEX  //CONSOLE_FONT_INFOEX structure // //Contains extended information for a console font. // //typedef struct _CONSOLE_FONT_INFOEX { //  ULONG cbSize; //  DWORD nFont; //  COORD dwFontSize; //  UINT  FontFamily; //  UINT  FontWeight; //  WCHAR FaceName[LF_FACESIZE]; //} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; // //Members //cbSize //    The size of this structure, in bytes. //nFont //    The index of the font in the system's console font table. //dwFontSize //    A COORD structure that contains the width and height of each character in the font, in logical units. The X member contains the width, while the Y member contains the height. //FontFamily //    The font pitch and family. For information about the possible values for this member, see the description of the tmPitchAndFamily member of the TEXTMETRIC structure. //FontWeight //    The font weight. The weight can range from 100 to 1000, in multiples of 100. For example, the normal weight is 400, while 700 is bold. //FaceName //    The name of the typeface (such as Courier or Arial). //Remarks //    To obtain the size of the font, pass the font index to the GetConsoleFontSize function. //Requirements //    Minimum supported client //    Windows Vista [desktop apps only] //    Minimum supported server //    Windows Server 2008 [desktop apps only] //Header //    Wincon.h (include Windows.h)  //GetCurrentConsoleFontEx function // //Retrieves extended information about the current console font. // //BOOL WINAPI GetCurrentConsoleFontEx( //  _In_  HANDLE               hConsoleOutput, //  _In_  BOOL                 bMaximumWindow, //  _Out_ PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx //);

标准C 没这玩意。

找到窗口句柄发送消息看看成不成


Question: 小弟 初学C语言 有一题不明 还望大神提点

从楼主的描述来看，ratingCounters[11]刚好处在number的位置，ratingCounters[11] = 0;等价于number=0 这样就可以解释调换顺序的区别了。

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

引用 1 楼 brookmill 的回复:数组越界。 int ratingCounters[11];//用来存储每个分数的个数 这个数组的合法范围是0~10，而不是1~11 所以， for (i = 1; i <= 11; ++i) 应该是 for (i = 0; i < 11; ++i)   感谢大神  确实是因为越界了


Question: 请教关于EOF的一个问题

<Enter>,<Ctrl+Z>,<Enter>

引用 4 楼 qq423399099 的回复:因为它没有读到EOF当然不会跳出循环。 你要输入一行就跳出循环应该写成while((c = getchar()) != '\n') windows下要输入CTRL+Z才相当于结束符EOF  我输入的是'a'+EOF+'\n'，为啥没有读到呢？

引用 2 楼 qq423399099 的回复:cin读入标准输入，直到遇到文件结束符结束符，而在Windows中CTRL+Z相当于文件结束符EOF windows认为，如果缓冲中还有其它内容，ctrl+z不表示输入结束，仅代表当前行输入结束，只在单独一个ctrl+z的时候才表示输入结束。  那我请问缓冲中还有其他内容时，while((c = getchar()) != EOF)到底为什么变成等待输入的状态？ 不该是此时跳出循环么？


Question: 关于C语言海龟图问题

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

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

谢谢赵老师和版主大人的悉心教诲，因为自学C语言，一开始就没有养成一个好习惯去自己调试程序，真的谢谢你们能够抽出时间来告诉我怎么学习C语言


Question: 各位大大帮帮忙，关于fwrite函数

可以试试在系统下跑一跑会不会无故退出,如果不会,应该是目标运行环境的问题；

本来是2万多字节一次性写入的，结果会退出，后来改成现在这样分开写入，还是退出 真是没辙了

引用 2 楼 brookmill 的回复:其它看不出什么问题了。延时、fflush应该都没什么关系。 再就是那些自定义的数组和结构，使用是否正确，只有你自己知道了。 嗯我再检查检查，是一个比较大的数组两万多字节， 类似这样的 U8 SaveData[26302]; U8 *SaveInitData=SaveData; U8 *SaveSlideData=SaveData+100; U8 *SaveCtrlData=SaveData+200; ......

硬盘上有坏道。我再猜。

磁盘空间满。我猜。

引用 2 楼 brookmill的回复:其它看不出什么问题了。延时、fflush应该都没什么关系。 再就是那些自定义的数组和结构，使用是否正确，只有你自己知道了。 跟数组没关系，随便新建一个100字节的数组，重复保存保存263次，也会死，保存少点，比如64次就没事， for(i=0;i<263;i++)     fwrite(aaa,1,100,fp);

引用 6 楼 brookmill的回复:1楼的fclose放错位置了，应该在if的大括号里面。 还可以试试先写第3个文件再写前两个。 既然SaveInitData、SaveSlideData、SaveCtrlData这些都是连续的，为什么不一次写300字节呢？不过这也没什么本质区别。 只保存一次没问题，随便哪个文件都没事

我已经放弃了。现在是分成几个比较小的文件分开保存，目前一切正常。谢谢大家帮忙。

写入速度限制的话，你多次写之间得加适当的延时。

也就是说，程序应该没问题了。 存储设备是64M的DOC电子盘，写入速度据说很慢500K/S,不知道有没有关系。 因为在两台设备上都有问题，应该不是空间和坏道的问题

引用 1 楼 brookmill 的回复:1. 是FILE * 还是 File * 2. 同样的代码复制好几遍的时候，就可以考虑写个函数了，比如 fp = fopen("par1.dat", "wb"); if(fp != NULL) {     save(fp); } fclose(fp);  fp = fopen("par2.dat", "wb"); if(fp != NULL) {     save(fp); } fclose(fp);  fp = fopen("par3.dat", "wb"); if(fp != NULL) {     save(fp); } fclose(fp);  是FILE，代码是手敲的，公司的项目，没法拷贝


Question: 有没有大牛 帮我解决这两个程序题  小弟感激不尽

#include"stdio.h" #include"stdlib.h" #include"string.h" int main(){ 	int i,n,len,j=0,j1=0,flag; 	char buf[50] = { 0 };//存放输入的字符串 	char s[123] = { 0 };//a到z是97到122    s这个数组每个位置代表着一个字母，里面的值表示这个字母出现的次数 	char buf_puts[50] = { 0 }; 	printf("输入字符串\n"); 	scanf("%s", buf); 	printf("输入字符出现次数\n"); 	scanf("%d", &n); 	len = strlen(buf); 	for (i = 0; i < len; i++){ 		s[buf[i]]++;  //每个字母出现的次数都存起来 	} 	for (i = 0; i < len; i++){ 		if (s[buf[i]] == n){   //找出次数与n相同的 			flag = 0; 			for (j1 = 0; j1 < j;j1++){                  				if (buf_puts[j1] == buf[i]){       //buf_puts是已经输出过的字符，flag置1表示此字符已经输出过一次 					flag = 1; 					break; 				} 			} 			if (flag == 0){ 				printf("%c", buf[i]); 				buf_puts[j++] = buf[i]; 			} 		} 	}  	return 0; } 上一个有点问题 这个已调试通过

#include"stdio.h" #include"stdlib.h" #include"string.h" int main(){ 	int i,n,len,j=0,j1=0,flag; 	char buf[50] = { 0 };//存放输入的字符串 	char s[123] = { 0 };//a到z是97到122    s这个数组每个位置代表着一个字母，里面的值表示这个字母出现的次数 	char buf_puts[50] = { 0 }; 	printf("输入字符串\n"); 	scanf("%s", buf); 	printf("输入字符出现次数\n"); 	scanf("%d", &n); 	len = strlen(buf); 	for (i = 0; i < len; i++){ 		s[buf[i]]++;  //每个字母出现的次数都存起来 	} 	for (i = 0; i < len; i++){ 		if (s[buf[i]] == n){   //找出次数与n相同的 			flag = 0; 			for (j1 = 0; j1 < j;j1++){                  				if (buf_puts[j++] == buf[i]){       //buf_puts是已经输出过的字符，flag置1表示此字符已经输出过一次 					flag = 1; 					break; 				} 			} 			if (flag == 0){ 				printf("%c", buf[i]); 				buf_puts[j++] = buf[i]; 			} 		} 	}  	return 0; } 第一题 因为会重复输出的问题略微繁琐了  可自行研究

仅供参考：#include <stdio.h> #include <string.h> char s1[]="delete"; char s2[]="select"; unsigned char n[256]={0}; char r[257]; int i,L,o=0; void main() {     L=strlen(s1); for (i=0;i<L;i++) if (!n[(unsigned int)s1[i]]) n[(unsigned int)s1[i]]=++o;     L=strlen(s2); for (i=0;i<L;i++) if (!n[(unsigned int)s2[i]]) n[(unsigned int)s2[i]]=++o;     L=0;     for (o=1;o<=256;o++) {         for (i=0;i<256;i++) {             if (o==n[i]) {                 r[L++]=i;                 break;             }         }         if (i>=256) break;     }     r[L]=0;     printf("[%s]\n",r); } //[deltsc]


Question: 请教用printf显示地址。

你这是学指针吧，但语法你还没记好

数组结束地址由 数组长度，类型长度 决定 char 长度一般是一个字节 char [N] 就是N个字节 地址本身，只表示位置 但是C,C++ 表示地址的数据，其实是指针，是有类型的指针 这个类型的长度，表示下一个同类型数据，最近可以存放在哪里（距离为0时候）。 这也是指针加减法的单位长度 ++ 增加一个单位长度 ， +=n ,增加 n个单位长度 注意 void 类型长度为0 ; void* 指针，无法计算长度（其实是0）， 虽然是通用类型的指针，但是指针算术运算，却不能进行。 PS: 字符串结束符，不是数组结束符。仅仅表示这一串字符到此结束。 数组通常比这长些. 二者至少是相等的， 串长不会长过数组长度除非越界（出错了）

对于C++ char 类型数组，或者指针 用cout<<str ;这种方式输出的是字符串 对于非字符类型数组 输出的是数组的（首元素）地址  C++ 数组，和C数组基本一致，除了输出

以上，都说针对C的 基本上是针对 printf 系列函数的

引用 16 楼 qq_16774199 的回复:[quote=引用 14 楼 zhao4zhong1 的回复:] 不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。 但是没有书从你说的角度去教初学者啊，而初学者能把printf学清楚也不容易了。 您说的反汇编入手，对初学都好像更难，实际上我连反汇编窗口是哪个，从哪里点出来都不清楚，更别说看懂。[/quote] http://edu.csdn.net/course/detail/2344

引用 14 楼 zhao4zhong1 的回复:不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。 但是没有书从你说的角度去教初学者啊，而初学者能把printf学清楚也不容易了。 您说的反汇编入手，对初学都好像更难，实际上我连反汇编窗口是哪个，从哪里点出来都不清楚，更别说看懂。

引用 13 楼 qq423399099 的回复:[quote=引用 12楼我是你的主体 的回复:][quote=引用 11 楼 qq423399099 的回复:] 对的，会自动帮你加上'\0'(注意不是'0'自己注意区分）  谢谢。 进一步说0012ff43就是字母S的地址啦？ 若把0012ff43放到一个名叫ABC的变量里，于是ABC就成为指针变量。 凭着ABC指针变量去内存里就能找到str1字符串开始的位置，然后开始读取，读到\0结束，于是读出str1字符串变量的内容？ 是不是这样子？[/quote]对[/quote] 以上都是我想当然的推测，这真的就是针指的真实面目吗？

引用 12楼我是你的主体 的回复:[quote=引用 11 楼 qq423399099 的回复:] 对的，会自动帮你加上'\0'(注意不是'0'自己注意区分）  谢谢。 进一步说0012ff43就是字母S的地址啦？ 若把0012ff43放到一个名叫ABC的变量里，于是ABC就成为指针变量。 凭着ABC指针变量去内存里就能找到str1字符串开始的位置，然后开始读取，读到\0结束，于是读出str1字符串变量的内容？ 是不是这样子？[/quote]对

引用 11 楼 qq423399099 的回复:对的，会自动帮你加上'\0'(注意不是'0'自己注意区分）  谢谢。 进一步说0012ff43就是字母S的地址啦？ 若把0012ff43放到一个名叫ABC的变量里，于是ABC就成为指针变量。 凭着ABC指针变量去内存里就能找到str1字符串开始的位置，然后开始读取，读到\0结束，于是读出str1字符串变量的内容？ 是不是这样子？

对的，会自动帮你加上'\0'(注意不是'0'自己注意区分）

引用 9 楼 qq423399099 的回复:字符串读取到'\0'就会自动结束读取  那么情况就变成这样：

字符串读取到'\0'就会自动结束读取

引用 5 楼 lm_whales 的回复:数组名 str加上取址运算符&， 表示取str 这个N元素的数组的地址  该地址代表整个数组  数组名，单独出现在表达式中， (除了有限的结个例外)  往往解析为数组首元素的地址， 这个地址和数组地址值是相同的，  只是类型不同 一个是 字符地址。 一个是字符数组地址。  输出地址用 %p 输出字符串 用 %s  输出数组，只能循环了，没有直接输出的方法 输出结果，也是自行定义  你好，我做个图，希望能帮助理解，请看看是否正确。 0012ff43是字母s在内存中的地址，也是字符串开始的位置，对吧？ 如果只是开始地址，那结束地址谁记录？不记录那读取过头了怎么办？

数组名代表数组的地址，它不是指针，是符号地址常量，在内存中没有给它分配空间。所以对它取地址应该是不合法的。但一般对它取地址后得到的值就是它本身代表的值，即数组的地址。 1、输出的是int类型，是十进制。 2、开始地址。 3、可以。 4、如果你说的是&str1的话，它不是指针。 指针变量储存的是地址，它本身也有内存空间，也有自己的地址。

数组名本来就是一个地址了吧？为什么还要取值符号呢？我也不是很懂

char str1[]="silenthunter"; 	int add=str1;     printf("%s\n%s\n",str1,(int *)add); 	return 0; 自己琢磨一下.

%d输出的是int，使用%p输出指针


Question: 这个程序，总是出现这个问题，搞不清，求大神解答

引用 5 楼 qq423399099 的回复:C语言 local function definitions are illegal是：本地函数定义不合法的意思！ 造成这种问题的原因通常是因为函数的嵌套定义造成的。 检查下你的大括号，估计是你哪里少了一个大括号 PS：不是非要用VC6的话，建议换掉，用VS 好的，谢谢版主，问题解决了！！

[quote=引用 2 楼 qq423399099 的回复:] 按你的要求全部改了，出现了下面的问题，我的运行环境是：VC++6.0。

/******元素进栈******/ void Push(char X, Stack S) {	 	PtrToNode TmpCell; 	TmpCell = (PtrToNode)malloc(sizeof(struct Node)); 	if (TmpCell == NULL) 		perror("Out of Space!"); 	else{ 		TmpCell->Element = X; 		TmpCell->Next = S->Next; 		S->Next = TmpCell; 	} }  /******float元素进栈******/ void FPush(float X, FStack S) {	 	Ptr_Fn TmpCell; 	TmpCell = (Ptr_Fn)malloc(sizeof(struct FNode)); 	if (TmpCell == NULL) 		perror("Out of Space!"); 	else{ 		TmpCell->Element = X; 		TmpCell->Next = S->Next; 		S->Next = TmpCell; 	} }  /******返回栈顶元素******/ char Top(Stack S) { 	if (!IsEmpty(S)) 		return S->Next->Element;	 	perror("Empty Stack"); 	exit(1); 	return 0; }  /******返回float栈顶元素******/ float FTop(FStack S) { 	if (!FIsEmpty(S)) 		return S->Next->Element; 	perror("Empty Stack"); 	exit(1); 	return 0; }  /******将堆栈元素倒置******/ void Reverse(Stack Rev) { 	Stack Tempstack; 	Tempstack = (Stack)malloc(sizeof(struct Node)); 	Tempstack->Next = NULL; 	while (!IsEmpty(Rev)){ 		Push(Top(Rev),Tempstack);  	 /*将元素压栈到一个临时堆栈*/ 		Pop(Rev); 	} 	Rev->Next = Tempstack->Next;   	/*指向新的堆栈*/ }   /******* Whereat 说明: Whereat 记录了操作数和运算符号的位置，用A和B区分。A = operand, B = operator.  (例如 1+2转换成12+,在whereat中的形式应该是 AAB) OpHolder说明: Char类型的堆栈Opholder用来保存运算符号。 ******/  int IsOperator(char ToCompare); int OperatorValue(char ValueToGive);  /******将中缀表带式转换为后缀表达式******/ void ConvertToPost(FILE *In, Stack Whereat, FILE *Temp) { 	Stack OpHolder; 	char holder; 	char lastseen; 	int digitcounter = 0;                       /*操作数的计数器*/ 	OpHolder = (Stack)malloc(sizeof(struct Node));      /*初始化*/ 	OpHolder->Next = NULL; 	holder=getc(In); 	lastseen = '@';                           /*用来防止输入格式错误，例如两个小数点*/ 	putc(' ',Temp);   	while ((holder !='\n') && (holder != EOF)){ 		if (holder == ' '){ 			digitcounter = 0; 		} 		else if ( IsOperator(holder) == -1){       /*如果holder不是操作数或运算符号*/ 			PrintError = 1; 		} 		else if (IsOperator(holder)==0){ 			if ((lastseen == holder) && (lastseen == '.')){   /*错误处理*/ 				PrintError = 1; 			} 			else 				lastseen = holder; 			if (digitcounter == 0){	 				Push('A',Whereat);             /*进栈*/ 				digitcounter++;	/*计数器加一*/ 				putc(' ',Temp); 			} 			putc(holder,Temp); 		} 		else{ 			digitcounter = 0; 			if ((lastseen == holder) && (lastseen != '(') && (lastseen != ')'))  /*"("情况特殊对待*/ 				PrintError = 1;	 			else 				lastseen = holder; 			if(IsEmpty(OpHolder)==1){	    /*当OpHolder为空*/ 				Push(holder,OpHolder); 			}  			else if(OperatorValue(Top(OpHolder)) == 6){  /*OpHolder是"("的情况*/ 				if(OperatorValue(holder)==5) 					Pop(OpHolder); 				else 					Push(holder,OpHolder); 			} 			else if(OperatorValue(holder) == 6){   				Push(holder,OpHolder); 			} 			else if(OperatorValue(holder) == 5){         /* OpHolder是" )"的情况*/ 				while ((IsEmpty(OpHolder) != 1) && (OperatorValue(Top(OpHolder)) != 6)) 				{   					putc(' ',Temp); 					Push('B',Whereat); 					putc(Top(OpHolder),Temp); 					Pop(OpHolder); 				} 				if (IsEmpty(OpHolder) == 1){          /*错误处理,括号不匹配*/ 					PrintError = 1;	 				} 				else  					Pop(OpHolder); 			} 			else if((OperatorValue(holder) == OperatorValue(Top(OpHolder)))  				&& (OperatorValue(holder) == 3)){      /*幂运算情况*/ 					Push(holder,OpHolder); 			} 			else if((OperatorValue(holder) < OperatorValue(Top(OpHolder)))  				&& OperatorValue(Top(OpHolder)) == 3){  /*幂运算情况*/ 					putc(' ',Temp); 					Push('B',Whereat);    					putc(Top(OpHolder),Temp); 					Pop(OpHolder); 					while((IsEmpty(OpHolder) != 1) && (OperatorValue(Top(OpHolder)) == 3)) 					{ 						Push('B',Whereat); 						putc(' ',Temp);	 						putc(Top(OpHolder),Temp);  						Pop(OpHolder); 					} 					Push(holder,OpHolder); 			} 			/****** 			如果当前运算符号的优先级小于或者等于堆栈中的运算符号的优先级,则将其放入temp中，并且将堆栈中的运算符号出栈，放入temp中，直到堆栈为空或者优先级小于堆栈顶元素的优先级 			******/ 			else if(OperatorValue(Top(OpHolder)) >= OperatorValue(holder)){	 				while((IsEmpty(OpHolder) != 1)  					&& (OperatorValue(Top(OpHolder)) >= OperatorValue(holder))  					&& (OperatorValue(Top(OpHolder))!=6)) 				{ 					putc(' ',Temp);	 					putc(Top(OpHolder),Temp); 					Push('B',Whereat); 					Pop(OpHolder); 				} 				Push(holder,OpHolder); 			} 			else if(OperatorValue(Top(OpHolder)) < OperatorValue(holder)){    				/****** 				如果当前运算符号的优先级大于堆栈中的运算符号的优先级,则将其压入堆栈中 				******/ 				Push(holder,OpHolder); 			} 		} 		holder=getc(In);	 	}	                                 /* While循环结束*/  	while(IsEmpty(OpHolder)!=1){  		/****** 		最后如果堆栈中还有运算符号，则一并放到temp中 		******/ 		Push('B',Whereat); 		putc(' ',Temp);	 		putc(Top(OpHolder),Temp); 		Pop(OpHolder); 	} 	MakeEmpty(OpHolder);  	free(OpHolder); }  /******判断类型，1为运算符号，0为操作数，-1为错误******/ int IsOperator(char ToCompare) { 	if (ToCompare == '(' || ToCompare == ')'|| ToCompare == '+' || ToCompare == '-'  		|| ToCompare == '*'|| ToCompare == '/' || ToCompare == '^'|| ToCompare == '%') 	{ 		return 1; 	} 	else if (ToCompare == '1' || ToCompare == '2'|| ToCompare == '3'  		|| ToCompare == '4' || ToCompare == '5'|| ToCompare == '6'  		|| ToCompare == '7'|| ToCompare == '8' || ToCompare == '9' 		|| ToCompare == '0'|| ToCompare == '.') 	{ 		return 0; 	} 	else{ 		return -1; 	} }  /******返回运算符号的优先级******/ int OperatorValue(char ValueToGive) { 	if (ValueToGive == '(') 		return 6; 	if (ValueToGive == ')') 		return 5; 	if (ValueToGive == '^')	 		return 3; 	if (ValueToGive == '%')	 		return 2; 	if (ValueToGive == '*')  		return 2; 	if (ValueToGive == '/') 		return 2; 	if (ValueToGive == '+') 		return 1; 	if (ValueToGive == '-') 		return 1; 	return 0; }  /******计算后缀表达式******/ void Calculate(FILE *Change, Stack Whereat, FILE *Temp) { 	FStack Operands; 	float looker; 	char Op; 	char spacefinder; 	float answer = 0; 	float NumA; 	float NumB; 	Operands = (Ptr_Fn)malloc(sizeof(struct FNode)); 	Operands->Next= NULL;  	while ((IsEmpty(Whereat) != 1) && PrintError != 1)  	{                         /*循环直到Whereat空，或者遇到错误*/ 		if (Top(Whereat) == 'A'){ 			fscanf(Temp," ",&spacefinder); 			fscanf(Temp,"%f",&looker);	     /*如果是A,则是操作数*/ 			FPush(looker,Operands);	 			Pop(Whereat); 		} 		else if (Top(Whereat) == 'B'){ 			fscanf(Temp," ",&spacefinder);     /*如果是B,则是运算符*/ 			Op = getc(Temp);	 			switch(Op){	  /* 判断是什么运算符*/ 			case('^'):                       /*幂运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	  /*错误处理*/ 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if ((NumA == 0 && NumB < 0)||((NumA<0)  						&& (NumB - (int)NumB != 0))) 					{ 						PrintError = 1; 					} 					else{ 						answer = pow(NumA,NumB); 						FPush(answer,Operands); 					} 				} 				break; 			case '%':                         /*取模运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	/*错误处理*/ 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if ((NumA - (int)NumA != 0) || (NumB - (int)NumB != 0)  						|| (NumB == 0)) 					{ 						PrintError = 1; 					} 					else{ 						answer = (int)NumA % (int)NumB;	  /* x mod b*/ 						FPush(answer,Operands); 					} 				} 				break; 			case '*':                                       /*乘法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA * NumB;	  /* x * y*/ 					FPush(answer,Operands); 				} 				break; 			case '/':                                        /*除法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if (NumB == 0){ 						PrintError = 1;	                 /*分母不为0*/ 					} 					else{ 						answer = (float)(NumA / NumB);	 /* x / y*/ 						FPush(answer,Operands); 					} 				} 				break; 			case '+':                                      /*加法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA + NumB;	/* x + y*/ 					FPush(answer,Operands); 				} 				break; 			case '-':                                      /*减法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){   					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA - NumB;	/* x - y*/ 					FPush(answer,Operands); 				} 				break; 			default: 				PrintError = 1; 				break; 			}                                          /*判断结束*/ 			Pop(Whereat); 		} 	}                                                  /*循环结束*/ 	if (!PrintError){	 		answer =  FTop(Operands); 		FPop(Operands); 		if (FIsEmpty(Operands) != 1){ 			fprintf(Change,"Error in infix notation.");         /*如果还有操作数*/ 			PrintError = 0; 		} 		else 			fprintf(Change,"%.2f",answer);	 	} 	else{ 		fprintf(Change,"Error in infix notation.");	 		PrintError = 0; 	} 	FMakeEmpty(Operands); 	free(Operands); }

1.好几处malloc(sizeof(struct Node));改为 (Stack)malloc(sizeof(struct Node)); 2.FMakeEmpty函数里IsEmpty应该是FIsEmpty，Pop应该是FPop 3.IsOperator和OperatorValue函数需要前置声明  #include <stdio.h> #include <stdlib.h> #include <math.h>  int PrintError = 0; /*全局变量，0代表正常，1代表表达式出错*/  /*char类型链表式堆栈，用来存放运算符号，以及用在中缀表达式转换等时候*/ typedef struct Node *PtrToNode; typedef PtrToNode Stack; int IsEmpty(Stack S); void MakeEmpty(Stack S); void Push(char X,Stack S); char Top(Stack S); void Pop(Stack S);  typedef struct Node{ 	char Element; 	PtrToNode Next; };  /*float类型链表式堆栈，用来存放操作数*/ typedef struct FNode *Ptr_Fn; typedef Ptr_Fn FStack; int FisEmpty(FStack S); void FPush(float X,FStack S); float FTop(FStack S); void FPop(FStack S);  typedef struct FNode{ 	float Element; 	Ptr_Fn Next; };  void ConvertToPost(FILE *In, Stack Whereat,FILE *Temp); void Reverse(Stack Rev); void Calculate(FILE *Change, Stack Whereat,FILE *Temp);  /******主函数******/ int main() { 	FILE *InputFile, *OutputFile,*Temp;	/*初始化变量*/ 	Stack Whereat;	 	char sample; 	InputFile = fopen("Input.txt","r");	/*打开文件*/ 	OutputFile = fopen("Output.txt","w");  	Whereat = (Stack)malloc(sizeof(struct Node));	/*给 Whereat分配空间*/ 	Whereat->Next = NULL; 	if (!InputFile || !OutputFile) {	                /*错误处理*/ 		printf("intput or output file(s) do not exist.\n"); 		return(1); 	} 	sample = getc(InputFile);            	while ( sample != EOF){ 		Temp = fopen("Temp.txt","w+");	 /*生成Temp文件*/ 		ungetc(sample,InputFile);	 /* put back sample字符*/ 		ConvertToPost(InputFile,Whereat,Temp);	 /*中缀变后缀*/ 		if (PrintError){                             /*错误处理*/ 			fprintf(OutputFile,"Error in infix notation.");	  			fscanf(InputFile,"\n",&sample); 			PrintError = 0; 		} 		else if (IsEmpty(Whereat) == 1){              /*跳过在input文件中的空格*/ 		} 		else if (IsEmpty(Whereat) != 1){ 			Reverse(Whereat); 			if (Top(Whereat) == 'B'){	    /*错误处理，*/ 				/*A表示操作数B表示运算符*/ 				PrintError = 1;     	/*后缀表达式第一个元素应是操作数而不是运算符号*/ 			} 			fclose(Temp); 			Temp = fopen("Temp.txt","r+");	 			Calculate(OutputFile, Whereat,Temp);	/*计算结果*/ 		} 		fclose(Temp);	 		MakeEmpty(Whereat);	/* 清空Whereat用来处理下一行*/ 		putc('\n',OutputFile);	/* 在输出文件中换行*/ 		sample = getc(InputFile);	 	}                                           /* While循环结束*/ 	free(Whereat);                                   	fclose(InputFile); 	fclose(OutputFile); 	remove("Temp.txt");                           /* 删除Temp.txt*/ 	return 1; }  /******检查堆栈是否为空******/ int IsEmpty(Stack S) {	 	return(S->Next==NULL);	 }  /******检查float堆栈是否为空******/ int FIsEmpty(FStack S) {	 	return(S->Next==NULL);	 }  /******弹出栈顶元素******/ void Pop(Stack S) {	 	PtrToNode FirstCell; 	if (IsEmpty(S)) 		perror("Empty Stack");	 	else{ 		FirstCell = S->Next; 		S->Next = S->Next->Next; 		free(FirstCell); 	} } /******弹出float栈顶元素******/ void FPop(FStack S) {	 	Ptr_Fn FirstCell; 	if (FIsEmpty(S)) 		perror("Empty Stack");	 	else{ 		FirstCell = S->Next; 		S->Next = S->Next->Next; 		free(FirstCell); 	} }  /******将堆栈置空******/ void MakeEmpty(Stack S) {	 	if (S == NULL) 		perror("Must use Createstack first"); 	else 		while (!IsEmpty(S)) 			Pop(S); }  /******将float堆栈置空******/ void FMakeEmpty(FStack S) {	 	if (S == NULL) 		perror("Must use Createstack first"); 	else 		while (!FIsEmpty(S)) 			FPop(S); }

/******元素进栈******/ void Push(char X, Stack S) {		 	PtrToNode TmpCell; 	TmpCell = (PtrToNode)malloc(sizeof(struct Node)); 	if (TmpCell == NULL) 		perror("Out of Space!"); 	else{ 		TmpCell->Element = X; 		TmpCell->Next = S->Next; 		S->Next = TmpCell; 	} }  /******float元素进栈******/ void FPush(float X, FStack S) {		 	Ptr_Fn TmpCell; 	TmpCell = (Ptr_Fn)malloc(sizeof(struct FNode)); 	if (TmpCell == NULL) 		perror("Out of Space!"); 	else{ 		TmpCell->Element = X; 		TmpCell->Next = S->Next; 		S->Next = TmpCell; 	} }  /******返回栈顶元素******/ char Top(Stack S) { 	if (!IsEmpty(S)) 		return S->Next->Element;	 	perror("Empty Stack"); 	exit(1); 	return 0; }  /******返回float栈顶元素******/ float FTop(FStack S) { 	if (!FIsEmpty(S)) 		return S->Next->Element; 	perror("Empty Stack"); 	exit(1); 	return 0; }  /******将堆栈元素倒置******/ void Reverse(Stack Rev) { 	Stack Tempstack; 	Tempstack = malloc(sizeof(struct Node)); 	Tempstack->Next = NULL; 		while (!IsEmpty(Rev)){ 			Push(Top(Rev),Tempstack);  	 /*将元素压栈到一个临时堆栈*/ 			Pop(Rev); 		} 		Rev->Next = Tempstack->Next;   	/*指向新的堆栈*/ }   /******* Whereat 说明: Whereat 记录了操作数和运算符号的位置，用A和B区分。A = operand, B = operator.  (例如 1+2转换成12+,在whereat中的形式应该是 AAB) OpHolder说明: Char类型的堆栈Opholder用来保存运算符号。 ******/  /******将中缀表带式转换为后缀表达式******/ void ConvertToPost(FILE *In, Stack Whereat, FILE *Temp) { 	Stack OpHolder; 	char holder; 	char lastseen; 	int digitcounter = 0;                       /*操作数的计数器*/ 	OpHolder = malloc(sizeof(struct Node));      /*初始化*/ 	OpHolder->Next = NULL; 	holder=getc(In); 	lastseen = '@';                           /*用来防止输入格式错误，例如两个小数点*/ 	putc(' ',Temp);   	while ((holder !='\n') && (holder != EOF)){ 		if (holder == ' '){ 			digitcounter = 0; 		} 		else if ( IsOperator(holder) == -1){       /*如果holder不是操作数或运算符号*/ 			PrintError = 1; 		} 		else if (IsOperator(holder)==0){ 			if ((lastseen == holder) && (lastseen == '.')){   /*错误处理*/ 				PrintError = 1; 			} 			else 				lastseen = holder; 			if (digitcounter == 0){				 				Push('A',Whereat);             /*进栈*/ 				digitcounter++;				/*计数器加一*/ 				putc(' ',Temp); 			} 			putc(holder,Temp); 		} 		else{ 			digitcounter = 0; 			if ((lastseen == holder) && (lastseen != '(') && (lastseen != ')'))  /*"("情况特殊对待*/ 				PrintError = 1;				 			else 				lastseen = holder; 			if(IsEmpty(OpHolder)==1){		    /*当OpHolder为空*/ 				Push(holder,OpHolder); 			}  			else if(OperatorValue(Top(OpHolder)) == 6){  /*OpHolder是"("的情况*/ 				if(OperatorValue(holder)==5) 					Pop(OpHolder); 				else 				Push(holder,OpHolder); 			} 			else if(OperatorValue(holder) == 6){   				Push(holder,OpHolder); 			} 			else if(OperatorValue(holder) == 5){         /* OpHolder是" )"的情况*/ 			while ((IsEmpty(OpHolder) != 1) && (OperatorValue(Top(OpHolder)) != 6)) 			{   					putc(' ',Temp); 					Push('B',Whereat); 					putc(Top(OpHolder),Temp); 					Pop(OpHolder); 				} 				if (IsEmpty(OpHolder) == 1){          /*错误处理,括号不匹配*/ 					PrintError = 1;	 				} 				else  					Pop(OpHolder); 			} 			else if((OperatorValue(holder) == OperatorValue(Top(OpHolder)))  					&& (OperatorValue(holder) == 3)){      /*幂运算情况*/ 				Push(holder,OpHolder); 			} 			else if((OperatorValue(holder) < OperatorValue(Top(OpHolder)))  					&& OperatorValue(Top(OpHolder)) == 3){  /*幂运算情况*/ 				putc(' ',Temp); 				Push('B',Whereat);    				putc(Top(OpHolder),Temp); 				Pop(OpHolder); 				while((IsEmpty(OpHolder) != 1) && (OperatorValue(Top(OpHolder)) == 3)) 				{ 					Push('B',Whereat); 					putc(' ',Temp);				 					putc(Top(OpHolder),Temp);  					Pop(OpHolder); 				} 				Push(holder,OpHolder); 			} /****** 如果当前运算符号的优先级小于或者等于堆栈中的运算符号的优先级,则将其放入temp中，并且将堆栈中的运算符号出栈，放入temp中，直到堆栈为空或者优先级小于堆栈顶元素的优先级 ******/ 			else if(OperatorValue(Top(OpHolder)) >= OperatorValue(holder)){			 				while((IsEmpty(OpHolder) != 1)  						&& (OperatorValue(Top(OpHolder)) >= OperatorValue(holder))  						&& (OperatorValue(Top(OpHolder))!=6)) 				{ 					putc(' ',Temp);	 					putc(Top(OpHolder),Temp); 					Push('B',Whereat); 					Pop(OpHolder); 				} 				Push(holder,OpHolder); 			} 			else if(OperatorValue(Top(OpHolder)) < OperatorValue(holder)){    /****** 如果当前运算符号的优先级大于堆栈中的运算符号的优先级,则将其压入堆栈中 ******/ 				Push(holder,OpHolder); 			} 		} 		holder=getc(In);	 	}	                                 /* While循环结束*/  	while(IsEmpty(OpHolder)!=1){  /****** 最后如果堆栈中还有运算符号，则一并放到temp中 ******/ 		Push('B',Whereat); 		putc(' ',Temp);		 		putc(Top(OpHolder),Temp); 		Pop(OpHolder); 	} 	MakeEmpty(OpHolder);  	free(OpHolder); }  /******判断类型，1为运算符号，0为操作数，-1为错误******/ int IsOperator(char ToCompare) { 	if (ToCompare == '(' || ToCompare == ')'|| ToCompare == '+' || ToCompare == '-'  		|| ToCompare == '*'|| ToCompare == '/' || ToCompare == '^'|| ToCompare == '%') 	{ 		return 1; 	} 	else if (ToCompare == '1' || ToCompare == '2'|| ToCompare == '3'  			|| ToCompare == '4' || ToCompare == '5'|| ToCompare == '6'  			|| ToCompare == '7'|| ToCompare == '8' || ToCompare == '9' 			|| ToCompare == '0'|| ToCompare == '.') 		{ 		   return 0; 	     } 	else{ 		return -1; 	} }  /******返回运算符号的优先级******/ int OperatorValue(char ValueToGive) { 	if (ValueToGive == '(') 		return 6; 	if (ValueToGive == ')') 		return 5; 	if (ValueToGive == '^')	 		return 3;     if (ValueToGive == '%')	 		return 2; 	if (ValueToGive == '*')  		return 2; 	if (ValueToGive == '/') 		return 2; 	if (ValueToGive == '+') 		return 1; 	if (ValueToGive == '-') 		return 1; 	return 0; }  /******计算后缀表达式******/ void Calculate(FILE *Change, Stack Whereat, FILE *Temp) { 	FStack Operands; 	float looker; 	char Op; 	char spacefinder; 	float answer = 0; 	float NumA; 	float NumB; 	Operands = (Ptr_Fn)malloc(sizeof(struct FNode)); 	Operands->Next= NULL;  	while ((IsEmpty(Whereat) != 1) && PrintError != 1)  	{                         /*循环直到Whereat空，或者遇到错误*/ 		if (Top(Whereat) == 'A'){ 			fscanf(Temp," ",&spacefinder); 			fscanf(Temp,"%f",&looker);	     /*如果是A,则是操作数*/ 			FPush(looker,Operands);	 			Pop(Whereat); 		} 		else if (Top(Whereat) == 'B'){ 			fscanf(Temp," ",&spacefinder);     /*如果是B,则是运算符*/ 			Op = getc(Temp);						 			switch(Op){					  /* 判断是什么运算符*/ 			case('^'):                       /*幂运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	  /*错误处理*/ 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if ((NumA == 0 && NumB < 0)||((NumA<0)  						&& (NumB - (int)NumB != 0))) 					{ 						PrintError = 1; 					} 					else{ 						answer = pow(NumA,NumB); 						FPush(answer,Operands); 					} 				} 				break; 			case '%':                         /*取模运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){		/*错误处理*/ 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if ((NumA - (int)NumA != 0) || (NumB - (int)NumB != 0)  						|| (NumB == 0)) 					{ 						PrintError = 1; 					} 					else{ 						answer = (int)NumA % (int)NumB;	  /* x mod b*/ 						FPush(answer,Operands); 					} 				} 				break; 			case '*':                                       /*乘法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA * NumB;				  /* x * y*/ 					FPush(answer,Operands); 				} 				break; 			case '/':                                        /*除法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					if (NumB == 0){ 						PrintError = 1;		                 /*分母不为0*/ 					} 					else{ 						answer = (float)(NumA / NumB);		 /* x / y*/ 						FPush(answer,Operands); 					} 				} 				break; 			case '+':                                      /*加法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){	 					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA + NumB;				/* x + y*/ 					FPush(answer,Operands); 				} 				break; 			case '-':                                      /*减法运算*/ 				NumB = FTop(Operands); 				FPop(Operands); 				if (FIsEmpty(Operands)){   					PrintError = 1; 				} 				else{ 					NumA = FTop(Operands); 					FPop(Operands); 					answer = NumA - NumB;				/* x - y*/ 					FPush(answer,Operands); 				} 				break; 			default: 				PrintError = 1; 				break; 			}                                          /*判断结束*/ 			Pop(Whereat); 		} 	}                                                  /*循环结束*/ 	if (!PrintError){		 		answer =  FTop(Operands); 		FPop(Operands); 		if (FIsEmpty(Operands) != 1){ 			fprintf(Change,"Error in infix notation.");         /*如果还有操作数*/ 			PrintError = 0; 		} 		else 			fprintf(Change,"%.2f",answer);			 	} 	else{ 		fprintf(Change,"Error in infix notation.");			 		PrintError = 0; 	} 	FMakeEmpty(Operands); 	free(Operands); }


Question: 这个延时程序看了很久都没弄懂到底延时时间是多少，求大神指点。

要看晶振了,通过晶振计算出执行一条指令需要的时间； 不过,这样的延时是不准确的,不如使用中断来做的精确

n*5000的量纲不是时间。

那我可以认为延时时间是n*5000吗？

使用电脑计时有时误差会很大，因为待测程序段的运行会影响电脑时钟。 将待测程序段循环足够多次，手动掐秒表计时可能更准确。

具体事件多少未知，反正是n * 5000次循环。

难到这个延时函数是错的？？

未知 .... 与太多东西相关了 ...  ================== 开了优化，可能没有任何延迟。整个函数都可能被完全优化掉。

我用的晶振是12M的，是用在单片机上面的。但是我没弄懂这个延时函数，所代表的延时时间。

既然是单片机，拿你可以读它的计时器计数，类似PC上8253/8254的计数器0，在两次计数之间调用delay，然后根据计数差值和晶振频率就可以算出时间。

延时有忙延时，和定时器延时两种方案 忙延时就是循环 需要跟汇编关联，确定每个指令执行多少周期 一共执行多少指令 然后延时 定时器延时，PC上，在多线程，多进程环境下，用的多点 嵌入式，也可自行处理， 或者采用实时操作系统，定时器来延时 定时器延时，基本不占用CPU。而是倚靠定时器硬件的定时中断，到达延时的目的

这跟指令周期有关（跟CPU速度相关：架构、流水线、频率、Cache等有关），单片机上可能有用，一般不这么用吧。

这是嵌入式里面的程序吗？

这个函数的延时时间需要你自己仿真。外部晶振不一样，延时时间是不同的！


Question: 本人新手，打出的程序错误有个错误一直改不对，哪位大神能帮忙修改一下

仅供参考：#include <conio.h> #include <stdio.h> char pw[40]; int i,ch; FILE *f; void main() {     cprintf("\r\nPassword:");     i=0;pw[i]=0;     while (1) {         ch=getch();         if (ch==13 || i>=39) break;         switch (ch) {         case 27:             cprintf("\rPassword: %40s"," ");             cprintf("\rPassword: ");             i=0;pw[i]=0;             break;         case 8:             if (i>0) {                 i--;                 pw[i]=0;                 cprintf("\b \b");             }             break;         default:             pw[i]=ch;             i++;             pw[i]=0;             cprintf("*");             break;         }     }     cprintf("\r\n");     f=fopen("password.txt","w");     fprintf(f,"%s\n",pw);     fclose(f); }

引用 12 楼 ooolinux的回复:main函数是空的，你想做什么？ 做一个班级档案管理系统，需要在前面加一个输入密码的功能

引用 11 楼 小灸舞的回复:你的编译器不认识bool C语言是没有bool型的。 但是，C99标准里面，又定义了bool类型变量。这时，只要引入头文件 <stdbool.h>，就能在C语言里面正常使用bool类型。 但是！！！！VC6太老了，是不支持的。 PS：不是一定要用VC6的话，建议换掉，换成VS 我们学的是VC6，而且作业要求是用VC6

main函数是空的，你想做什么？

引用 7 楼 小灸舞的回复:修改后的，你是编译过不去，还是运行错误？ 代码编译的时候就出现了错误

修改后的 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> bool Check(char pas[6])//密码验证 { 	FILE *fp;//文件类型指针型变量 	char ch; 	char a[7]={" "}; 	int i = 0; 	if ((fp=fopen("c:\\1.txt","r"))==NULL) //在C盘中建立文件名为1.txt的文档来存放密码 	{ 		printf("打开文件失败!\n"); 		exit(0); 	} 	ch=fgetc(fp); 	while (ch!=EOF&&i<6)//循环控制 	{ 		a[i] = ch; 		ch=fgetc(fp); 		i++;//自加1 	} 	a[6] = '\0';//正常结束的标志 	if (!strcmp(pas,a)) 	{ 		return true; 	} 	else 	{ 		printf("密码错误\n"); 		return false; 	} 	fclose(fp);//关闭一个流，原型是int fclose（FILE*stream）stream为流指针，返回EOF时表示出错。 } void main() {  } 错误提示 C:\Users\admin\Desktop\6.c(6) : error C2061: syntax error : identifier 'Check' C:\Users\admin\Desktop\6.c(6) : error C2059: syntax error : ';' C:\Users\admin\Desktop\6.c(6) : error C2059: syntax error : 'type' 6.exe - 1 error(s), 0 warning(s)

//原来的代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> bool Check(char pas[6])//密码验证 { 	FILE *fp;//文件类型指针型变量 	char ch; 	char a[7]={" "}; 	int i = 0; 	if ((fp=fopen("c:\\1.txt","r"))==NULL) //在C盘中建立文件名为1.txt的文档来存放密码 	{ 		printf("打开文件失败!\n"); 		exit(0); 	} 	ch=fgetc(fp); 	while (ch!=EOF&&i<6)//循环控制 	{ 		a[i] = ch; 		ch=fgetc(fp); 		i++;//自加1 	} 	a[6] = '\0';//正常结束的标志 	if (!strcmp(pas,a)) 	{ 		return true; 	} 	else 	{ 		printf("密码错误\n"); 		return false; 	} 	fclose(fp);//关闭一个流，原型是int fclose（FILE*stream）stream为流指针，返回EOF时表示出错。 } //代码错误 error C2061: syntax error : identifier 'Check' C:\Users\admin\Desktop\密码设计.c(5) : error C2059: syntax error : ';' C:\Users\admin\Desktop\密码设计.c(5) : error C2059: syntax error : 'type' 密码设计.exe - 1 error(s), 0 warning(s)

修改后的，你是编译过不去，还是运行错误？

引用 5 楼 小灸舞的回复:再重新贴下你的代码，顺便贴一下错误 原来的，还是修改后的

再重新贴下你的代码，顺便贴一下错误

引用 1 楼 小灸舞的回复:1.bool Check(char pas[6])后面多了个分号 2.没有main函数  #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> bool Check(char pas[6])//密码验证 { 	FILE *fp;//文件类型指针型变量 	char ch; 	char a[7]={" "}; 	int i = 0; 	if ((fp=fopen("c:\\1.txt","r"))==NULL) //在C盘中建立文件名为1.txt的文档来存放密码 	{ 		printf("打开文件失败!\n"); 		exit(0); 	} 	ch=fgetc(fp); 	while (ch!=EOF&&i<6)//循环控制 	{ 		a[i] = ch; 		ch=fgetc(fp); 		i++;//自加1 	} 	a[6] = '\0';//正常结束的标志 	if (!strcmp(pas,a)) 	{ 		return true; 	} 	else 	{ 		printf("密码错误\n"); 		return false; 	} 	fclose(fp);//关闭一个流，原型是int fclose（FILE*stream）stream为流指针，返回EOF时表示出错。 } void main() {  }  这是运行以后的错误，还是那个地方

引用 1 楼 小灸舞的回复:1.bool Check(char pas[6])后面多了个分号 2.没有main函数  #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> bool Check(char pas[6])//密码验证 { 	FILE *fp;//文件类型指针型变量 	char ch; 	char a[7]={" "}; 	int i = 0; 	if ((fp=fopen("c:\\1.txt","r"))==NULL) //在C盘中建立文件名为1.txt的文档来存放密码 	{ 		printf("打开文件失败!\n"); 		exit(0); 	} 	ch=fgetc(fp); 	while (ch!=EOF&&i<6)//循环控制 	{ 		a[i] = ch; 		ch=fgetc(fp); 		i++;//自加1 	} 	a[6] = '\0';//正常结束的标志 	if (!strcmp(pas,a)) 	{ 		return true; 	} 	else 	{ 		printf("密码错误\n"); 		return false; 	} 	fclose(fp);//关闭一个流，原型是int fclose（FILE*stream）stream为流指针，返回EOF时表示出错。 } void main() {  }  按照你的修改，我又试了一遍，还是那个地方有错误

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