Question: 进行删除操作后为什么操作的文件里面最后一条记录会变成两次，是不是需要进行分配的内存回收，怎么进行回收？是这个问题吗？

所谓修改删除文件a某位置的内容，其实是读打开文件a，再将‘a中修改删除位置之前的内容＋修改删除的内容＋a中修改删除位置之后的内容’保存到文件b，关闭文件a，删除文件a，将文件b改名为与之前文件a相同的名字，仅此而已。

不要使用 while (条件) 更不要使用 while (组合条件) 要使用 while (1) {  if (条件1) break;  //...  if (条件2) continue;  //...  if (条件3) return;  //... } 因为前两种写法在语言表达意思的层面上有二义性，只有第三种才忠实反映了程序流的实际情况。 典型如： 下面两段的语义都是当文件未结束时读字符 while (!feof(f)) {  a=fgetc(f);  //...  b=fgetc(f);//可能此时已经feof了！  //... } 而这样写就没有问题： while (1) {  a=fgetc(f);  if (feof(f)) break;  //...  b=fgetc(f);  if (feof(f)) break;  //... } 类似的例子还可以举很多。   “多一少一”问题占程序员常犯错误的10%以上！ 避免“多一少一”问题的方法之一是将比如<10甚至<5的数代入程序片断，搬手指头心算验证一下程序到底应该写为 x、x-1、x+1中的哪个？ <、<=、==、>、>=中的哪个？

仅供参考//假设带表头结点的单向链表头指针为head，试编写一个算法将值为5的结点插入到连接表的第k个结点前，删除第k个节点，并对该链表进行排序。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*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;     }      //将单链表中前 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; } //18->94->58->17->27->20->43->57->75->78-> //18->94->05->58->17->27->20->43->57->75->78-> //18->94->05->58->27->20->43->57->75->78-> //05->18->20->27->43->57->58->75->78->94-> //43->57->58->75->78->94->05->18->20->27-> //

进行删除一条记录的文件下一次导入时会出现最后一条记录会变成两次


Question: 各位大哥大姐 帮帮忙 偶是计算机菜鸟 要完成课程设计 这是我自己写 一直不知道怎么改

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

额 这个功能可以追加题目

#include<stdio.h> #include<stdlib.h> #include<windows.h> #include<string.h> #include<time.h> #include<conio.h> #define MAX 200 #define  N  30 int read(int k);/*读取文件并显示试卷*/ int test();/*选择试卷难度*/ void insert ();/*插入题库*/ int match(int n,char c,char a);/*判定正确与错误*/ struct question  {    char quest[MAX];    char option1[N];    char option2[N];    char option3[N];    char option4[N];    char ans; }; int i; int m; FILE *fp; struct question questdata[N]; /*用于存放试题的结构体数组*/ int main(void) { 	int x; 	int y; 	y=0; 	while(1) 	{ 		printf("\n欢迎登陆选择题标准化系统\n"); 		printf("\n "); 		printf(" \t完成试卷并评分 <1>\n"); 		printf(" \t导入试题库     <2>\n"); 		printf(" \t退出系统       <3>\n");          scanf("%d",&x);	 		while(x!=1&&x!=2&&x!=3) 		{ 			printf("请重新输入 选择<1-3>\n"); 		    scanf("%d",&x); 		} 		 		switch(x) 		{ 	    	case 1: 				{ 			     	system("cls"); 					m=test(); 					read(m); 					break; 				} 			case 2:  				{ 					system("cls");  			  		insert(); 				     break; 				} 			case 3: 				{ 					system("cls");   					y=2; 					break; 				} 			 		}         if(y==2) 			break; 			 	} 	return 0; }  int read(int k) {	 	int choice,j,a[30],total=0; 	srand(time(NULL));/*用于产生随机数*/ 	if((fp=fopen("e:\\test.txt","a"))==NULL)/*读取文件text.dat*/ 		printf("无法打开文件\n"); 	while(!feof(fp))/*使用feof函数检查文件是否结束*/ 		for(i=0;i<k;i++) 		{ 			a[i]=(rand()%k);/*产生随机数并保证不重复，如果一次相同i-1加一 保证m道题*/ 			if(i>0) 			for(j=i-1;j>=0;j--) 			{ 			   if(a[i]==a[j]) 			   { 				 i--; 				 break; 			   } 			   for(i=0;i<k;i++) 				j=a[i]; 			   fread(&questdata[j],sizeof(struct question),1,fp);/*随机读取m道题目*/ 		       printf("%d %s",i,questdata[j].quest[MAX]);/*输出试题*/ 			   printf("A %s",questdata[j].option1); 			   printf("B %s",questdata[j].option2); 			   printf("c %s",questdata[j].option3); 			   printf("D %s",questdata[j].option4); 			   printf("请输入答案：\n"); 			   scanf("%c",&choice); 			   total+=match(k,choice,questdata[j].ans); 			} 			   printf("你的总成绩为：%d",total); 		} 		return 1;  }    int test()/*根据难度选择试卷 难易体现在题量上*/ {    int n,m;    printf("\t\t\t请选择试卷难度:\n");    printf("\t\t1 容易 2 中等 3 困难\n");    scanf("%d",&n); 	while(n!=1&&n!=2&&n!=3) 	{ 		printf("\t\t请重新输入 选择<1-3>\n"); 	}    switch(n)    {       case 1: m=5; break;       case 2: m=10; break; 	  case 3: m=20; break;    }    return m; } //用于试卷评分 评一道题根据等级选择每道题分数  int match(int n,char c,char a) { 	int score; 	switch(n) 	{ 	  case 1: score=20; break;/*做对一道题的得分*/       case 2: score=10; break; 	  case 3: score=5; break; 	} 	if(c!=a)/*如果答案不正确，得分为0*/ 	{ 		score=0; 		printf("答案错误\n"); 	} 	else printf("答案正确\n"); 	return score; }  void insert() { 	while(1) 	{ 	  char sign; 	  int m; 	  FILE *fp;       struct question *p; 	 printf("请输入要插入的选择题数目:\n"); 	 scanf("%d",&m); 	 fflush(stdin);      for(i=0;i<m;i++) 	 {           p=(struct question*)malloc(sizeof(struct question)); 	      printf("请输入要插入的题干内容：\n"); 	      scanf("%s",&p[i].quest); 	      printf("请输入A选项内容\n"); 		  scanf("%s",&p[i].option1); 		   printf("请输入B选项内容\n"); 		   scanf("%s",&p[i].option2); 			printf("请输入C选项内容\n"); 		   scanf("%s",&p[i].option3); 	       printf("请输入D选项内容\n"); 		   scanf("%s",&p[i].option4); 	      printf("请输入答案选项<A-D>\n"); 		  scanf("%s",&p[i].ans); 		   fflush(stdin); 	 } 	    if(( fp=fopen("e:\\test.txt","a+"))==NULL) 		{ 			printf("文件不存在，现在已重新在指定路径生成文件\n"); 			fp=fopen("e:\\test.txt.","wb"); 		} 		if(fp==NULL) 		{ 			 printf("\n文件打开出错\n"); 			  getchar(); 			  exit(-1);  		} 	     fwrite(p,sizeof(struct question),1,fp); 	     fclose(fp); 	  	  printf("是否继续插入题目,继续请按Y,退出请按N\n"); 	   	   sign = getchar(); 		  if(sign == 'N'||sign == 'n') 		  { 			  system("cls");	//清屏函数 			  break; 		  }  	} 	 	 }  这是修改过的 但是那个试题的插入还是有点问题

为什么要一道一道去导入题目呢？直接把要导入的题目存放在文件里然后合并到原题库文件不就行了吗？

先把你的代码格式弄得好看点。 注意 锁紧、断行。


Question: 求助 怎么包含头文件和include的用法

引用 6 楼 u013539260 的回复:[quote=引用 2 楼 zhao4zhong1 的回复:] The #include Directive The #include directive tells the preprocessor to treat the contents of a specified file as if those contents had appeared in the source program at the point where the directive appears. You can organize constant and macro definitions into include files and then use #include directives to add these definitions to any source file. Include files are also useful for incorporating declarations of external variables and complex data types. You only need to define and name the types once in an include file created for that purpose.  Syntax  #include "path-spec"  #include <path-spec>  The path-spec is a filename optionally preceded by a directory specification. The filename must name an existing file. The syntax of the path-spec depends on the operating system on which the program is compiled.  Both syntax forms cause replacement of that directive by the entire contents of the specified include file. The difference between the two forms is the order in which the preprocessor searches for header files when the path is incompletely specified.  Syntax Form Action  Quoted form This form instructs the preprocessor to look for include files in the same directory of the file that contains the #include statement, and then in the directories of whatever files that include (#include) that file. The preprocessor then searches along the path specified by the /I compiler option, then along paths specified by the INCLUDE environment variable.  Angle-bracket form This form instructs the preprocessor to search for include files first along the path specified by the /I compiler option, then along the path specified by the INCLUDE environment variable.    The preprocessor stops searching as soon as it finds a file with the given name. If you specify a complete, unambiguous path specification for the include file between two sets of double quotation marks (" "), the preprocessor searches only that path specification and ignores the standard directories.  If the filename enclosed in double quotation marks is an incomplete path specification, the preprocessor first searches the “parent” file’s directory. A parent file is the file containing the #include directive. For example, if you include a file named file2 within a file named file1, file1 is the parent file.  Include files can be “nested”; that is, an #include directive can appear in a file named by another #include directive. For example, file2, above, could include file3. In this case, file1 would still be the parent of file2 but would be the “grandparent” of file3.  When include files are nested, directory searching begins with the directories of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source currently being processed. If the file is not found, the search moves to directories specified by the /I compiler option. Finally, the directories specified by the INCLUDE environment variable are searched.   The following example shows file inclusion using angle brackets:  #include <stdio.h>  This example adds the contents of the file named STDIO.H to the source program. The angle brackets cause the preprocessor to search the directories specified by the INCLUDE environment variable for STDIO.H, after searching directories specified by the /I compiler option.  The following example shows file inclusion using the quoted form:  #include "defs.h"  This example adds the contents of the file specified by DEFS.H to the source program. The double quotation marks mean that the preprocessor searches the directory containing the parent source file first.  Nesting of include files can continue up to 10 levels. Once the nested #include is processed, the preprocessor continues to insert the enclosing include file into the original source file.  Microsoft Specific   To locate includable source files, the preprocessor first searches the directories specified by the /I compiler option. If the /I option is not present or fails, the preprocessor uses the INCLUDE environment variable to find any include files within angle brackets. The INCLUDE environment variable and /I compiler option can contain multiple paths separated by semicolons (;). If more than one directory appears as part of the /I option or within the INCLUDE environment variable, the preprocessor searches them in the order in which they appear.  For example, the command  CL /ID:\MSVC\INCLUDE MYPROG.C  causes the preprocessor to search the directory D:\MSVC\INCLUDE for include files such as STDIO.H. The commands  SET INCLUDE=D:\MSVC\INCLUDE CL MYPROG.C  have the same effect. If both sets of searches fail, a fatal compiler error is generated.  If the filename is fully specified for an include file with a path that includes a colon (for example, F:\MSVC\SPECIAL\INCL\TEST.H), the preprocessor follows the path.  For include files specified as #include "path-spec", directory searching begins with the directory of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source file containing the #include directive being processed. If there is no grandparent file and the file has not been found, the search continues as if the filename were enclosed in angle brackets.  END Microsoft Specific 谢谢赵老师，很好奇这些资料你在哪里找的呢？你知道的，英文权威资料不好找啊。[/quote] MSDN98

一般的库里的用include<xxx>；自定义的用include "路径/xxx"；自定义的在同一目录下的话可以不用+路径

引用 2 楼 zhao4zhong1 的回复:The #include Directive The #include directive tells the preprocessor to treat the contents of a specified file as if those contents had appeared in the source program at the point where the directive appears. You can organize constant and macro definitions into include files and then use #include directives to add these definitions to any source file. Include files are also useful for incorporating declarations of external variables and complex data types. You only need to define and name the types once in an include file created for that purpose.  Syntax  #include "path-spec"  #include <path-spec>  The path-spec is a filename optionally preceded by a directory specification. The filename must name an existing file. The syntax of the path-spec depends on the operating system on which the program is compiled.  Both syntax forms cause replacement of that directive by the entire contents of the specified include file. The difference between the two forms is the order in which the preprocessor searches for header files when the path is incompletely specified.  Syntax Form Action  Quoted form This form instructs the preprocessor to look for include files in the same directory of the file that contains the #include statement, and then in the directories of whatever files that include (#include) that file. The preprocessor then searches along the path specified by the /I compiler option, then along paths specified by the INCLUDE environment variable.  Angle-bracket form This form instructs the preprocessor to search for include files first along the path specified by the /I compiler option, then along the path specified by the INCLUDE environment variable.    The preprocessor stops searching as soon as it finds a file with the given name. If you specify a complete, unambiguous path specification for the include file between two sets of double quotation marks (" "), the preprocessor searches only that path specification and ignores the standard directories.  If the filename enclosed in double quotation marks is an incomplete path specification, the preprocessor first searches the “parent” file’s directory. A parent file is the file containing the #include directive. For example, if you include a file named file2 within a file named file1, file1 is the parent file.  Include files can be “nested”; that is, an #include directive can appear in a file named by another #include directive. For example, file2, above, could include file3. In this case, file1 would still be the parent of file2 but would be the “grandparent” of file3.  When include files are nested, directory searching begins with the directories of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source currently being processed. If the file is not found, the search moves to directories specified by the /I compiler option. Finally, the directories specified by the INCLUDE environment variable are searched.   The following example shows file inclusion using angle brackets:  #include <stdio.h>  This example adds the contents of the file named STDIO.H to the source program. The angle brackets cause the preprocessor to search the directories specified by the INCLUDE environment variable for STDIO.H, after searching directories specified by the /I compiler option.  The following example shows file inclusion using the quoted form:  #include "defs.h"  This example adds the contents of the file specified by DEFS.H to the source program. The double quotation marks mean that the preprocessor searches the directory containing the parent source file first.  Nesting of include files can continue up to 10 levels. Once the nested #include is processed, the preprocessor continues to insert the enclosing include file into the original source file.  Microsoft Specific   To locate includable source files, the preprocessor first searches the directories specified by the /I compiler option. If the /I option is not present or fails, the preprocessor uses the INCLUDE environment variable to find any include files within angle brackets. The INCLUDE environment variable and /I compiler option can contain multiple paths separated by semicolons (;). If more than one directory appears as part of the /I option or within the INCLUDE environment variable, the preprocessor searches them in the order in which they appear.  For example, the command  CL /ID:\MSVC\INCLUDE MYPROG.C  causes the preprocessor to search the directory D:\MSVC\INCLUDE for include files such as STDIO.H. The commands  SET INCLUDE=D:\MSVC\INCLUDE CL MYPROG.C  have the same effect. If both sets of searches fail, a fatal compiler error is generated.  If the filename is fully specified for an include file with a path that includes a colon (for example, F:\MSVC\SPECIAL\INCL\TEST.H), the preprocessor follows the path.  For include files specified as #include "path-spec", directory searching begins with the directory of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source file containing the #include directive being processed. If there is no grandparent file and the file has not been found, the search continues as if the filename were enclosed in angle brackets.  END Microsoft Specific 谢谢赵老师，很好奇这些资料你在哪里找的呢？你知道的，英文权威资料不好找啊。

引用 3 楼 colddown 的回复:如果楼主用的是gcc, 可以用-E选项进行预编译，这样就能看出是include哪些文件了。头文件的搜寻路径一般以-I 或-i参数形式出现在gcc的命令行里，楼主可以看看Makefile。  不知道在哪里看makefie,请问下在哪里看呢？以前的都是.c在一个文件.h的在另一个文件。现在当文件很多的时候，我不知道怎么放头文件。

引用 1 楼 whustyle 的回复:1如果你所说的“几个路径”、“同一路径”是指文件目录的路径，那么自定义头文件是需要放在同一个工程文件夹路径下； 2 只要变量所在的头文件，存在于一系列包含链条之中，就可以使用而不报错。你所说的这个原因就是这样。 3 编译器自带头文件，例如math.h、stdlib.h等等，这些头文件和你自己的定义的头文件当然不在同一级目录下，因为你的自定义头文件一般放在工程文件夹目录以下某个位置，这是不会出错的。  1、为什么同一个头文件会出现在好几个路径下面，只出现在一个路径下面不可以吗？        我的意思是在同一个工程文件的有些.c文件会出现在不同文件夹下。 2、再请问下一个.c文件里面函数的作用域是.c文件所在的当前文件夹吗？这个文件夹的上级目录的代码可以引用这个.c文件定义的函数吗？这个文件夹的下级目录呢？ 谢谢


Question: C中按字节读文件读不出数据

试一下去  用C++把这个解决了  谢谢

试改如下:   FILE *fp,*fw;    int i = 0,j=0;    char id[32+1]; //改 char id[32];   unsigned int pid;    short type;    long tm;    char ip[257+1]; //改 char ip[257];    fp = fopen("wtmpx","rb");    fw = fopen("my","wb");     if (fp==NULL || fw==NULL)    {      cout<<"打开文件失败"<<endl;      exit(-1);    }     id[32] = 0; //加 字符串结尾   ip[257] = 0; //加 字符串结尾   while(1)    {      memset(id,0,sizeof(char)*32);       i=fread(id,32,1,fp);      if(i<=0)      {        break;      }      fseek(fp,36,SEEK_CUR);      memset(&pid,0,sizeof(unsigned int));      fread(&pid,4,1,fp);      memset(&type,0,sizeof(short));      fread(&type,2,1,fp);      fseek(fp,6,SEEK_CUR);      memset(&tm,0,sizeof(long));      fread(&tm,4,1,fp);      fseek(fp,30,SEEK_CUR);      memset(ip,0,sizeof(char)*257);      fread(ip,257,1,fp);        fseek(fp,1,SEEK_CUR);      printf("%s %d %d %ld %s\n",id,pid,type,tm,ip);        fprintf(fw,"%s %d %d %ld %s\n",id,pid,type,tm,ip);      cout<<"文件读取保存成功"<<endl;        //移出循环 fclose(fw);      //移出循环 fclose(fp);   }   fclose(fw);    fclose(fp);

引用 3 楼 zhao4zhong1 的回复:[quote=引用 2 楼 peaktravel 的回复:] 为什么需要改SEEK_SET，SEEK_CUR就是当前位置，我没必要去增加偏移量吧？ 你SEEK_CUR后调用ftell看看返回值指出你当前偏移量到底是多少。[/quote]  把那段代码放在while外面可以读欸     试试  谢谢

引用 2 楼 peaktravel 的回复:为什么需要改SEEK_SET，SEEK_CUR就是当前位置，我没必要去增加偏移量吧？ 你SEEK_CUR后调用ftell看看返回值指出你当前偏移量到底是多少。

请将所有的SEEK_CUR改为SEEK_SET并相应修改偏移量的值。 判断每次调用fseek的返回值。


Question: 小弟C语言课程设计遇阻，求大神给力助攻，跪谢！！！！！！！

哈哈，图书管理系统。之前也写过。工程实践来着

不知道你哪里遇到阻碍，你先得把你哪不会，或者哪出问题说清楚。

printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方，而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。  在每个最后不带\n的printf后面加fflush(stdout); 在每个不想受接收缓冲区旧内容影响的scanf前面加rewind(stdin); 另外请检查scanf的返回值。  代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了  不要使用 while (条件) 更不要使用 while (组合条件) 要使用 while (1) {  if (条件1) break;  //...  if (条件2) continue;  //...  if (条件3) return;  //... } 因为前两种写法在语言表达意思的层面上有二义性，只有第三种才忠实反映了程序流的实际情况。 典型如： 下面两段的语义都是当文件未结束时读字符 while (!feof(f)) {  a=fgetc(f);  //...  b=fgetc(f);//可能此时已经feof了！  //... } 而这样写就没有问题： while (1) {  a=fgetc(f);  if (feof(f)) break;  //...  b=fgetc(f);  if (feof(f)) break;  //... } 类似的例子还可以举很多。

我给你提供一个思路，你就自定义一个数据库文件Student.dat,用文件形式对其进行操作，


Question: C 语言中 #define CODE_P 用法

还不是太懂啊！呵呵 太菜了

问题不够清楚啊

就是在特定#if条件下让CODE_P变为空。  编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E


画画内存图就知道为什么了

printf("%d + %s = %s\n", a, b, a+b); 输出的是__func_version__

这个就是去除b加2地址的值，就看数据在寄存器中怎么存储的了 如下： 我的64位下面是： (gdb) p &b $3 = (char (*)[2]) 0x7fffffffe470             b的地址是这个 (gdb) p &__func_version__ $4 = (char (*)[2]) 0x7fffffffe480               数据5的地址是这个 (gdb) p b+a $5 = 0x7fffffffe472 " 14"                           b+a的地址是这个，现在这个地址中存储的数据是14。 所以b+a就是14了。

理解和讨论之前请先学会如何观察！

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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对应的汇编并单步执行观察相应内存和寄存器变化。）

引用 7 楼 u013163178 的回复:理解了，原来是是利用栈的生长方向和函数压栈来实现的。又学习了 理解了就OK^_^

16位编译器时代的东西，在32、64位时代玩会有些问题的。这么落伍的东西来了也不知道改一下。。。 这是原理分析图：

引用 6 楼 starytx 的回复:这个问题有意思的很啊，闲的蛋疼了可以研究一下你在嘲讽我，我已经知道是怎么实现的了，又长姿势了

理解了，原来是是利用栈的生长方向和函数压栈来实现的。又学习了

这个问题有意思的很啊，闲的蛋疼了可以研究一下

这个得编译器的，VC6就显示的不行。 VC6显示的是    烫5

我觉得，没准在某些系统或编译器有可能不是5，看栈内存怎么分配了

引用 1 楼 longburulin 的回复:有意思么 一个是指针 一个是数值，加起来也就是地址的值偏移了几位了 确实没什么意思，还不如直接这样更爽快 printf("%s", "2+2=5");

这里的b和a+b都是用%s作为字符串打出来的。b的内容是2，而a+b也就是b+2这个指针想必是指向了之前的__func_version__，所以就是5了

有意思么 一个是指针 一个是数值，加起来也就是地址的值偏移了几位了

加油吧，楼主~~~  推荐一本书：《程序员的自我修养----链接装载与库》

printf("%d + %s = %s\n", a, b, a+b);  想到了大学时一个C语言老师出的考题

好吧你们都没看到我的帖子啊： http://blog.csdn.net/mydo/article/details/34422733

玩的好高级~，不过对一般做项目的人来说，不能写这种代码

研究一般都有两个以上的方向， 大致上： 一个是顺的，研究事情如何做，如何做正确，如何做更好。 一个逆的，研究如何做会错误，会有什么样的错误，事情怎么能够做不出来。 有时候，需要二者结合，才能够把事情做好。。


有人在博客上问，所以贴在这里给他，就当发福利了。

楼主是在问问题还是在发代码福利


Question: C语言不强调函数前向声明导致的错误

引用 10 楼 grf123 的回复:#include<stdio.h> int add(float,float);    // 这样就叫显示声明了。 int main() { 	printf("%d\n",add(3.2,4.8));   // C是从上到下编译的，声明之后，编译器会在下面找。前面不声明，它就要默认为int 了。 	return  0; }  // 这里，叫定义，不叫声明。区分声明和定义。define and declare  int add(float a,float b) { 	printf("%f\n",a);//结果-0.000000 	printf("%f\n",b);//结果2.150000 	return 3; } 是定义就不叫声明？扯。

引用 7 楼 user-9 的回复:楼主没有搞清楚状况吧！  谁说C语言不要求前导声明啊，那叫隐式声明。  C99就不说了，二十多年前的C89就说的清清楚楚：     If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration           extern int  identifier(); 什么叫不说了，obselete还无视了？

是 printf("%f\n",add(3.0,4.0)); int printf( const char* format, ...);  后面 。。。 是 不知道 类型 的

需要前置声明的

这里说的很明显，编译器认为传给%f的是int，也就是默认声明的add的返回值类型 func.c:12:3: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat]

因为你没有事先声明，c编译器在main里面第一次见到add的时候会采取默认声明，把add作为一个返回int的函数。但是接下来定义的add是返回float，所以就冲突了 func.c:16:7: error: conflicting types for ‘add’  // 这里说的就是类型冲突，16行定义的float的add func.c:12:17: note: previous implicit declaration of ‘add’ was here  // 12行默认声明的int的add 虽然c不强制声明，还是都声明了比较稳妥，没必要跟自己跟编译器较劲

C语言强制要求函数使用前需声明

使用函数前都要申明一下！C语言应该是会进行参数检查的，我的看法！

长知识了！ 返回值默认为int，那隐式声明对函数的参数列表是怎么假设的？如下例子 传入的参数为什么是错误的？难道也默认为int吗？求指导！！ #include<stdio.h> int main() { 	printf("%d\n",add(3.2,4.8)); 	return  0; } int add(float a,float b) { 	printf("%f\n",a);//结果-0.000000 	printf("%f\n",b);//结果2.150000 	return 3; }


Question: 为结构体数组中的字符指针循环赋值的问题

引用 8 楼 zxh707wk 的回复:在给name复制前开辟一个空间 #include <stdio.h> #include <string.h> #include <malloc.h>  struct stu { 	int num; 	char* name; 	char sex; 	float score; };  int main(int argc, char* argv[])  { 	struct stu* p; 	int i; 	char str[20]; 	char ss[20] = "lucy"; 	char s[20]; 	p = (struct stu *)calloc(5, sizeof(struct stu)); 	for(i=0; i<5; i++) 	{ 		p->name=(char*)malloc(sizeof(char)*20); 		sprintf(str, "%d", i);  		strcpy(s, ss); 		strcat(s, str); 		strcpy(p->name, s); 		p++; 	} 	for(i=5; i>0; i--) 	{ 		--p; 		printf("%s\n", p->name); 	}	  	return 0; }  谢谢，这个正是我想要的效果呢！ 我早上5点钟就爬起来研究这个问题，当name是char *类型时，用strcpy(p->name, s);就会报错。原来是要先为p->name申请个内存空间，将其转换为数组，才行的。

引用 5 楼 baichi4141 的回复:p++->name=ss; 为什么那么多人喜欢用=复制字符串这个是用指针指向，不是复制

引用 5 楼 baichi4141 的回复:p++->name=ss; 为什么那么多人喜欢用=复制字符串  我是新手呵呵，一般正式开发中，怎样复制字符串呢？用malloc，strcpy还是memcpy？或者另外声明个全局字符数组？

p++->name=ss; 为什么那么多人喜欢用=复制字符串

引用 2 楼 anshiny 的回复:int main(int argc, char* argv[]) { 	struct stu{ 		int num; 		char name[20]; 		char sex; 		float score; 	} *p; 	int i; 	char str[5]; 	char ss[5] = "lucy"; 	char s[10]; 	 	p = (struct stu *)calloc(5, sizeof(struct stu));  	for(i=0; i<5; i++){ 		sprintf(str, "%d", i);  		strcpy(s, "lucy"); 		strcat(s, str); 		strcpy(p->name, s); 		p++; 	} 	 	for(i=5; i>0; i--){ 		--p; 		printf("%s\n", p->name); 	} 	 	return 0; }  你这里把str.name的类型由char *改成了char []，如果不改变原来的类型，则strcpy(p->name, s);无法使用，该怎样处理呢?

引用 1 楼 user-4 的回复:要做什么？ 如果是要解决局部量问题，那就扩大它的定义域，把它从循环体中拿出来 如果是要生成五个name，那就要有五个字符串容身的存储空间----只用一个ss数组能存储五个字符串？  这个也是种解决办法，在外面定义一个5个长度的字符数组，有没有更好点的办法呢？


Question: c語言實現rs232通過頭tx輸出rx輸入

引用 7 楼 u012293844 的回复:[quote=引用 5 楼 llxxhm 的回复:] [quote=引用 2 楼 u012293844 的回复:] [quote=引用 1 楼 zhao4zhong1 的回复:] 参考： MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DSP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RES MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RC MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\MAKEFILE MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\VERSION.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\RESOURCE.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.C MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\README.TXT MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.ICO MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.BMP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DEF板子上通過serial口插上serial線然後用金屬條將txrx相連 板子上運行程序能實現從tx傳數據給rx嗎？[/quote] 是的,TX和RX短接之后,硬件上就通了,只要驱动支持,应用就可以收到数据[/quote]但是我只要發送數據，機器就重啟[/quote] 如果应用可以用在其它地方接收串口数据,那很可能就是硬件的问题了

引用 5 楼 llxxhm 的回复:[quote=引用 2 楼 u012293844 的回复:] [quote=引用 1 楼 zhao4zhong1 的回复:] 参考： MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DSP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RES MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RC MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\MAKEFILE MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\VERSION.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\RESOURCE.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.C MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\README.TXT MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.ICO MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.BMP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DEF板子上通過serial口插上serial線然後用金屬條將txrx相連 板子上運行程序能實現從tx傳數據給rx嗎？[/quote] 是的,TX和RX短接之后,硬件上就通了,只要驱动支持,应用就可以收到数据[/quote]但是我只要發送數據，機器就重啟

//打开串口 hCOM = CreateFile("\\\\.\\COM3", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hCOM == INVALID_HANDLE_VALUE) { 	if ((i = GetLastError()) == 2)  		MessageBox(GetForegroundWindow(), TEXT("该串口不存在"), TEXT("操作失败"), MB_ICONINFORMATION); 	else if (i == 5) 		MessageBox(GetForegroundWindow(), TEXT("该串口已被占用"), TEXT("操作失败"), MB_ICONINFORMATION); 	else 		MessageBox(GetForegroundWindow(), TEXT("无法打开串口"), TEXT("操作失败"), MB_ICONINFORMATION); 	return TRUE; }  if (PurgeComm(hCOM, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR) == 0) { 	MessageBox(GetForegroundWindow(), TEXT("清除串口缓冲区出错"), TEXT("操作失败"), MB_ICONINFORMATION); 	return TRUE; }  //设置串口的波特率等等 if (!GetCommState(hCOM, &dcb)) { 	MessageBox(GetForegroundWindow(), TEXT("无法获取串口状态"), TEXT("操作失败"), MB_ICONINFORMATION); 	hCOM = INVALID_HANDLE_VALUE; 	return TRUE; } dcb.BaudRate = 9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; if (!SetCommState(hCOM, &dcb)) { 	MessageBox(GetForegroundWindow(), TEXT("无法设置串口状态"), TEXT("操作失败"), MB_ICONINFORMATION); 	hCOM = INVALID_HANDLE_VALUE; 	return TRUE; }  //设置串口超时 COMMTIMEOUTS communication_timeout; communication_timeout.ReadIntervalTimeout=MAXDWORD; communication_timeout.ReadTotalTimeoutMultiplier=200; communication_timeout.ReadTotalTimeoutConstant=1000; communication_timeout.WriteTotalTimeoutMultiplier=0; communication_timeout.WriteTotalTimeoutConstant=0; if (!SetCommTimeouts(hCOM, &communication_timeout)) { 	MessageBox(GetForegroundWindow(), TEXT("无法设置串口超时"), TEXT("操作失败"), MB_ICONINFORMATION); 	hCOM = INVALID_HANDLE_VALUE; 	return TRUE; }  //清除串口缓冲区 if (PurgeComm(hCOM, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR) == 0) { 	MessageBox(GetForegroundWindow(), TEXT("清除串口缓冲区出错"), TEXT("操作失败"), MB_ICONINFORMATION); 	return FALSE; }  //发送数据 BYTE cDataBuf[6]; DWORD dwBytesWriten, dwBytesReaded; cDataBuf[0] = 0x55; cDataBuf[1] = bType; cDataBuf[2] = 0xff; cDataBuf[3] = 0xff; cDataBuf[4] = 0xff; cDataBuf[5] = 0xaa; WriteFile(hCOM, cDataBuf, 6, &dwBytesWriten, NULL);  //接收数据 ReadFile(hCOM, cDataBuf, 6, &dwBytesReaded, NULL);

引用 2 楼 u012293844 的回复:[quote=引用 1 楼 zhao4zhong1 的回复:] 参考： MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DSP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RES MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RC MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\MAKEFILE MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\VERSION.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\RESOURCE.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.C MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\README.TXT MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.ICO MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.BMP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DEF板子上通過serial口插上serial線然後用金屬條將txrx相連 板子上運行程序能實現從tx傳數據給rx嗎？[/quote] 是的,TX和RX短接之后,硬件上就通了,只要驱动支持,应用就可以收到数据

引用 1 楼 zhao4zhong1 的回复:参考： MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DSP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RES MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.RC MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\MAKEFILE MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\VERSION.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\RESOURCE.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.H MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.C MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\README.TXT MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.ICO MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.BMP MSDN98\SAMPLES\VC98\SDK\WINBASE\IO\SERIAL\TTY.DEF板子上通過serial口插上serial線然後用金屬條將txrx相連 板子上運行程序能實現從tx傳數據給rx嗎？


Question: C语言结构体中用##的问题

引用 楼主 syrchina 的回复:程序如下， 问题在注释中：  #include<stdio.h> struct { float real; float imag; } complex; #define GetReal(x) (x##.real) //这个宏用了##符号，不能连接“.”号？ int main() { float r = 0; complex.real = 1; complex.imag = 2; r = GetReal(complex);//报错："complex" and "." dose not give a valid preprocessing token return 0; }  请各位大侠指教  ##并不是随便什么东西都可以组合的，##组合后的结果必须也是一个合法的token，而句点符号并不属于能够组成token的合法的词法要素，所以是错误的。

引用 1 楼 zhao4zhong1 的回复:#与##在宏定义中的--宏展开 #include <stdio.h> #define f(a,b) a##b #define g(a)   #a #define h(a) g(a) int main() {         printf("%s\n", h(f(1,2)));   // 12         printf("%s\n", g(f(1,2))); // f(1,2)         return 0; } 宏展开时： 如果宏定义以#开头，不展开参数，直接替换。 故g(f(1,2))--->#f(1,2)--->"f(1,2)"； 如果宏定义不以#开头，展开参数，直接替换，由外层向里层，如果碰到的是#开头的宏，不继续往里层展开，往外层展开。 由外层向里层，如果碰到的是以非#开头的宏，继续往里层走，直至最里层，开始一层层往外层展开。 故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。 PS： ##在宏中定义，是字符连接符 如a##b##c 等同于 "abc" #在宏开头出现，是表示宏展开的方式不同 #a 等同于"a" #abc 等同于 "abc" 复杂的: #include <stdio.h> #define f(a,b) a##b #define g(a)   #a #define h(a) g(a) int main() {         char a = 'a';         cout<<g(a)<<endl; // a         cout<<g(g(a))<<endl; // a         printf("%s\n", h(f(1,2)));   // 12         printf("%s\n", g(f(1,2))); // f(1,2)         printf("%s\n", g(h(f(1,2)))); // h(f(1,2))         printf("%s\n", h(g(f(1,2)))); // "f(1,2)"         printf("%s\n", h(h(f(1,2)))); // "12"         system("pause");         return 0; } 预处理后的：（在编译选项中添加/EP /P后编译生成的.i文件。gcc加-E） int main() {         char a = 'a';         cout<<"a"<<endl;         cout<<"g(a)"<<endl;         printf("%s\n", "12");         printf("%s\n", "f(1,2)");         printf("%s\n", "h(f(1,2))");         printf("%s\n", "\"f(1,2)\"");         printf("%s\n", "\"12\"");         system("pause");         return 0; } --------------------------------------------------- 宏解析 1.       ##操作符 ##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号，它不能出现于宏替代表的开端和末尾。 例： #define concat(s,t) s##t #define AAA ABC concat(A, AA) 将被替换成 ABC 2.       重新扫描和替换 在替换列表中的所有参数替换过之后，预处理器将对结果token序列重新扫描以便对其中的宏再次替换。 当正在替换的宏在其替换列表中发现自身时，就不再对其进行替换。在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换（防止递归）。 例： #define ROOT AAA CCC #define AAA ROOT ROOT 将被替换成 ROOT CCC  学习了！


Question: windows有没有类似linux中的poll函数

Windows下于串口异步通信，需要重叠I/O(Overlapped I/O)，操作完成会有Event通知，用WaitForSingleObject来等。看这篇文章吧： Serial Communications

windows有IOCP, 真正的异步IO


Question: 求问如何在gcc下压缩堆栈中变量的布局

对于门外汉的我来说，这些都是高精尖的技术呐

再up一下...

引用 31 楼 mydo 的回复:[quote=引用 30 楼 FrankHB1989 的回复:] [quote=引用 29 楼 mydo 的回复:] [quote=引用 12 楼 FrankHB1989 的回复:] 找到了一个个改然后自己艹后端代码去。  这个艹呢？我如果说“你自己艹xxx”，你作何感想呢？[/quote] 没啥感想，因为未来几年内GCC的代码整体而言名副其实地就是应该用f*cking形容的东西，后端代码也不例外。这只是不得不敲捣GCC intenal的倒霉孩子之间的自嘲罢了。 [/quote] 那你应该说gcc艹，或是艹gcc，或是fk gcc 哦。[/quote] 对GCC的局部修改也就是在fk了。撸码的结果也不会让它变得更好。  引用 32 楼 mydo 的回复:其实我也不想和你吵哦 引用 33 楼 mydo 的回复:害的这个帖子变成了吵架帖，没人关注了，哎。。。 本来就没想吵。 是不是容易被关注，主要还是看内容。 至少回复是在帮你顶上来了。

害的这个帖子变成了吵架帖，没人关注了，哎。。。

其实我也不想和你吵哦

引用 30 楼 FrankHB1989 的回复:[quote=引用 29 楼 mydo 的回复:] [quote=引用 12 楼 FrankHB1989 的回复:] 找到了一个个改然后自己艹后端代码去。  这个艹呢？我如果说“你自己艹xxx”，你作何感想呢？[/quote] 没啥感想，因为未来几年内GCC的代码整体而言名副其实地就是应该用f*cking形容的东西，后端代码也不例外。这只是不得不敲捣GCC intenal的倒霉孩子之间的自嘲罢了。 [/quote] 那你应该说gcc艹，或是艹gcc，或是fk gcc 哦。

引用 29 楼 mydo 的回复:[quote=引用 12 楼 FrankHB1989 的回复:] 找到了一个个改然后自己艹后端代码去。  这个艹呢？我如果说“你自己艹xxx”，你作何感想呢？[/quote] 没啥感想，因为未来几年内GCC的代码整体而言名副其实地就是应该用f*cking形容的东西，后端代码也不例外。这只是不得不敲捣GCC intenal的倒霉孩子之间的自嘲罢了。

引用 12 楼 FrankHB1989 的回复:找到了一个个改然后自己艹后端代码去。  这个艹呢？我如果说“你自己艹xxx”，你作何感想呢？

引用 27 楼 mydo 的回复:[quote=引用 24 楼 FrankHB1989 的回复:] [quote=引用 22 楼 mydo 的回复:] [quote=引用 9 楼 FrankHB1989 的回复:] -O3还艹布局，无聊过头了点。入门手段__attribute__((optimize("-O0"))要好好掌握。  没有你这个艹，何来滚蛋呢？[/quote] 所以说注意你的语文素质。 宾语是什么看清楚。 [/quote]  不管你艹什么，都是脏话，哪怕没有宾语。我在回帖中写 艹，fk，神马的你作何感想。[/quote] 偷换概念。脏话和骂人是一回事？ 判断是不是被骂了，可以通过上下文判断是在感叹还是祈使来分辨。 另外，虽然不值得人身攻击，但是你原文章里的题材的境界/高尚程度/逼格和这种表达也差不多。通晓C语言者应该很能“感同身受”才对。

引用 24 楼 FrankHB1989 的回复:[quote=引用 22 楼 mydo 的回复:] [quote=引用 9 楼 FrankHB1989 的回复:] -O3还艹布局，无聊过头了点。入门手段__attribute__((optimize("-O0"))要好好掌握。  没有你这个艹，何来滚蛋呢？[/quote] 所以说注意你的语文素质。 宾语是什么看清楚。 [/quote]  不管你艹什么，都是脏话，哪怕没有宾语。我在回帖中写 艹，fk，神马的你作何感想。

引用 25 楼 mydo 的回复:我根本没有删除任何回复，我只是添加新的回复内容，不行吗？  我版主就有这个权利，不行吗？ 行。 只是和职务无关的多余操作只会让人觉得你有更多机会在词穷时捣鬼而已。

引用 22 楼 mydo 的回复:[quote=引用 9 楼 FrankHB1989 的回复:] -O3还艹布局，无聊过头了点。入门手段__attribute__((optimize("-O0"))要好好掌握。  没有你这个艹，何来滚蛋呢？[/quote] 所以说注意你的语文素质。 宾语是什么看清楚。

引用 21 楼 mydo 的回复:C标准啊，不行吗？gcc支不支持C标准呢？ 哦，你还知道有C标准这么回事？哪个C标准？4L和6L的理由怎么看不懂？ 你倒是说说C标准哪个字跟你所谓的“堆栈”布局有关了？

引用 9 楼 FrankHB1989 的回复:-O3还艹布局，无聊过头了点。入门手段__attribute__((optimize("-O0"))要好好掌握。  没有你这个艹，何来滚蛋呢？

C标准啊，不行吗？gcc支不支持C标准呢？

引用 17 楼 mydo 的回复:[quote=引用 16 楼 DBA_Huangzj 的回复:] 回帖的注意用词。。。  我都说了，根本没想吵。是谁首先骂的？[/quote] 是你的“不会就滚蛋，没人请你回答”。 注意你的语文素质。

填空题： 不会汇编的C/C++程序员都是____________。

引用 14 楼 mydo 的回复:我标题就TM是GCC下的，什么TM的方言，你脑袋怎么长得，小学语文几年级啊？ 你那篇文章的标题是《C语言里为何会有“2+2=5”的结果 》。至于这里的问题，在我之前也根本就没人有兴趣鸟。 别像滥用版主权限编辑掉这里的回复一样毁尸灭迹了。  引用 15 楼 mydo 的回复:我说的就是GCC标准，扯TMD什么方言  我本来不想吵，只想心平静气的讨论问题，可是某人上来就艹啊什么的 别装了。GCC哪来的什么标准。 打脸服务： https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/C-Dialect-Options.html#C-Dialect-Options 不认识什么叫dialect自己查字典。 你的问题就是在无理取闹。这本来不是C语言该管的。据我所知GCC的方言的spec在此也没提供任何保证。

引用 16 楼 DBA_Huangzj 的回复:回帖的注意用词。。。  我都说了，根本没想吵。是谁首先骂的？


Question: 以下代码段中，ret的结果是多少？

非常感谢给位的帮助！

//C++ Operators //  Operators specify an evaluation to be performed on one of the following: //    One operand (unary operator) //    Two operands (binary operator) //    Three operands (ternary operator) //  The C++ language includes all C operators and adds several new operators. //  Table 1.1 lists the operators available in Microsoft C++. //  Operators follow a strict precedence which defines the evaluation order of //expressions containing these operators.  Operators associate with either the //expression on their left or the expression on their right;    this is called //“associativity.” Operators in the same group have equal precedence and are //evaluated left to right in an expression unless explicitly forced by a pair of //parentheses, ( ). //  Table 1.1 shows the precedence and associativity of C++ operators //  (from highest to lowest precedence). // //Table 1.1   C++ Operator Precedence and Associativity // The highest precedence level is at the top of the table. //+------------------+-----------------------------------------+---------------+ //| Operator         | Name or Meaning                         | Associativity | //+------------------+-----------------------------------------+---------------+ //| ::               | Scope resolution                        | None          | //| ::               | Global                                  | None          | //| [ ]              | Array subscript                         | Left to right | //| ( )              | Function call                           | Left to right | //| ( )              | Conversion                              | None          | //| .                | Member selection (object)               | Left to right | //| ->               | Member selection (pointer)              | Left to right | //| ++               | Postfix increment                       | None          | //| --               | Postfix decrement                       | None          | //| new              | Allocate object                         | None          | //| delete           | Deallocate object                       | None          | //| delete[ ]        | Deallocate object                       | None          | //| ++               | Prefix increment                        | None          | //| --               | Prefix decrement                        | None          | //| *                | Dereference                             | None          | //| &                | Address-of                              | None          | //| +                | Unary plus                              | None          | //| -                | Arithmetic negation (unary)             | None          | //| !                | Logical NOT                             | None          | //| ~                | Bitwise complement                      | None          | //| sizeof           | Size of object                          | None          | //| sizeof ( )       | Size of type                            | None          | //| typeid( )        | type name                               | None          | //| (type)           | Type cast (conversion)                  | Right to left | //| const_cast       | Type cast (conversion)                  | None          | //| dynamic_cast     | Type cast (conversion)                  | None          | //| reinterpret_cast | Type cast (conversion)                  | None          | //| static_cast      | Type cast (conversion)                  | None          | //| .*               | Apply pointer to class member (objects) | Left to right | //| ->*              | Dereference pointer to class member     | Left to right | //| *                | Multiplication                          | Left to right | //| /                | Division                                | Left to right | //| %                | Remainder (modulus)                     | Left to right | //| +                | Addition                                | Left to right | //| -                | Subtraction                             | Left to right | //| <<               | Left shift                              | Left to right | //| >>               | Right shift                             | Left to right | //| <                | Less than                               | Left to right | //| >                | Greater than                            | Left to right | //| <=               | Less than or equal to                   | Left to right | //| >=               | Greater than or equal to                | Left to right | //| ==               | Equality                                | Left to right | //| !=               | Inequality                              | Left to right | //| &                | Bitwise AND                             | Left to right | //| ^                | Bitwise exclusive OR                    | Left to right | //| |                | Bitwise OR                              | Left to right | //| &&               | Logical AND                             | Left to right | //| ||               | Logical OR                              | Left to right | //| e1?e2:e3         | Conditional                             | Right to left | //| =                | Assignment                              | Right to left | //| *=               | Multiplication assignment               | Right to left | //| /=               | Division assignment                     | Right to left | //| %=               | Modulus assignment                      | Right to left | //| +=               | Addition assignment                     | Right to left | //| -=               | Subtraction assignment                  | Right to left | //| <<=              | Left-shift assignment                   | Right to left | //| >>=              | Right-shift assignment                  | Right to left | //| &=               | Bitwise AND assignment                  | Right to left | //| |=               | Bitwise inclusive OR assignment         | Right to left | //| ^=               | Bitwise exclusive OR assignment         | Right to left | //| ,                | Comma                                   | Left to right | //+------------------+-----------------------------------------+---------------+

true ,0XFFFF = 0XFFFF


Question: scanf的问题

#include <stdio.h> char s[]="123 ab 4"; char *p; int v,n,k; void main() {     p=s;     while (1) {         k=sscanf(p,"%d%n",&v,&n);         printf("k,v,n=%d,%d,%d\n",k,v,n);         if (1==k) {             p+=n;         } else if (0==k) {             printf("skip char[%c]\n",p[0]);             p++;         } else {//EOF==k             break;         }     }     printf("End.\n"); } //k,v,n=1,123,3 //k,v,n=0,123,3 //skip char[ ] //k,v,n=0,123,3 //skip char[a] //k,v,n=0,123,3 //skip char[b] //k,v,n=1,4,2 //k,v,n=-1,4,2 //End.

作为一个C程序员，对  scanf,sscanf,fscanf  printf,sprintf,fprintf 这类函数的用法，还是要做到“拳不离手，曲不离口”的。

引用 6 楼 czarten 的回复:最后一个问题，为什么只有第一次scanf需要输入两次，后面的都不需要呢，我给你演示一下过程你就懂了： 引用 8 楼 zhao4zhong1 的回复:http://bbs.csdn.net/topics/390817373  喃俩是被我的结贴速度感动了吗  我都看了，谢谢  确实scanf用到的时候不多，才注意这个问题  英语也是硬伤

White-space characters: blank (' '); tab ('\t'); or newline ('\n').  空白字符包括：空格(' ');制表符('\t');或换行符('\n').  A white-space character causes scanf to read, but not store, all consecutive white-space characters in the input up to the next non–white-space character.   一个空白字符导致scanf从输入缓冲区中读入所有后续的空白符直到遇到非空白符为止，且不保存。  One white-space character in the format matches any number (including 0) and combination of white-space characters in the input. 在格式符中的一个空白字符匹配输入缓冲区中的任意个（包括0个）空白符以及空白符的任意组合。  英语也是一门计算机语言的说。  2楼内容可以作为计算机专业英语英译汉的典型练习题。

最后一个问题，为什么只有第一次scanf需要输入两次，后面的都不需要呢，我给你演示一下过程你就懂了：  首先我们系统里有个键盘缓冲区，键盘上按下的字符都送到缓冲区里，scanf也是从缓冲区里读取，这个不清楚你知不知道  一开始，缓冲区是空的，scanf("%d\n")等着你输入第一个数  你输入：１，回车 １进入缓冲区，被%d吃掉，回车进入缓冲区，被\n吃掉，scanf等着你结束输入  你输入：２，回车 ２进入缓冲区，scanf发现不是它要的，忽略，回车进入缓冲区，scanf看到回车，知道输入结束了  接下来是第二次scanf("%d\n") 注意此时缓冲区不是空的，里面有你刚才敲进去的2和回车！于是２和回车直接被%d和\n读取，scanf等你结束输入 你不知道scanf这小子已经把该读的都读完了，以为它在等你输入，于是敲了３和回车 同样，３和回车进入缓冲区，scanf看到回车结束输入，而这个３和回车留给了下一次scanf  所以，你第一次输入的两个数，实际上给了第一个和第二个变量 第二次输入的数，实际上给了第三个变量 不信你可以输出来看看，是不是错位的

我来给你说吧。  scanf("%d\n",&pos1[ii]); 这句scanf不该加那个\n，否则你输入完后，按下回车，这个回车就被\n匹配了，而不被认为是结束输入，所以系统继续等着你结束输入，你要再来一个回车，才会按结束输入处理。  如果你去试试，第一次输入的时候，输入一个数，按两次回车，会发现仍然不行，系统依旧等着你输入 这个是因为，一个\n可以匹配连续的多个换行，类似于scanf("%d %d",&a,&b)这句话，两个数中间有个空格，但是你输入两个空格三个空格都行，都只当做一个空格，同理这里的\n不管你连续按多少次回车，都会被这个\n吃掉  而你再输入一个数后再按回车，就输入成功了，这是因为，刚才我说了，一个\n是匹配连续的多个换行，你输入了别的东西，再来一个换行就不是连续的了，就不会被\n吃掉，就会作为输入结束符处理

1楼已经解释的很清楚了。

把scanf里的换行去掉则正常，这个怎么解释

引用 1 楼 zhao4zhong1 的回复:scanf("%d",&pos1[ii]);  请检查scanf的返回值。   输入的第一串字符scanf没有返回

scanf("%d",&pos1[ii]);  请检查scanf的返回值。  Format Specification Fields: scanf and wscanf Functions A format specification has the following form:  % [width] [{h | l | I64 | L}]type  The format argument specifies the interpretation of the input and can contain one or more of the following:   White-space characters: blank (' '); tab ('\t'); or newline ('\n'). A white-space character causes scanf to read, but not store, all consecutive white-space characters in the input up to the next non–white-space character. One white-space character in the format matches any number (including 0) and combination of white-space characters in the input.   Non–white-space characters, except for the percent sign (%). A non–white-space character causes scanf to read, but not store, a matching non–white-space character. If the next character in stdin does not match, scanf terminates.   Format specifications, introduced by the percent sign (%). A format specification causes scanf to read and convert characters in the input into values of a specified type. The value is assigned to an argument in the argument list.  The format is read from left to right. Characters outside format specifications are expected to match the sequence of characters in stdin; the matching characters in stdin are scanned but not stored. If a character in stdin conflicts with the format specification, scanf terminates, and the character is left in stdin as if it had not been read.  When the first format specification is encountered, the value of the first input field is converted according to this specification and stored in the location that is specified by the first argument. The second format specification causes the second input field to be converted and stored in the second argument, and so on through the end of the format string.  An input field is defined as all characters up to the first white-space character (space, tab, or newline), or up to the first character that cannot be converted according to the format specification, or until the field width (if specified) is reached. If there are too many arguments for the given specifications, the extra arguments are evaluated but ignored. The results are unpredictable if there are not enough arguments for the format specification.  Each field of the format specification is a single character or a number signifying a particular format option. The type character, which appears after the last optional format field, determines whether the input field is interpreted as a character, a string, or a number.   The simplest format specification contains only the percent sign and a type character (for example, %s). If a percent sign (%) is followed by a character that has no meaning as a format-control character, that character and the following characters (up to the next percent sign) are treated as an ordinary sequence of characters, that is, a sequence of characters that must match the input. For example, to specify that a percent-sign character is to be input, use %%.  An asterisk (*) following the percent sign suppresses assignment of the next input field, which is interpreted as a field of the specified type. The field is scanned but not stored.


Question: c语言编写函数 输入一个整数  输出对应的字符串

前辈们 ： while(1) 是什么意思啊

引用 1 楼 czarten 的回复:如果整数是从１开始连续的，搞个字符指针数组就好了嗯，如果不是的话，用switch也行

引用 6 楼 zhao4zhong1 的回复:#include <stdio.h> #include <string.h> char s[3][20]={     "It is error!",     "It is ok!",     "It may ok.", }; int main() {     int i;      while (1) {         printf("Input a number(0..2):");         fflush(stdout);         rewind(stdin);         if (1==scanf("%d",&i)) {             if (0<=i && i<=2) {                 printf("%s\n",s[i]);                 continue;             }         }         printf("Format error!\n");         break;     }     return 0; } //Input a number(0..2):0 //It is error! //Input a number(0..2):1 //It is ok! //Input a number(0..2):2 //It may ok. //Input a number(0..2):3 //Format error! //

引用 1 楼 czarten 的回复:如果整数是从１开始连续的，搞个字符指针数组就好了 我是刚开始学，不知道该怎么用，能不能写的例子给我看看一下呢，谢谢！

用c++的map<string,int> simap;

引用 2 楼 victor1960 的回复:[quote=引用 1 楼 czarten 的回复:] 如果整数是从１开始连续的，搞个字符指针数组就好了  顶一个[/quote] 顶

引用 1 楼 czarten 的回复:如果整数是从１开始连续的，搞个字符指针数组就好了  顶一个

如果整数是从１开始连续的，搞个字符指针数组就好了


Question: 编程题：小明的筷子

当数组中出现元素0的时候，表示数量错误，返回-1 当数组中，有两个以上奇数个统一长度的筷子时候，表示漏掉不止一根，返回 第一个奇数个的长度好了 当筷子全部成对的时候，表示没有漏掉，或者出错，返回 -1

int tmp[SIZE]={} for(int i=0;i<Input.length;i++) {       tmp[i]++; }  for(int i=0;i<SIZE;i++) {      if(tmp[i]==1)      {            //find      } }  这是伪代码，大家看看如何？

哦，明白了明白了，原来是一系列数不能组成对的多出来的那根 啊

我怎么没看懂，怎么漏掉的？查找的规则是什么？

你这个输入固定了 和题目要求不符吧

若筷子不是金箍棒一样长的话 用位图法再简单不过了 判断是奇数的就是少了的一跟筷子了

试改2行:   for(i = 0; i < arraySize; i ++) //改 for(i = 0; i < arraySize && 0 != chopsticks[i]; i ++)   {     if(0 != chopsticks[i]) for(j = i + 1; j < arraySize; j++) //改 for(j = i + 1; j < arraySize; j++)     {       if(chopsticks[i] == chopsticks[j])       {         chopsticks[i] = chopsticks[j] = 0;         count++;         break;       }     }   }

用数组下标存值 /* 小明是个马大哈，某天他到超市买了若干双筷子（n < 20） 筷子的长度不尽相同，他把全部筷子都放在购物袋里面拿回家，路上不小心漏了一根 请你用程序帮他找出是漏掉的筷子是多长的。   输入：  剩下的筷子数组，如：1, 2, 3, 2, 1, 3, 2 返回值：漏掉的筷子长度，如上述输入返回：2（当输入的筷子数据异常时返回-1，如：找不到漏掉的筷子）   */ #include <stdio.h>  #define MAX_LEN 20  int find_lost_chopsticks(int a[],int num) { 	int len[MAX_LEN+1]={0}; 	int i; 	for(i=0;i< num;i++) 	{ 		len[a[i]]++; 		if(len[a[i]]==2)len[a[i]]=0; 	} 	for(i=1;i<MAX_LEN+1;i++) 	{ 		if(len[i])return i; 	} 	return -1; }  int main() { 	int a[]={1, 2, 3, 2, 1, 3, 2}; 	printf("%d\n",find_lost_chopsticks(a,sizeof(a)/sizeof(int))); 	return 0; }

排序+计数

引用 1 楼 zhao4zhong1 的回复:n双 能帮我分析上上面的代码有什么疏漏吗？

如果只漏了1根筷子，则只需要将剩余筷子的长度依次异或，结果即为漏掉的那根筷子的长度；  如果漏了k根筷子，且k>=1，那么当k为偶数时，问题可能无解。例如漏了2根筷子，且其长度相同。

n双


Question: [求助]c语言中的system的一个问题

引用 6 楼 user-1 的回复:在你的第一个system之前加一行 fflush(fpart) 再试试，这个函数是强制把内存缓冲区写入文件的  厉害！！！ 多谢啦！ 你说的很对！

引用 3 楼 user-1 的回复:[quote=引用 2 楼 damaoshan 的回复:] 照这么看，有没有可能，fclose之前，也已经写到了硬盘？ 或者说只是个时间的问题？ 一切皆有可能。这个有点像复制文件到u盘 [/quote] 一般来讲，为什么需要fclose呢？ 假设不fclose不可以吗？

引用 2 楼 damaoshan 的回复:另外，既然fclose之前，不能保证数据写入硬盘，那么fclose之前就不能对所谓的写入文件做有关操作了？ 这个我不太确定，可能也要看你怎么操作吧，如果是同一个fp我觉得问题不大

引用 2 楼 damaoshan 的回复:照这么看，有没有可能，fclose之前，也已经写到了硬盘？ 或者说只是个时间的问题？ 一切皆有可能。这个有点像复制文件到u盘

@user-1  “这个和system没关系，关键在于fclose的作用。fwrite写的东西可能还在内存缓冲区里，没写到硬盘，只有fclose之后才确保写入文件了 ” 照这么看，有没有可能，fclose之前，也已经写到了硬盘？ 或者说只是个时间的问题？  另外，既然fclose之前，不能保证数据写入硬盘，那么fclose之前就不能对所谓的写入文件做有关操作了？


Question: 关于多语言的问题

IDispatch::GetIDsOfNames HRESULT GetIDsOfNames(    REFIID  riid,                     OLECHAR FAR* FAR*  rgszNames,     unsigned int  cNames,             LCID   lcid,                      DISPID FAR*  rgDispId           );   Maps a single member and an optional set of argument names to a corresponding set of integer DISPIDs, which can be used on subsequent calls to IDispatch::Invoke. The dispatch function DispGetIDsOfNames provides a standard implementation of GetIDsOfNames.  Parameters riid  Reserved for future use. Must be IID_NULL.  rgszNames  Passed-in array of names to be mapped.  cNames  Count of the names to be mapped.  lcid  The locale context in which to interpret the names.  rgDispId  Caller-allocated array, each element of which contains an identifier (ID) corresponding to one of the names passed in the rgszNames array. The first element represents the member name. The subsequent elements represent each of the member's parameters.  Return Value The return value obtained from the returned HRESULT is one of the following:  Return value Meaning  S_OK Success.  E_OUTOFMEMORY Out of memory.  DISP_E_UNKNOWNNAME One or more of the names were not known. The returned array of DISPIDs contains DISPID_UNKNOWN for each entry that corresponds to an unknown name.  DISP_E_UNKNOWNLCID The locale identifier (LCID) was not recognized.    Comments An IDispatch implementation can associate any positive integer ID value with a given name. Zero is reserved for the default, or Value property; –1 is reserved to indicate an unknown name; and other negative values are defined for other purposes. For example, if GetIDsOfNames is called, and the implementation does not recognize one or more of the names, it returns DISP_E_UNKNOWNNAME, and the rgDispId array contains DISPID_UNKNOWN for the entries that correspond to the unknown names.  The member and parameter DISPIDs must remain constant for the lifetime of the object. This allows a client to obtain the DISPIDs once, and cache them for later use.  When GetIDsOfNames is called with more than one name, the first name (rgszNames[0]) corresponds to the member name, and subsequent names correspond to the names of the member's parameters.  The same name may map to different DISPIDs, depending on context. For example, a name may have a DISPID when it is used as a member name with a particular interface, a different ID as a member of a different interface, and different mapping for each time it appears as a parameter.  The IDispatch interface binds to names at run time. To bind at compile time instead, an IDispatch client can map names to DISPIDs by using the type information interfaces described in Chapter 9, "Type Description Interfaces." This allows a client to bind to members at compile time and avoid calling GetIDsOfNames at run time. For a description of binding at compile time, see Chapter 9, "Type Description Interfaces."   The implementation of GetIDsOfNames is case insensitive. Users that need case-sensitive name mapping should use type information interfaces to map names to DISPIDs, rather than call GetIDsOfNames.  Examples The following code from the Lines sample file Lines.cpp implements the GetIDsOfNames member function for the CLine class. The ActiveX or OLE object uses the standard implementation, DispGetIDsOfNames.  STDMETHODIMP  CLine::GetIDsOfNames(         REFIID riid,         OLECHAR FAR* FAR* rgszNames,         UINT cNames,         LCID lcid,         DISPID FAR* rgDispId) {         return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgDispId); }  The following code might appear in an ActiveX client that calls GetIDsOfNames to get the DISPID of the CLine Color property.  HRESULT hresult; IDispatch FAR* pdisp = (IDispatch FAR*)NULL; DISPID dispid; OLECHAR FAR* szMember = "color";  // Code that sets a pointer to the dispatch (pdisp) is omitted.  hresult = pdisp->GetIDsOfNames(     IID_NULL,     &szMember,     1, LOCALE_SYSTEM_DEFAULT,     &dispid);  See Also CreateStdDispatch, DispGetIDsOfNames, ITypeInfo::GetIDsOfNames    或者参考 C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\GETQLOC.C C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\getqloc.c C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\src\getqloc.c C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\getqloc.c


Question: iconv转码问题

引用 15 楼 todo9351 的回复:楼主是用libiconv 吧。  就是要注意一下，转换过程中会修改原来的空间的内容。  还有就是原来字符的编码是不是 指定的，如 UTF-8  转成 GBK ，如果原来的字符是GBK的，那转一下立马就出错了。  我也是弄好久才发现的。 我是拿到网络的报文，存在字符串中，能肯定原来的编码格式就是Unicode，你觉得，哪里还会有问题呢？大神

ssize_t convert(const char *tocode, const char *fromcode, char *inbufp, size_t inbytesleft, char *outbufp, size_t outbytesleft) {               iconv_t ic;         size_t outbytes = outbytesleft;         size_t intbytes = inbytesleft;         int ret;         char *in, *out;          in = (char *)inbufp;         out = (char *)outbufp;         ic = iconv_open (tocode, fromcode);         if (ic == (iconv_t ) - 1)         {                 printf ("iconv_open failed: from: %s, to: %s: %s\n",                            fromcode, tocode, strerror (errno));                 return -1;         }         while (inbytesleft > 0)         {                 printf("conv before\n");                 printf("intbytes : %d\n", intbytes);                 printf("outbytes : %d\n", outbytes);                 ret = iconv (ic, (char **)&in, &intbytes, (char **)&out, &outbytes);                 if (ret == -1)                 {                         printf ("iconv failed: from: %s, to: %s: %s\n",                                 fromcode, tocode, strerror (errno));                                            return -1;                 }                 printf("conv after\n");         }         ret = iconv_close (ic);         if (ret == -1)         {                 printf ("iconv_close failed: from: %s, to: %s: %s\n",                           fromcode, tocode, strerror (errno));                 return -1;         }         return outbytesleft-outbytes; } 有问题么?ionv还是直接退出了，真没法了。。

先 http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express 点开Visual C++ 2010 Express下面的语言选‘简体中文’，再点立即安装  再参考C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\cvt\*.*   自己写个转码函数。不用iconv这个劳什子了！

引用 11 楼 zhao4zhong1 的回复:[quote=引用 10 楼 whenyumen 的回复:] [quote=引用 9 楼 zhao4zhong1 的回复:] 引用 5 楼 zhao4zhong1 的回复: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令 关键环境，没有gdb，不允许安装，但是可以把core文件调出来，您看代码有问题么[/quote] core文件拷贝到其它机器上，照样可以使用 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 [/quote] 没用的，我看了，我保证是iconv函数那儿有问题，但是有啥问题呢？。。

引用 10 楼 whenyumen 的回复:[quote=引用 9 楼 zhao4zhong1 的回复:] 引用 5 楼 zhao4zhong1 的回复: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令 关键环境，没有gdb，不允许安装，但是可以把core文件调出来，您看代码有问题么[/quote] core文件拷贝到其它机器上，照样可以使用 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。

引用 9 楼 zhao4zhong1 的回复:引用 5 楼 zhao4zhong1 的回复: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令 关键环境，没有gdb，不允许安装，但是可以把core文件调出来，您看代码有问题么

引用 4 楼 user-3 的回复:gdb 了吗？程序怎么能直接退出呢。 core文件，gbd具体如下，段错误？ warning: core file may not match specified executable file. Failed to read a valid object file image from memory. Core was generated by `./JDdecodetds11'. Program terminated with signal 11, Segmentation fault. [New process 8113] [New process 8111] #0  0x305b5ba3 in ?? ()

引用 4 楼 user-3 的回复:gdb 了吗？程序怎么能直接退出呢。 没有产生core文件

引用 3 楼 whenyumen 的回复:仍没找到任何问题啊。。 是啊，程序从ionv中直接退出了

gdb 了吗？程序怎么能直接退出呢。

仍没找到任何问题啊。。

没人用过么？紧急求救啊

不能沉啊，亲们！！


Question: 求教:文件段落间字符串排序问题.

仅供参考//假设带表头结点的单向链表头指针为head，试编写一个算法将值为5的结点插入到连接表的第k个结点前，删除第k个节点，并对该链表进行排序。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*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;     }      //将单链表中前 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; } //18->94->58->17->27->20->43->57->75->78-> //18->94->05->58->17->27->20->43->57->75->78-> //18->94->05->58->27->20->43->57->75->78-> //05->18->20->27->43->57->58->75->78->94-> //43->57->58->75->78->94->05->18->20->27-> //


Question: shiyan.exe 中的 0x502ff4a5 (msvcr100d.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000064

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

WORD *word=new WORD[word_max];    //结构体类型数组, 上面一行的new是什么意思，为何我这里显示没有定义？


Question: 以下指针指向字符串与数组存储字符串的区别是什么？

第一个指针p指向的字符串是存放在常量区，所以试图修改字符串是错误的，p[1]='a'会出现内存错误 相反，第二个字符数组是可以修改的

#pragma comment(linker,"/SECTION:.rdata,RW") //加这句可以让常量区可写，后果自负！

非常感谢大家的帮助！

第一个当中的p是一个指针，指向一个静态分配的只读字符串。 第二个当中的p是一个字符数组。


Question: 为了解决多线程的问题将SO复制多份进行处理，可行吗？

引用 14 楼 lgmsyy 的回复:[quote=引用 13 楼 Saleayas 的回复:] 使用复制的方法，如果那个 DLL 没有问题。 可以把 DLL 放到资源里，然后，当你需要创建一个线程的时候， 把这个 DLL 的资源释放到临时文件夹中，并且使用临时文件名。 然后，加载并导出函数。 这样，在不同的线程中，这些 DLL 函数就是不同的。  但是，如果这些 DLL 还依赖其他的 DLL，或者有特殊的地方，多线程就会出问题。 因为 开发这个 DLL 的人根本可能就只测试了一个进程一个线程的问题。  我是这样认为：首先我复制了两份SO/DLL文件。然后我开启了两个线程，其中每个线程类对应不同的SO/DLL。是这样吗？  我这样测试了，确实可以。但是我同时又发现，当我通过WEB应用连续执行的时候，会造成系统的不稳定。我不知道这是另外的错误引起的，还是因为我当前这么做而引起的？[/quote]  只有调试分析才能知道。

引用 14 楼 lgmsyy 的回复:[quote=引用 13 楼 Saleayas 的回复:] 使用复制的方法，如果那个 DLL 没有问题。 可以把 DLL 放到资源里，然后，当你需要创建一个线程的时候， 把这个 DLL 的资源释放到临时文件夹中，并且使用临时文件名。 然后，加载并导出函数。 这样，在不同的线程中，这些 DLL 函数就是不同的。  但是，如果这些 DLL 还依赖其他的 DLL，或者有特殊的地方，多线程就会出问题。 因为 开发这个 DLL 的人根本可能就只测试了一个进程一个线程的问题。  我是这样认为：首先我复制了两份SO/DLL文件。然后我开启了两个线程，其中每个线程类对应不同的SO/DLL。是这样吗？  我这样测试了，确实可以。但是我同时又发现，当我通过WEB应用连续执行的时候，会造成系统的不稳定。我不知道这是另外的错误引起的，还是因为我当前这么做而引起的？[/quote]  你确认这两个 DLL 是交替使用的，而且在再次使用前，确认被释放了。 那个 DLL 的 PROCESS_ATTACH 和 THREAD_ATTACH 以及对应的 DETACH 可能没有处理好。 所以，在你不确认那个 DLL 的时候，每次都是用一个新的 DLL 名字。

引用 18 楼 zhao4zhong1 的回复:[quote=引用 17 楼 lgmsyy 的回复:] [quote=引用 16 楼 zhao4zhong1 的回复:] 每个复制的so要改名为互不相同的文件名。  SO的名字我是可以更改为互不相同的。但是SO中的函数名称我更改不了啊[/quote] 函数名称不用改。 在每个进程中用LoadLibrary加载各自对应的dll文件，GetProcAddress，……，FreeLibrary[/quote] 这是windows  Linux下参考下面： EXAMPLE Load the math library, and print the cosine of 2.0:  #include <stdio.h> #include <dlfcn.h>  int main(int argc, char **argv) {     void *handle;     double (*cosine)(double);     char *error;      handle = dlopen ("libm.so", RTLD_LAZY);     if (!handle) {         fprintf (stderr, "%s\n", dlerror());         exit(1);     }      dlerror();    /* Clear any existing error */     *(void **) (&cosine) = dlsym(handle, "cos");     if ((error = dlerror()) != NULL)  {         fprintf (stderr, "%s\n", error);         exit(1);     }      printf ("%f\n", (*cosine)(2.0));     dlclose(handle);     return 0; }  If this program were in a file named "foo.c", you would build the program with the following command:   gcc -rdynamic -o foo foo.c -ldl   Libraries exporting _init() and _fini() will want to be compiled as follows, using bar.c as the example name:   gcc -shared -nostartfiles -o bar bar.c

引用 17 楼 lgmsyy 的回复:[quote=引用 16 楼 zhao4zhong1 的回复:] 每个复制的so要改名为互不相同的文件名。  SO的名字我是可以更改为互不相同的。但是SO中的函数名称我更改不了啊[/quote] 函数名称不用改。 在每个进程中用LoadLibrary加载各自对应的dll文件，GetProcAddress，……，FreeLibrary

引用 16 楼 zhao4zhong1 的回复:每个复制的so要改名为互不相同的文件名。  SO的名字我是可以更改为互不相同的。但是SO中的函数名称我更改不了啊

每个复制的so要改名为互不相同的文件名。

引用 14 楼 lgmsyy 的回复:[quote=引用 13 楼 Saleayas 的回复:] 使用复制的方法，如果那个 DLL 没有问题。 可以把 DLL 放到资源里，然后，当你需要创建一个线程的时候， 把这个 DLL 的资源释放到临时文件夹中，并且使用临时文件名。 然后，加载并导出函数。 这样，在不同的线程中，这些 DLL 函数就是不同的。  但是，如果这些 DLL 还依赖其他的 DLL，或者有特殊的地方，多线程就会出问题。 因为 开发这个 DLL 的人根本可能就只测试了一个进程一个线程的问题。  我是这样认为：首先我复制了两份SO/DLL文件。然后我开启了两个线程，其中每个线程类对应不同的SO/DLL。是这样吗？  我这样测试了，确实可以。但是我同时又发现，当我通过WEB应用连续执行的时候，会造成系统的不稳定。我不知道这是另外的错误引起的，还是因为我当前这么做而引起的？[/quote]  注意，因为线程数和复制的SO/DLL文件数量一致。所以每个线程类对应不同的SO/DLL。

引用 13 楼 Saleayas 的回复:使用复制的方法，如果那个 DLL 没有问题。 可以把 DLL 放到资源里，然后，当你需要创建一个线程的时候， 把这个 DLL 的资源释放到临时文件夹中，并且使用临时文件名。 然后，加载并导出函数。 这样，在不同的线程中，这些 DLL 函数就是不同的。  但是，如果这些 DLL 还依赖其他的 DLL，或者有特殊的地方，多线程就会出问题。 因为 开发这个 DLL 的人根本可能就只测试了一个进程一个线程的问题。  我是这样认为：首先我复制了两份SO/DLL文件。然后我开启了两个线程，其中每个线程类对应不同的SO/DLL。是这样吗？  我这样测试了，确实可以。但是我同时又发现，当我通过WEB应用连续执行的时候，会造成系统的不稳定。我不知道这是另外的错误引起的，还是因为我当前这么做而引起的？

引用 11 楼 lgmsyy 的回复:[quote=引用 8 楼 60 的回复:] 一个SO，只能被一个进程加载一次。  >> 对方说“为了解决多线程的问题将SO复制多份进行处理”，然后分别调用以实现多线程。 问题是怎么解决 方法重名的问题。  可以考虑用5楼的方式使用多进程调用这个so，然后你写一个调度管理进程，统一进行管理。  是不是这个意思：我写一个线程，其实是每个线程调用不同的对应进程而已。是这样吗？ 然后可以统一管理这个线程[/quote]楼主先确定下进程跟线程是什么东东

引用 8 楼 60 的回复:一个SO，只能被一个进程加载一次。  >> 对方说“为了解决多线程的问题将SO复制多份进行处理”，然后分别调用以实现多线程。 问题是怎么解决 方法重名的问题。  可以考虑用5楼的方式使用多进程调用这个so，然后你写一个调度管理进程，统一进行管理。  是不是这个意思：我写一个线程，其实是每个线程调用不同的对应进程而已。是这样吗？ 然后可以统一管理这个线程

引用 8 楼 60 的回复:一个SO，只能被一个进程加载一次。  >> 对方说“为了解决多线程的问题将SO复制多份进行处理”，然后分别调用以实现多线程。 问题是怎么解决 方法重名的问题。  可以考虑用5楼的方式使用多进程调用这个so，然后你写一个调度管理进程，统一进行管理。  这个好办，我可以在外封装一层SO，通过我封装的SO重新命名。

引用 7 楼 user-6 的回复:明显是为了糊弄你 也不能这么说，如果对方确实不支持多线程，那么就想办法其他方式呗。

有人帮忙吗？

明显是为了糊弄你

引用 4 楼 tiantangxingkong 的回复:[quote=引用 3 楼 lgmsyy 的回复:] [quote=引用 2 楼 zhao4zhong1 的回复:] 使用多进程。  我的描述，是不是就是多进程方式。[/quote]把你的程序用鼠标双击多次[/quote]  如果不行，你还可以多WindowsStation CreateWindowStation The CreateWindowStation function creates a window station object. It returns a handle that can be used to access the window station. A window station is a secure object that contains a set of global atoms, a clipboard, and a set of desktop objects.  HWINSTA CreateWindowStation(   LPTSTR lpwinsta,        // name of the new window station   DWORD dwReserved,       // reserved; must be NULL   DWORD dwDesiredAccess,  // specifies access of returned handle   LPSECURITY_ATTRIBUTES lpsa  // specifies security attributes of                                // the window station );   Parameters lpwinsta  Optionally points to a null-terminated string specifying the name of the window station to be created. Window station names are case-insensitive and cannot contain backslash characters (\). Only members of the Administrators group are allowed to specify a name. If lpwinsta is NULL, the system forms a window station name using the logon session identifier for the calling process. To get this name, call the GetUserObjectInformation function.  dwReserved  Reserved; must be NULL.  dwDesiredAccess  Specifies the type of access to the window station. This parameter can be one or more of the following values: Value Description  WINSTA_ACCESSCLIPBOARD Required to use the clipboard.  WINSTA_ACCESSGLOBALATOMS Required to manipulate global atoms.  WINSTA_CREATEDESKTOP Required to create new desktop objects on the window station.  WINSTA_ENUMDESKTOPS Required to enumerate existing desktop objects.  WINSTA_ENUMERATE Required for the window station to be enumerated.  WINSTA_EXITWINDOWS Required to successfully call theExitWindows orExitWindowsEx functions.  WINSTA_READATTRIBUTES Required to read the attributes of a window station object.  WINSTA_READSCREEN Required to access screen contents.  WINSTA_WRITEATTRIBUTES Required to modify the attributes of a window station object.    lpsa  Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpsa is NULL, the handle cannot be inherited.  The lpSecurityDescriptor member of the structure specifies a security descriptor for the new window station. If lpsa is NULL, the window station (and any desktops created within the window) gets a security descriptor that grants GENERIC_ALL access to all users.   Return Values If the function succeeds, the return value is a handle to the newly created window station. If the specified window station already exists, the function succeeds and returns a handle to the existing window station.  If the function fails, the return value is NULL. To get extended error information, call GetLastError.  QuickInfo   Windows NT: Requires version 3.51 or later.   Windows: Unsupported.   Windows CE: Unsupported.   Header: Declared in winuser.h.   Import Library: Use user32.lib.   Unicode: Implemented as Unicode and ANSI versions on Windows NT.  See Also Window Stations and Desktops Overview, Window Station and Desktop Functions, GetUserObjectInformation, OpenWindowStation

我以前用到过一个 嵌入式的下载工具包。 这个包编写很简单，每次只能 OPEN 一个 串口来下载。 因为的它的源码里面使用了 static COMM comm 之类的数据。 不支持多线程。 也就说说这个进程只能有一个 COMM 口在运行。  而真正在工作中下载的时候，使用一个测试架，一次下载 16 个。 所以，当时我们只能使用 16 个进程来下载。类似于现在的浏览器模式。  使用 复制16 分不同名的 DLL ，如果不意外应该是可以得。 但是，我当年使用的有硬件工程师给的下载工具包，为了稳妥起见，我使用了进程。 我总觉得要求一个硬件工程师去写一个漂亮的 DLL，太无理了。

引用 3 楼 lgmsyy 的回复:[quote=引用 2 楼 zhao4zhong1 的回复:] 使用多进程。  我的描述，是不是就是多进程方式。[/quote]把你的程序用鼠标双击多次

引用 2 楼 zhao4zhong1 的回复:使用多进程。  我的描述，是不是就是多进程方式。


Question: 字符串截取

引用 18 楼 Intel0011 的回复:void GetField(char *czData, char *outData) {    sscanf(czData, "%*[^;];NB=%[^;]", outData); }  解释一下 %[^;]表示匹配到非;符号为止 *号表示不存储所匹配的值 合起来就是 %*[^;]不存储匹配到非;符号为止的值 ;NB=表示匹配;NB=符号 %[^;]表示匹配到非;符号为止的值，并存储到outData中

引用 8 楼 xuzhouweihao 的回复:, sscanf(czData,"NB=%[^;];",outdata);[/quote]  骚年，你测试了没？

需要那么麻烦吗？  用 strstr  就好了呗

上帖回错了。

#include <stdio.h> #include <stdlib.h> #include <malloc.h> int **p; 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 //

void main() { 	char* czData = "SN=12346;NB=abc;TB=688;"; 	char outData[255] = {0}; 	GetField(czData, "NB=", outData); 	printf("%s", outData); }  void GetField(char* czData,char* key,char* outData) { 	char *keyPos = strstr(czData, key);//寻找源串中Key首次出现的位置	  	//未找到 	if(keyPos == NULL)			 		return;	  	//找到 	char *semPos = strstr(keyPos, ";");//寻找key后首次出现;的位置 	char *equPos = strstr(keyPos, "=");//寻找key后首次出现=的位置 	char *outPos = equPos+1;//=后面就是我们要的内容			 	strncpy(outData, outPos, semPos-outPos);//复制这部分内容 }

引用 9 楼 zhao4zhong1 的回复:[quote=引用 7 楼 xuzhouweihao 的回复:] [quote=引用 6 楼 xuzhouweihao 的回复:] 使用 sscanf(czData,"NB=%[^;],outdata);  这样就可以了吧  少了个" sscanf(czData,"NB=%[^;];“,outdata);[/quote]   char outdata[40]; char *p; p=strstr(czData,";NB="); if  (p) {  if (1==sscanf(p,";NB=%39[^;];“,outdata)) {   printf("NB=%s\n",outdata);  } } [/quote] 是的，最好加一个截取字符串的长度。

引用 7 楼 xuzhouweihao 的回复:[quote=引用 6 楼 xuzhouweihao 的回复:] 使用 sscanf(czData,"NB=%[^;],outdata);  这样就可以了吧  少了个" sscanf(czData,"NB=%[^;];“,outdata);[/quote]   char outdata[40]; char *p; p=strstr(czData,";NB="); if  (p) {  if (1==sscanf(p,";NB=%39[^;];“,outdata)) {   printf("NB=%s\n",outdata);  } }

引用 6 楼 xuzhouweihao 的回复:使用 sscanf(czData,"NB=%[^;],outdata);  这样就可以了吧  少了个" sscanf(czData,"NB=%[^;];“,outdata);

引用 2 楼 brookmill 的回复:int GetField(char *czData, char *strSearch, char *outData) {          char *p;         if (czData == NULL || strSearch == NULL || outData == NULL) {                 return -1;         }         p = strstr(czData, strSearch);         if (p == NULL) {                 return -1;         }         while (*p != '=' && *p != '\0') {                 p++;         }         if (*p == '\0') {                 return -1;         }         p++;         while (*p != ';' && *p != '\0') {                 *outData++ = *p++;         }         *outData = '\0';         return 0; }   赞

p++;   /////应去掉词句         while (*p != ';' && *p != '\0') {                 *outData++ = *p++;         }         *outData = '\0';         return 0; } O(∩_∩)O谢谢 2楼

///引用2楼 的， int GetField(char *czData, char *strSearch, char *outData) {          char *p;   char *q=strSearch;    ////////////////         if (czData == NULL || strSearch == NULL || outData == NULL) {                 return -1;         }         p = strstr(czData, strSearch);         if (p == NULL) {                 return -1;         }         while (*p ==*q&& *q != '\0') {                  p++;                  q++;         }         if (*p == '\0') {                 return -1;         }         p++;         while (*p != ';' && *p != '\0') {                 *outData++ = *p++;         }         *outData = '\0';         return 0; } ///////////////////////////// 将2楼的修改下， 扩充性更好些

#include <stdio.h> #include <string.h> #define BUFSIZE 64 #define DEBUG enum tar_GF_ERR{ 	GF_Ok				= 0, 	GF_InputNullErr		=-1, 	GF_No_Match			=-2, };  int  GetField(char const *czData, char const *GetStr, char *outData);  int main() { 	int m = 1; 	int n; 	char* czData = "SN=12346;NB=abc;TB=688;"; 	char outData[BUFSIZE] = {0}; 	 	n = m+++m++;   // m++ + m++ 	printf("m = %d n = %d\n", m, n); 	 	if(!GetField(czData,"NB=",outData)) 		printf("outdata = %s\n", outData); }   int  GetField(char const *czData, char const *GetStr, char *outData) { 	char *start = NULL; 	char *end = NULL; 	int GetStrLen = 0; 	int LastLen = 0; 	int count = 0; 	 	if(!czData || !GetStr || !outData) 		return GF_InputNullErr; 		 	if(!(start = strstr(czData, GetStr)))   // if NULL 	{ 		strcpy(outData, ""); 		return GF_No_Match; 	} 	GetStrLen = strlen(GetStr);				// care 	if(GetStrLen > 0) 		start += GetStrLen; 		 	LastLen	= strlen(start); #ifdef DEBUG 	printf("DBG:LastLen = %d\n", LastLen); #endif 	end = start;		 	while(!(*end == ';') && LastLen--) 	{ #ifdef DEBUG 	printf("DBG:*end = %c\n", *end); #endif			 		end ++; 		count++; 	} #ifdef DEBUG 	printf("DBG:count = %d\n", count); #endif	 	if(LastLen == 0) 	{ 		strcpy(outData, ""); 		return GF_No_Match;		 	} 	else 	{ 		strncpy(outData, start, count); 	} 				 //	strcpy(outData, start);			// debug 	return GF_Ok; }

没说清楚 “NB=”是会变的吗？ 函数原型写完整，类型什么的


Question: BUG求大神看看

引用 3 楼 u014313894 的回复:恩，可是我已今天头疼一阵时间了  范围很大，而且功能很多，操作也不少，你说一下bug发生的条件，进行了什么操作会出现问题等等。。

代码太长了，下断点调试下看看

Windows： 崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。  Linux： 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈，内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件，参考“ulimit -c core文件最大块大小”命令

在你出错的那两个函数设个断点，然后单步执行。另外，你这个程序的函数参数都是结构体啊，都没用指针，修改信息什么的肯定没生效。

在出错地儿加几个断点

恩，可是我已今天头疼一阵时间了

先缩小发生的条件，然后一步一步调试吧，问题自己找出来进步会最大化。

代码太多了


Question: 奇怪的报错 C# （新手求大神解答）

有对象没有引用实际的实例对象。

你是不是发错版块了?


Question: 求助各位了，大家快来帮帮忙啊

简单啊！用一个通过地址访问数据而已

不知道是不是 #include <stdio.h> #include <malloc.h>  int main() { 	int* a[3]; 	int i; 	int j; 	int temp; 	for(i=0;i<3;i++) 	{ 		a[i]=(int*)malloc(sizeof(int)); 		scanf("%d",a[i]); 	} 	for(i=0;i<2;i++) 	{ 		for(j=0;j<2;j++) 		{ 			if(*a[j]>*a[j+1]) 			{ 				temp=*a[j]; 				*a[j]=*a[j+1]; 				*a[j+1]=temp; 			} 		} 	} 	printf("%d:%d:%d\n",*a[0],*a[1],*a[2]); 	return 0; }

引用 1 楼 user-4 的回复:消灭 0 回复。 这是求源代码呀。 说思路 定义多维数组 , scanf 获取输入，然后指针做比较大小输出。 楼上的可以帮我消灭我帖子http://bbs.csdn.net/topics/390805950的0回复么，谢谢！


Question: 有详细介绍callback函数的资料吗？

callback function  Used to asynchronously read the messages in a queue. It is an application-defined function that MSMQ calls when a message is available, a time-out occurs, or an error occurs.   Windows系统：“不要调用我，请先填写好未来收到某个消息时你的处理流程，在那个消息到来时我会调用你！”

就是让你定义一个借口，让系统用，打个比方说，系统提供了一个借口 void  abc（），这个abc在开机的时候都会运行，但是这个借口你可以在里面写什么都行，比如printf hello  或者printf word, 那么开机的时候就会打印hello或者word

赵老师这是要玩死新人的节奏啊...  引用 1 楼 zhao4zhong1 的回复:

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


Question: 弱弱的问一个问题

#include<stdio.h> #include<conio.h>  int main(void) { 	printf("Thanks a lot!\n"); 	getch();  	return (0); }

hi dream    在发帖子的上方有一行是字体，表情等选择按钮。 中间有个 选择需要的语言，然后把代码复制到框里面就OK了


Question: 寄存器  内存 volatile  static

引用 3 楼 taodm 的回复:是副本到本体间有个同步的过程。 写的同步时间不确定。 读的同步可以被优化。 另外，找本好点的教材吧，没事别乱看网文。  请问你是参考的哪本书？有什么推荐？感谢！

引用 1 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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对应的汇编并单步执行观察相应内存和寄存器变化。）怎么又是这句。。。

引用 1 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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对应的汇编并单步执行观察相应内存和寄存器变化。）   赵老师，你好，赵老师，再见！


Question: 字节存储顺序  大小端问题

引用 1 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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对应的汇编并单步执行观察相应内存和寄存器变化。）  谢谢分享，学习了

引用 1 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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对应的汇编并单步执行观察相应内存和寄存器变化。）  不过还是感谢你来顶

引用 2 楼 zhao4zhong1 的回复:typedef struct bitstruct { int b1 : 5; int : 2; int b2 : 2; }biistruct; 和 typedef struct bitstruct { unsigned int b1 : 5; unsigned int : 2; unsigned int b2 : 2; }biistruct; 不是一回事！   赵老师，你也特不给力了，发些灌水的有意思么？

引用 3 楼 a775992553 的回复:问题一跟问题二就一样么。。其实补码是为了在计算机中表示负数。字母对应的全是ASCII码值，都是正数，所以没必要硬是要说是按原码还是补码。存储方式是第一种，打断小段是针对字节的，不是针对位的。 其实你可以输出更多信息，这样你自己就能通过结果推敲出好多结论。比如。把那个sizeof(b)输出，还有 printf("%x, %x\n", b.b1, b.b2); printf("%p, %p\n",&( b.b1), &(b.b2)); 等等。  其实不是第一种，在面试宝典中 是第二种 。。


Question: 堆排序中的一个函数有点不懂

大概理解了，谢谢大家！

引用 4 楼 TreeCare 的回复:如何交换呢？  (a^b)^b  这个值就是a;  一个值异或其他的值，然后再异或这个其他的值，还是它本身。

#include <stdio.h> #define SWAP(a,b) do ((&(a))!=(&(b)))?((a)^=(b)^=(a)^=(b)):((a)=(a)); while (0) char   *p1="1" ,*p2="2" ; char    c1=1   , c2=2   ; short   s1=1   , s2=2   ; int     i1=1   , i2=2   ; __int64 I1=1i64, I2=2i64; float   f1=1.0f, f2=2.0f; double  d1=1.0 , d2=2.0 ; void main() {     SWAP((int)p1,(int)p2);                printf("char *     %5s,   %5s\n",p1,p2);     SWAP(c1,c2);                          printf("char       %5d,   %5d\n",c1,c2);     SWAP(s1,s2);                          printf("short      %5d,   %5d\n",s1,s2);     SWAP(i1,i2);                          printf("int        %5d,   %5d\n",i1,i2);     SWAP(I1,I2);                          printf("__int64 %5I64d,%5I64d\n",I1,I2);     SWAP(*(int     *)&f1,*(int     *)&f2);printf("float      %5g,   %5g\n",f1,f2);     SWAP(*(__int64 *)&d1,*(__int64 *)&d2);printf("double    %5lg,  %5lg\n",d1,d2);      SWAP(c1,c1);     printf("%d\n",c1); } //char *         2,       1 //char           2,       1 //short          2,       1 //int            2,       1 //__int64     2,    1 //float          2,       1 //double        2,      1 //2

引用 5 楼 zxh707wk 的回复:异或运算，这个老师讲过，和那个a=a+b; b=a-b; a=a-b;一样的，能交换两个数的值 这个会溢出。

如何交换呢？

这是异或运算

引用 1 楼 xuzhouweihao 的回复:异或，  交换 a和b的值 函数的功能是交换a和b的值

异或，  交换 a和b的值


Question: Wireshark 听包问题

看起来像voip 的报文，是不是  sip  或 h323 数据连接？

相关RFC文档研读一下？


Question: rand函数问题与if语句的结合

引用 6 楼 cao_julians 的回复:[quote=引用 3 楼 xuzhouweihao 的回复:] 我看到这代码后确实想改一下， 就不吐槽了，下面代码参考下吧 #include<stdio.h> #include<stdlib.h> #include<time.h>  #define MAXCOUNT 20   int main() { 	int randvalue=0; 	int count[10] = {0}; 	int i=0;  	srand((unsigned)time(NULL));  	for (i = 1; i<= MAXCOUNT; i++){ 		randvalue = rand()%10 + 1; 		printf("%d ",randvalue);  		switch(randvalue){ 			case 10: 				count[9]++; 				break; 			case 9: 				count[8]++; 				break; 			case 8: 				count[7]++; 				break; 			case 7: 				count[6]++; 				break; 			case 6: 				count[5]++; 				break; 			case 5: 				count[4]++; 				break; 			case 4: 				count[3]++; 				break; 			case 3: 				count[2]++; 				break; 			case 2: 				count[1]++; 				break; 			case 1: 				count[0]++; 				break; 			default: 				break; 		}     }  	printf("\n"); 	for(i=1;i<=10;i++){ 		printf("%d:%d ",i,count[i-1]); 	} 	printf("\n");  	return 0;  } 还是太啰嗦了 循环中  randvalue = rand()%10 + 1;/*randvalue的值是1到10中任一个，可以直接转化为下标*/ printf("%d ",randvalue); count[randvalue-1]++; 即可 if和switch结构完全是多余[/quote]  是的。。。。

引用 3 楼 xuzhouweihao 的回复:我看到这代码后确实想改一下， 就不吐槽了，下面代码参考下吧 #include<stdio.h> #include<stdlib.h> #include<time.h>  #define MAXCOUNT 20   int main() { 	int randvalue=0; 	int count[10] = {0}; 	int i=0;  	srand((unsigned)time(NULL));  	for (i = 1; i<= MAXCOUNT; i++){ 		randvalue = rand()%10 + 1; 		printf("%d ",randvalue);  		switch(randvalue){ 			case 10: 				count[9]++; 				break; 			case 9: 				count[8]++; 				break; 			case 8: 				count[7]++; 				break; 			case 7: 				count[6]++; 				break; 			case 6: 				count[5]++; 				break; 			case 5: 				count[4]++; 				break; 			case 4: 				count[3]++; 				break; 			case 3: 				count[2]++; 				break; 			case 2: 				count[1]++; 				break; 			case 1: 				count[0]++; 				break; 			default: 				break; 		}     }  	printf("\n"); 	for(i=1;i<=10;i++){ 		printf("%d:%d ",i,count[i-1]); 	} 	printf("\n");  	return 0;  } 还是太啰嗦了 循环中  randvalue = rand()%10 + 1;/*randvalue的值是1到10中任一个，可以直接转化为下标*/ printf("%d ",randvalue); count[randvalue-1]++; 即可 if和switch结构完全是多余

int onescount=0, twoscount=0, threescount=0, fourscount=0, fivescount=0;  int sixscount=0, sevenscount=0, eightscount=0, ninescount=0, tenscount=0;写成scount[10]={0}不好吗？

判断是否越界访问，可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断，可将数组多声明一个元素，并设置数据读写断点在该多出元素对应的地址上。 #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; }

你应该把    randvalue=1+((int)rand()%10);    printf("%d\n",randvalue); 处理放在 if  if ..之前处理。

1.取随机数的应当在前面 2.判断的时候==写成了= 3.10的判断，应当和别的数字判断一样，或者别的判断的时候都接一个else   #include<stdio.h> #include<stdlib.h> #include<time.h> #define MAXCOUNT 10   int main() { 	 	int randvalue; 	int onescount=0, twoscount=0, threescount=0, fourscount=0, fivescount=0; 	int sixscount=0, sevenscount=0, eightscount=0, ninescount=0, tenscount=0; 	int i; 	 	srand(time(NULL)); 	 	for(i=1;i<=MAXCOUNT;i++) 	{ 		randvalue=1+((int)rand()%10); 		printf("%d\n",randvalue); 		if(randvalue==1) 		{ 			onescount++; 		} 		if(randvalue==2) 		{ 			twoscount++; 		} 		if(randvalue==3) 		{ 			threescount++; 		} 		if(randvalue==4) 		{ 			fourscount++; 		} 		if(randvalue==5) 		{ 			fivescount++; 		} 		if(randvalue==6) 		{ 			sixscount++; 		} 		if(randvalue==7) 		{ 			sevenscount++; 		} 		if(randvalue==8) 		{ 			eightscount++; 		} 		if(randvalue==9) 		{ 			ninescount++; 		} 		if(randvalue==10) 		{ 			tenscount++; 		} 	} 	printf("%d ,%d ,%d ,%d ,%d ,%d ,%d ,%d ,%d ,%d \n",onescount,twoscount,threescount,fourscount,fivescount,sixscount,sevenscount,eightscount,ninescount,tenscount); 	return 0; 	 }


Question: 关于指针的题目

指针的只能指向本程序的数据区，地址空间是操作系统分配的，不能赋直接地址给指针。 如果直接地址指向的是非本程序的地址空间，进程想访问该空间时，就会被操作系统杀掉。

理论上的分析，前面的各位大虾都分析过了。作为bird的我就来实践验证一下吧！欢迎大虾帮忙指点一下。特别是那个warning。 #include<stdio.h> #include<conio.h>  int main(void) { 	int *i=0x1234; 	int* p; 	p=i+1;  	printf("i=%x\np=%x\n",i,p);  	getch();  	return (0); } Ctrl+F7 编译当前文件后(1 warning)：   F7 编译工程后(正常)：   F5 调试执行后：    如果代码里要输出*i ,增加一行：printf("*i=%x\n",*i);  Ctrl+F7 编译当前文件后(1 warning)：   F7 编译工程后(正常)：   F5 调试执行后：除了会显示先前同样的DOS界面框还会弹出：   点击“确定”后，新增代码行多了一个黄色箭头：

引用 8 楼 duxd1989 的回复:[quote=引用 4 楼 buyong 的回复:] int  *i = 0x1234; 一般不能编译，强制转换后p=0x1238 确实不能编译  怎么进行强制转换[/quote] int  *i = (int *)0x1234;

同上，i地址为0x1234,*i 由于地址内容未知无法确定 i和p都为int*类型指针，int指针占用4个字节/32位系统所以 p = 0x1238

i  为0x1234; *i为 某个数值 即 0x1234 处存储的内容的整数值 p为 0x1238

引用 4 楼 buyong 的回复:int  *i = 0x1234; 一般不能编译，强制转换后p=0x1238 确实不能编译  怎么进行强制转换

*i 可能不能获取。因为0x1234 可能是保护的。这样赋值的只能除非特殊情况，否者就是野指针。 p = 0x1235.

指针不能直接这样赋值啊 int  *i = 0x1234;

为嘛研究这种现实完全错误的用法呢

int  *i = 0x1234; 一般不能编译，强制转换后p=0x1238

自己打印下吧。考查指针的算术运算！

i=0x1234 p=0x1238 因为i的类型是int*，所以i+1加的是一个int的长度4

i = 0x1234 *i 未定义，访问可能出现内存错误 p = 0x1238


Question: 指针的一些基本问题  求高人指点

引用 15 楼 arthuryangsh 的回复:其实大家想说的是，赵老师不要老复制粘贴这段话了。 不复制这段话，怎么能让搜索引擎搜这段话的时候出现次数尽量多呢？

这个跟指针不指针无关 数值上相似不说明什么问题，只说明存储位置相近。 str1指针和str2数组都是你定义的局部变量，存储位置相近很正常，跟类型是不是指针完全没有关系 而"123"是一个字符串常量，存储位置跟变量不一样，你的str1指向了它，自然内容是一个相差较大的数值了

引用 15 楼 arthuryangsh 的回复:其实大家想说的是，赵老师不要老复制粘贴这段话了。  大家都明白就好，人艰不拆

其实大家想说的是，赵老师不要老复制粘贴这段话了。

//x和[3]结合说明是一个大小为3的数组，该数组的每个元素为一类指针，该类指针指向一类函数，该类函数无参数，返回一类指针，该类指针指向一个大小为5的char型数组

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

引用 9 楼 zhao4zhong1 的回复:[quote=引用 8 楼 lzj891013 的回复:] [quote=引用 7 楼 zhao4zhong1 的回复:] 2楼内容都是本ID原创的。  赵老师是CSDN的兼职么？怎么到处都看到你？你哪来这么多时间来逛贴吧的？能告诉我秘诀么？[/quote] 时间就象乳沟(.)(.)，挤挤总能挤出来的。 [/quote]  真心希望赵老师能够写一些 对工作方向  就业方面 写一写文章！少挤点乳沟！

数组首元素的地址值与整个数组的地址值是相同的，但概念上是区别的。 就象一个大院中有多个楼，地址编成时，首个楼叫作100#楼，并用100#用来称呼这个大院===》有100#楼和100#院。 只说100#时，就是那个位置。是楼呢还是院呢？要说出这个字（楼或院）。 程序中就是地址值相同，要从str2(即&str2[0])和&str2的形式来判读是指向元素的指针（地址）还是指向数组的指针（地址）

引用 8 楼 lzj891013 的回复:[quote=引用 7 楼 zhao4zhong1 的回复:] 2楼内容都是本ID原创的。  赵老师是CSDN的兼职么？怎么到处都看到你？你哪来这么多时间来逛贴吧的？能告诉我秘诀么？[/quote] 时间就象乳沟(.)(.)，挤挤总能挤出来的。

引用 7 楼 zhao4zhong1 的回复:2楼内容都是本ID原创的。  赵老师是CSDN的兼职么？怎么到处都看到你？你哪来这么多时间来逛贴吧的？能告诉我秘诀么？

2楼内容都是本ID原创的。

这些都是基本概念，写多了就不会搞错

引用 2 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  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",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “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  大哥你这是哪本书上  拿来了，，幸苦了

引用 3 楼 czarten 的回复:内存分三块，堆区，栈区，静态存储区 局部变量都在栈区，字符串常量在静态存储区  整个过程就是：  char*  str1 = "123"; 定义了一个类型为【char指针】的变量str1，地址为【栈1】 又在静态存储区放了一个字符串常量"123"，地址为【静1】 然后str1的内容，也就是它指向的地址，就是【静1】  char   str2[] = "456"; 定义了一个char数组，地址为【栈2～栈5】共4个变量，内容分别为'4','5','6','\0'  结束。  printf("%p\n", str1);  // 打印str1的内容，静1 printf("%p\n", &str1);  // 打印str1的地址，栈1 printf("%p\n", str2);  // 打印数组首地址，栈2 printf("%p\n", &str2);  // 打印数组首地址，栈2  看懂了没？   三楼正解，应该是存储位置不一样，是这样的！！对的！！关于本质这块，大侠是参考哪本书或者资料的呢？


gcc -Wall -c "001.c"  001.c: In function ‘main’: 001.c:21:4: warning: implicit declaration of function ‘sleep’ [-Wimplicit-function-declaration]     sleep(1);     ^ 001.c: In function ‘task’: 001.c:10:1: warning: control reaches end of non-void function [-Wreturn-type]  }  ^ 编译成功结束。

gcc编译时添加链接选项-lpthread可以解决


Question: 水仙花数 C语言求教

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