Question: 关于c/c++模板的问题，涉及代码自动生成

始终没明白题目描述跟模板有什么关系。模板本身就是C++代码，像我说的“样板”，编译的时候根据不同模板实参，生成不同的函数重载或类。但是模板不是一个工具，他是一种语法。生成代码，再经过编译，其实都是在编译的时候完成的，你可以理解为编译模板代码为常规C++代码，再编译C++代码，虽然都是在你单击编译之后自动完成的。

没弄明白你的实际应用场景是什么。  1.为什么需要【工具】->【生成代码】->【再编译】->【程序完成1加到100】这个过程？直接写一个完成1加到100的程序不就好了  2.如果说你的目的不在于【完成1加到100】，这个功能只是个例子，你真正想要的是一个【自动生成代码】的工具，那你要这个工具它的能力到什么水平？是你给出一份用伪代码或者怎么样描述的样板，就能按配置生成出代码（像linux的configure生成makefile一样）？还是你说一个功能，这工具做语音识别，做自然语言理解，然后自动为你编写你需要的这个功能的代码（想想就好）？

#include <stdio.h> // 功能描述：输入求和的范围 a 和 b，生成c++代码，该代码计算a 累计到 b 的和 int main(int argc, char *argv[]) {     int a, b;     scanf("%d %d", &a, &b);          char file[] = "my.cpp";     FILE *fp = fopen(file, "w");     if (!fp)        printf("Cannot create or open the file: %s", file);          // include header      fprintf(fp, "#include <stdio.h>\n");     // function: int Sum(int nBegin, int nEnd)     fprintf(fp, "int Sum(int nBegin, int nEnd)\n");     fprintf(fp, "{\n");     fprintf(fp, "    if (nBegin >= nEnd) return nEnd;\n");     fprintf(fp, "    return nBegin + Sum(nBegin + 1, nEnd);\n");     fprintf(fp, "}\n\n");     // main      fprintf(fp, "void main()\n");     fprintf(fp, "{\n");     fprintf(fp, "    int a = %d, b = %d;\n", a, b);     fprintf(fp, "    printf(\"%%d\\n\", Sum(a, b));\n");     fprintf(fp, "}\n");          fclose(fp);          return 0; }

引用 3 楼 chikey 的回复:[quote=引用 1 楼 user-4 的回复:] 运行后才能生成代码？那跟模板没关系了，模板是编译期的。 //求1加到100，并显示结果  #include <iostream> template <int N> struct SUM  {     static const int value = SUM<N - 1>::value + N; };  template <> struct SUM<1> {     static const int value = 1; };   int main() {     std::cout << SUM<100>::value << std::endl; }  跟您的思路类似，可是我提交之后说不符合要求，说没有生成代码，请问怎样可以使代码自动生成出来呢？ [/quote] 啊，不好意思，刚才回复错地方了，那请问有其他实现的方法吗？

引用 2 楼 pengzhixi 的回复:template<int N> class Test { public: 	static const int m = N + Test<N - 1>::m; };   template<> class Test<1> { public: 	static const int m = 1; }; 你想这样？ //求1加到100，并显示结果  #include <iostream> template <int N> struct SUM  {     static const int value = SUM<N - 1>::value + N; };  template <> struct SUM<1> {     static const int value = 1; };   int main() {     std::cout << SUM<100>::value << std::endl; }  跟您的思路类似，可是我提交之后说不符合要求，说没有生成代码，请问怎样可以使代码自动生成出来呢？

引用 1 楼 user-4 的回复:运行后才能生成代码？那跟模板没关系了，模板是编译期的。 //求1加到100，并显示结果  #include <iostream> template <int N> struct SUM  {     static const int value = SUM<N - 1>::value + N; };  template <> struct SUM<1> {     static const int value = 1; };   int main() {     std::cout << SUM<100>::value << std::endl; }  跟您的思路类似，可是我提交之后说不符合要求，说没有生成代码，请问怎样可以使代码自动生成出来呢？

运行后才能生成代码？那跟模板没关系了，模板是编译期的。


Question: 帮我看下，为什么死循环，主要是fun函数

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

指针S没改变

s的位置没变话，直到]遇到字符"*"改一下：   while (*s) {     if (*s == '*')         *s = *s++;     else         s++; }

死在赋值哪里了~建议单步调试看看~自己亲眼看看死在哪里呢》》》

第一个循环 如果不是*的话 ，永远是原地循环啊

*s == '*'才++，其他情况都不会前进啊。


Question: 研究 Tinyhttpd源码遇到的问题

buf[15] = '\0';这句是将前15个字符截断了。


Question: 求分析这段代码

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct subjects             { 	int num;                          //课程编号  	char name[20]; 	char kind[10];                    //课程性质 	int stime;                        //总学时 	int ttime;                        //授课学时 	int etime;                        //实验或上机学时  	int score;                        //学分 	int term;                         //开课学期 	struct subjects *next;            //结构体指针 }SUB;  SUB *create_form()                    //创建课表 { 	SUB *head, *tail, *p;             //head，tail指向head第一个结点，p指向新建结点（楼主可以区分链表有无头结点） 	int num, stime, ttime;            //这一行以及下两行的的变量主要存储你要输入课程的内容 	int etime, score, term; 	char name[20], kind[10]; 	int size = sizeof(SUB);           //其实这一行可以省略，然后将下面的p = (SUB *)malloc(size)修改一下，这行如果不修改意思是看一下这个结构体的大小，及所占的内存 	head = tail = NULL;               //在还没有开始创建课表的时候，这两个指针先赋空值，否则会报错（不懂，请百度指针初始化赋空值的缘由） 	printf("输入选修课程信息:\n"); 	scanf_s("%d %s %s %d %d %d %d %d", &num, &name, &kind, &stime, &ttime, &etime, &score, &term); //开始存你课程的内容 	while (num != 0){                //因为你的课表有很多课，所以是循环结构 		p = (SUB *)malloc(size);     //可以直接写p = (SUB *)malloc(SUB);在一个链表中添加一个新的节点，这个节点得先申请内存（详见sizeof的使用） 		p->num = num;                //这一行以及接下来几行的语句是将你输入的课程内容存入到这个新建节点中 		strcpy_s(p->name, name); 		strcpy_s(p->kind, kind); 		p->stime = stime; 		p->ttime = ttime; 		p->etime = etime; 		p->score = score; 		p->term = term; 		if (head == NULL)            //如果你刚建立这个表，你的表是没有内容的，所以你的第一个结点head指向NULL 		{ 			head= p;                //p成为第一个结点 			              		} 		else 			tail->next = p;         //如果这个表里面本来就有东西，那就tail->next指向新结点，换我，其实可以不用tail,直接head->next=p。。 		tail = p;                   //tail指向p（换我 ，我直接写head=p，觉得多设置这个指针没什么用...） 		scanf_s("%d %s %s %d %d %d %d %d", &num, &name, &kind, &stime, &ttime, &etime, &score, &term);  //继续输入内容，继续新建结点加入链表中 	} 	tail->next = NULL;             //最后记得链表尾赋NULL 	return head; }  void savefile(SUB *head)          //存课表到文件中，读写文件你会的吧？下面的存文件为什么不合并一起...明明是一毛一样的功能，非要分开文件存储 { 	SUB *p; 	FILE *fp; 	fp = fopen("subjects.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void savefileadd(SUB *head)       { 	SUB *p; 	FILE *fp; 	fp = fopen("subjectsadd.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void savefiledel(SUB *head) { 	SUB *p; 	FILE *fp; 	fp = fopen("subjectsdel.txt", "w"); 	fprintf(fp, "课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (p = head; p; p = p->next) 		fprintf(fp, "%5d%12s%9s%9d%9d%11d%11d%7d\n", p->num, p->name, p->kind, p->stime, p->ttime, p->etime, p->score, p->term); 	fclose(fp); }  void prin(SUB *head)                    //读文件 { 	SUB *ptr; 	if (head == NULL){ 		printf("没有此门课程记录\n"); 		return; 	} 	printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 	for (ptr = head; ptr; ptr = ptr->next) 		printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); } void search(SUB *head) { 	int a, num; 	int t = 1; 	char type[10]; 	char ch = 'a', ch1; 	SUB *ptr;  	while (ch != ' '){ 		printf("按课程性质查找输入1，按学分查找输入2:\n"); 		scanf("%d", &a); 		switch (a){ 		case 1:printf("输入要查找的课程性质:\n"); 			scanf_s("%s", type); 			printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 			for (ptr = head; ptr; ptr = ptr->next)         //这里ptr=head跟ptr=head->next都可以 			if (strcmp(type, ptr->kind) == 0){ 				printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); 				t = 0; 			} 			if (t) printf("未找到\n"); 			t = 1; 			break; 		case 2:printf("输入要查找的课程的学分\n"); 			scanf_s("%d", &num); 			printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n"); 			for (ptr = head; ptr; ptr = ptr->next) 			if (ptr->score == num){ 				printf("%5d%12s%9s%9d%9d%11d%11d%7d\n", ptr->num, ptr->name, ptr->kind, ptr->stime, ptr->ttime, ptr->etime, ptr->score, ptr->term); 				t = 0; 			} 			if (t) printf("未找到\n"); 			t = 1;  		} 		printf("继续查找请按回车，结束请按空格:\n"); 		ch1 = getchar();                              //将回车键赋给CH1，否则CASE里面最后输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} }  SUB *insert(SUB *head)                               //添加函数跟创建表的函数内容差不多，看不懂你再问我吧.. { 	SUB *ptr, *ptr2, *subj; 	int size = sizeof(SUB); 	char ch = 'a', ch1; 	while (ch != ' '){ 		subj = (SUB *)malloc(size); 		ptr = subj; 		printf("输入要插入的课程信息:\n"); 		scanf_s("%d%s%s%d%d%d%d%d", &subj->num, subj->name, subj->kind, &subj->stime, &subj->ttime, &subj->etime, &subj->score, &subj->term); 		if (head == NULL){ 			head = ptr; 			head->next = NULL; 		} 		else{ 			for (ptr2 = head; ptr2; ptr2 = ptr2->next) 			if (ptr2->next == NULL){ 				ptr2->next = subj; 				subj->next = NULL; 				break; 			} 		} 		printf("继续插入请按回车，结束请按空格:\n"); 		ch1 = getchar();                      //将回车键赋给CH1，否则subj->term输完后输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} 	return head; }     SUB *del(SUB *head) { 	SUB *p1, *p2; 	char ch = 'a', ch1; 	int num; 	while (ch != ' '){ 		printf("输入要删除的课程编号:\n"); 		scanf_s("%d", &num); 		if (head->num == num){                    //如果你删除的课程刚好就是链表第一个结点，那么 			p2 = head;                            //指针p指向这个结点 			head = head->next;                    //让head指向自己下一个结点 			free(p2);                             //释放掉这个不想要的结点 		} 		if (head == NULL)                         //如果课程表本来就是空的，那就直接回去= =，一般逻辑思维这个应该放在前面，先判断课程表是否为空 			return NULL; 		p1 = head;                               //能运行到这个阶段说明，要删除的结点不是第一个结点，故让p1指向第一个结点 		p2 = head->next;                         //p2指向第二个结点 		while (p2){                              //p2不能为空 			if (p2->num == num){                 //当你找到要删除的点的时候 				p1->next = p2->next;             //直接让p1指向p2后一个结点，即p1直接无视了p2..跟p2后面的结点连在了一起 				free(p2);                        //依旧记得释放没用的结点 			} 			else p1 = p2;                        //如果没找到，p1就到了p2的位置 			p2 = p1->next;                       //不管有没有找到，一定要保证p2永远在p1后面 		} 		printf("继续删除请按回车，结束请按空格:\n"); 		ch1 = getchar();                       //将回车键赋给CH1，否则num输完后再输入的回车键会赋给CH，因此用CH1填补。 		ch = getchar(); 	} 	return head; }  void choose(SUB *head) { 	SUB *p, *q; 	int a[5]; 	int num, total = 0, i = 0, j; 	printf("输入要选修的课程的编号，编号之间以空格分开，输完后以0结束\n"); 	scanf_s("%d", &num); 	while (num != 0){ 		for (p = head; p; p = p->next) 		if (p->num == num){ 			total = total + p->score; 			a[i] = num; 			i++; 		} 		scanf_s("%d", &num); 	} 	if (total<60) printf("选修总学分未达到60,选修失败!\n"); 	else { 		printf("选修成功!!\n"); 		printf("您选修的课程为:\n"); 		for (j = 0; j<i; j++) 		for (q = head; q; q = q->next) 		if (q->num == a[j]) 			printf("%s  ", q->name); 		printf("\n"); 	} }  void main() { 	SUB *head = create_form();                 //创建表 	savefile(head);                            //存表 	prin(head);                               //打印表 	search(head);                             //查找 	head = insert(head);                        //函数insert的的返回值 	savefileadd(head);                         //存添加后的表 	printf("修改后的信息为:\n"); 	prin(head); 	head = del(head);                           //函数del的的返回值 	savefiledel(head); 	printf("修改后的课程信息为:\n"); 	prin(head); 	choose(head); }     .......写到最后写不下去了.....不是自己的代码，感觉看着一直想吐槽，有什么看不懂的可以问我，强烈建议，这种题创建链表要用带有头结点的,这道题，这道题没有......  （楼上说的有道理，代码功能归根结底不是别人帮自己看或讲解或注释出来的，只是毕竟自己学渣学链表的时候还是很希望有人带带自己。。。）

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

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct subjects {     int num;     char name[20];     char kind[10];     int stime;     int ttime;     int etime;     int score;     int term;     struct subjects *next; }SUB;  SUB *create_form() {     SUB *head,*tail,*p;     int num,stime,ttime;     int etime,score,term;     char name[20],kind[10];     int size=sizeof(SUB);     head=tail=NULL;     printf("输入选修课程信息:\n");     /* name and kind remove the char '&' */     scanf("%d %s %s %d %d %d %d %d", &num, name, kind,&stime,&ttime,&etime,&score,&term);     while(num!=0){         p=(SUB *)malloc(size);         p->num=num;         strcpy(p->name,name);         strcpy(p->kind,kind);         p->stime=stime;         p->ttime=ttime;         p->etime=etime;         p->score=score;         p->term=term;         if(head==NULL)             head=p;         else             tail->next=p;         tail=p;     /* name and kind remove the char '&' */         scanf("%d %s %s %d %d %d %d %d",&num, name, kind, &stime,&ttime,&etime,&score,&term);     }     tail->next=NULL;     return head; }  void savefile(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjects.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void savefileadd(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjectsadd.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void savefiledel(SUB *head) {     SUB *p;     FILE *fp;     fp=fopen("subjectsdel.txt","w");     fprintf(fp,"课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(p=head;p;p=p->next)         fprintf(fp,"%5d%12s%9s%9d%9d%11d%11d%7d\n",p->num,p->name,p->kind,p->stime,p->ttime,p->etime,p->score,p->term);     fclose(fp); }  void prin(SUB *head) {     SUB *ptr;     if(head==NULL){         printf("没有此门课程记录\n");         return;     }     printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");     for(ptr=head;ptr;ptr=ptr->next)         printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term); } void search(SUB *head) {     int a,num;     int t=1;     char type[10];     char ch='a',ch1;     SUB *ptr;      while(ch!=' '){         printf("按课程性质查找输入1，按学分查找输入2:\n");         scanf("%d",&a);         switch(a){             case 1:printf("输入要查找的课程性质:\n");                    scanf("%s",type);                    printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");                    for(ptr=head;ptr;ptr=ptr->next)                        if(strcmp(type,ptr->kind)==0){                            printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term);                            t=0;                        }                    if(t) printf("未找到\n");                    t=1;                    break;             case 2:printf("输入要查找的课程的学分\n");                    scanf("%d",&num);                    printf("课程编号 课程性质 总学时 授课学时 实验或上机学时 学分 开课学期\n");                    for(ptr=head;ptr;ptr=ptr->next)                        if(ptr->score==num){                            printf("%5d%12s%9s%9d%9d%11d%11d%7d\n",ptr->num,ptr->name,ptr->kind,ptr->stime,ptr->ttime,ptr->etime,ptr->score,ptr->term);                            t=0;                        }                    if(t) printf("未找到\n");                    t=1;          }         printf("继续查找请按回车，结束请按空格:\n");         ch1=getchar();                              //将回车键赋给CH1，否则CASE里面最后输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     } }  SUB *insert(SUB *head) {     SUB *ptr,*ptr2,*subj;     int size=sizeof(SUB);     char ch='a',ch1;     while(ch!=' '){         subj=(SUB *)malloc(size);         ptr=subj;         printf("输入要插入的课程信息:\n");         scanf("%d%s%s%d%d%d%d%d", &subj->num, subj->name, subj->kind,&subj->stime,&subj->ttime,&subj->etime,&subj->score,&subj->term);         if(head==NULL){             head=ptr;             head->next=NULL;         }         else{             for(ptr2=head;ptr2;ptr2=ptr2->next)                 if(ptr2->next==NULL){                     ptr2->next=subj;                     subj->next=NULL;                     break;                 }         }         printf("继续插入请按回车，结束请按空格:\n");         ch1=getchar();                      //将回车键赋给CH1，否则subj->term输完后输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     }     return head; }     SUB *del(SUB *head) {     SUB *p1,*p2;     char ch='a',ch1;     int num;     while(ch!=' '){         printf("输入要删除的课程编号:\n");         scanf("%d",&num);         if(head->num==num){             p2=head;             head=head->next;             free(p2);         }         if(head==NULL)             return NULL;         p1=head;         p2=head->next;         while(p2){             if(p2->num==num){                 p1->next=p2->next;                 free(p2);             }             else p1=p2;             p2=p1->next;         }         printf("继续删除请按回车，结束请按空格:\n");         ch1=getchar();                       //将回车键赋给CH1，否则num输完后再输入的回车键会赋给CH，因此用CH1填补。         ch=getchar();     }     return head; }  void choose(SUB *head) {     SUB *p,*q;     int a[5];     int num,total=0,i=0,j;     printf("输入要选修的课程的编号，编号之间以空格分开，输完后以0结束\n");     scanf("%d",&num);     while(num!=0){         for(p=head;p;p=p->next)             if(p->num==num){                 total=total+p->score;                 a[i]=num;                 i++;             }         scanf("%d",&num);     }     if(total<60) printf("选修总学分未达到60,选修失败!\n");     else {         printf("选修成功!!\n");         printf("您选修的课程为:\n");         for(j=0;j<i;j++)             for(q=head;q;q=q->next)                 if(q->num==a[j])                     printf("%s  ",q->name);         printf("\n");     } }  int main() {     SUB *head=create_form();     savefile(head);     prin(head);     search(head);     head=insert(head);                        //函数insert的的返回值     savefileadd(head);     printf("修改后的信息为:\n");     prin(head);     head=del(head);                           //函数del的的返回值     savefiledel(head);     printf("修改后的课程信息为:\n");     prin(head);     choose(head); }   有两处错误～

总要是链表那一块有点模糊

请从main函数看起，哪里不懂就百度，必应，查参考书，要是还不懂就指出来是哪里。


Question: vs2010编译C代码的奇怪问题 error C2039： 不是成员

名字冲突了，你改个名字试试

CreateMutex是个宏，没定义UNICODE宏时，会被替换成CreateMutexA

引用 5 楼 zhaoxuefeng2180 的回复:[quote=引用 4 楼 user-1 的回复:] [quote=引用 3 楼 zhaoxuefeng2180 的回复:] [quote=引用 2 楼 user-1 的回复:] 名字冲突了，你改个名字试试  换名字不太方便，我定义了UNICODE试，报错变成 error C2039: “CreateMutexW”: 不是“INITIALIZE_ARGS”的成员  有办法不用改成员名来通过编译么？[/quote] 把宏删掉#undef CreateMutex[/quote]  我在头文件定义结构体之前undef了还是报错。 或者是源文件include的其它头文件又把windows定义的宏给弄进来了 我干脆改源文件吧，顺便把成员名字改了 [/quote] 不要改头文件，写在源文件里，所有的include最下面

引用 4 楼 user-1 的回复:[quote=引用 3 楼 zhaoxuefeng2180 的回复:] [quote=引用 2 楼 user-1 的回复:] 名字冲突了，你改个名字试试  换名字不太方便，我定义了UNICODE试，报错变成 error C2039: “CreateMutexW”: 不是“INITIALIZE_ARGS”的成员  有办法不用改成员名来通过编译么？[/quote] 把宏删掉#undef CreateMutex[/quote]  我在头文件定义结构体之前undef了还是报错。 或者是源文件include的其它头文件又把windows定义的宏给弄进来了 我干脆改源文件吧，顺便把成员名字改了

引用 3 楼 zhaoxuefeng2180 的回复:[quote=引用 2 楼 user-1 的回复:] 名字冲突了，你改个名字试试  换名字不太方便，我定义了UNICODE试，报错变成 error C2039: “CreateMutexW”: 不是“INITIALIZE_ARGS”的成员  有办法不用改成员名来通过编译么？[/quote] 把宏删掉#undef CreateMutex

引用 2 楼 user-1 的回复:名字冲突了，你改个名字试试  换名字不太方便，我定义了UNICODE试，报错变成 error C2039: “CreateMutexW”: 不是“INITIALIZE_ARGS”的成员  有办法不用改成员名来通过编译么？


Question: strcat函数链接字符串，目标串内容被覆盖问题

引用 1 楼 cfjtaishan 的回复:你的程序有error，语法错误哦 我删掉了一些没用的，多删掉了一行代码 int nLen = strlen(s); 应该是这个没有定义吧，在37行代码前边放上这个应该就不会有语法错误了，程序的错误不是这个

你的程序有error，语法错误哦

闲着没事，用代码实现了一下，参考参考吧#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h>  //生成随机字符串 void get_rand_str(int number,char szHex[]) { 	char str[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 	int len=strlen(str); 	char ss[3];  	szHex[0]=0; 	for (int i=0;i<number;i++) 	{ 		ss[0]=0; 		sprintf(ss,"%X",str[rand()%len]); 		strcat(szHex,ss); 	} 	printf("szHex : %s\n",szHex); }  int main() { 	srand((unsigned int)time(0));  	char strTxt[4096]={0}; 	char sz[20]={0}; 	while (strlen(strTxt)<4095) 	{ 		get_rand_str(8,sz); 		strncat(strTxt,sz,strlen(sz)); 		//usleep(50); 	}  	return 0; }

感谢各位大虾，很久不在Linux下写ARM上的C程序了，完全蒙圈，问题解决了，越界问题也清理了，谢谢各位大虾的帮助，分数不多，分给大家，马上结贴

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

看来看去应该是字符串和字符数组这两个东西分不清，用乱了

#include <sys/statfs.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h>  //字符串转换成16进制 inline char *CharArrayToHexString(char* pOut, const char* pInput, const int nInLen) {     const char* chHexList = "0123456789ABCDEF";     int nIndex = 0;     int i=0, j=0;     for (i = 0, j = 0; i<nInLen;i++, j+=2)     {         nIndex = (pInput[i] & 0xf);         pOut[i*2+1] = chHexList[nIndex];         nIndex = ((pInput[i]>>4) & 0xf);         pOut[i*2] = chHexList[nIndex];     }     //printf("pOut hexString:%s\n",pOut);     return pOut; } //生成随机字符串 void get_rand_str(char s[], int number,char szHex[]) {     char str[64] = "00123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";     int i;     char ss[2] = {0};     srand((unsigned int)time(0));     for(i = 1;i <= number;i++){         sprintf(ss,"%c",str[(rand()%62)+i]);         //printf("rand:%s\n",ss);         strcat(s, ss);     }     int nLen = strlen(s);     printf("%d: %d\n", __LINE__, nLen);     //将8个字符换成十六进制串表示     CharArrayToHexString(szHex, s, nLen);     nLen = 2*nLen;     szHex[nLen] = '\0';     printf("szHex : %s\n",szHex); }  int main() {     char strTxt[4096]={0};      char s[12] = {0};     char sz[20] = {0};      while(1){         if(strlen(strTxt)<=4096){             get_rand_str(s, 8, sz);             if (strlen(strTxt) + strlen(sz) > 4096-1)                 break;             strncat(strTxt, sz, strlen(sz));             printf("strTxt:%s ;sz length %d;strTxt length:%d\n",strTxt, strlen(sz), strlen(strTxt));             memset(sz, 0x0, sizeof(sz));             memset(s, 0x0, sizeof(s));             //usleep(50);         }         else{                 break;         }     } }  main函数中的s也是越界的。s是8个字符空间，而你往里面放了8个字符没有'\0'的空间； 在ARM板上运行注意要字节对齐吧，因为ARM的指令和X86是不一样的。X86是复杂指令集，而arm是简单的指令集，建议以4字节方式对齐。

数组s和数组ss代表的字符串没有空间存放空终结字符‘\0’

除了刚才楼上讲过的strTxt越界问题，之外，还有一个问题可能是导致你这种情况的原因：  char sz[17] = {0}; //... memset(sz,0x0,20);   请改为: memset(sz, 0x00, sizeof(sz));

引用 4 楼 cfjtaishan 的回复:sz length 14;strTxt length:4104 strTxt长度越界了 我在Ubuntu上运行的时候也知道这个样子的结果，但是放到ARM板上的Linux系统上运行不到越界  程序再ARM板上的Linux系统下边运行的时候，第二次执行到main函数第54行strcat这个函数的时候，会把strTXT里边第一次放进去的字符串都覆盖掉，printf显示出来的字符串还是16个字节大小，上一次拼进去的字符串被覆盖掉了  我这么描述能描述清楚吗？ 程序不会执行到数组越界，因为strTxt在使用strlen测试大小的时候始终都是16个字节

引用 3 楼 adlay 的回复:if(strlen(strTxt)<=4096):   在 strlen(strTxt)==4096 的时候, 再执行你下面的语句访问就越界了 不是，我的意思是程序再ARM板上的Linux系统下边运行的时候，第二次执行到main函数第54行strcat这个函数的时候，会把strTXT里边第一次放进去的字符串都覆盖掉，printf显示出来的字符串还是16个字节大小，上一次拼进去的字符串被覆盖掉了  我这么描述能描述清楚吗？ 程序不会执行到数组越界，因为strTxt在使用strlen测试大小的时候始终都是16个字节


Question: y=1.5 f

将1.5赋值给y而已，若y不是float或double型，将会丢失精度

1.5作为float型常量 因为不加后缀的小数形式常量，C语言都把它作为double型

缺省是double，加f表示float

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

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


Question: 把C代码编为DLL使用VB调用

那个VB代码用的多项式不一样，而且是查表法。  用楼主的代码创建DLL也很简单，保存为crc16.cpp：  #include <windows.h>  /*CRC-16效验函数 多项式为X^16+X^15+X^2+1  CRC_RESULT为全局变量，是计算结果结果，可能有上次计算的结果在 */ extern "C" _declspec(dllexport) unsigned int CRC_16(unsigned char *str, int lenth) {   unsigned char k;   unsigned long temp=0;   while(lenth--)   {     for(k = 0x80; k != 0; k = k>>1)     {       temp = temp * 2;       if((temp & 0x10000) != 0)       temp = temp ^ 0x18005;       if((*str & k) != 0)       temp = temp ^ (0x10000 ^ 0x18005);     }     str++;   }   return temp; }  BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {   HANDLE g_hModule;    switch(dwReason)   {     case DLL_PROCESS_ATTACH:       break;      case DLL_PROCESS_DETACH:       break;   }    return true; }   编译，假设用VC++: cl /O2 /LD crc16.cpp

CRC16如果用 RAMDISK，估计会卡。  GOOGLE可以查到这个 http://www.tek-tips.com/viewthread.cfm?qid=1587721  修改一下应该可以。

不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件，或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。 比如： A将请求数据写到文件a.txt，写完后改名为aa.txt B发现aa.txt存在时，读取其内容，调用相应功能，将结果写到文件b.txt，写完后删除aa.txt，改名为bb.txt A发现bb.txt存在时，读取其内容，读完后删除bb.txt 以上A可以替换为任何一种开发语言或开发环境，B可以替换为任何一种与A不同的开发语言或开发环境。 除非A或B不支持判断文件是否存在、文件读写和文件更名。 但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢？ 可以将临时文件放在RamDisk上提高效率减少磨损磁盘。 数据的结构很复杂的话，文本文件的格式问题可参考json或xml  共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多，下面仅列出我现在能想到的： ·进程之间松耦合 ·进程可在同一台机器上，也可跨机，跨操作系统，跨硬件平台，甚至跨国。 ·方便调试和监视，只需让第三方或人工查看该临时文本文件即可。 ·方便在线开关服务，只需删除或创建该临时文本文件即可。 ·方便实现分布式和负载均衡。 ·方便队列化提供服务，而且几乎不可能发生队列满的情况（除非硬盘空间满） ·……  “跨语言、跨机，跨操作系统，跨硬件平台，跨国，跨*.*的”苦海无边， 回头是“使用共享纯文本文件进行信息交流”的岸！

那为什么不用vb写，然后生成dll呢


Question: 读入两个小于100的正整数A和B，计算A+B，需要注意的是A和B的为一位数字由对应的英文单词输入，且结果也由英文输出

我编的另一种思路  #include<stdio.h> #include<string.h> int main() {     char a[10][10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};     char str[100];     int j, y = 0, z = 0, sum = 0, b = 0, d = 0, e = 0;      while(1)     {         y = 0;         z = 0;         sum = 0;         b = 0;         d = 0;         e = 0;          while(b == 0)         {             scanf("%s", str);              for(j = 0; j < 10; j++)             {                 if(strcmp(str, a[j]) == 0)                 {                     d = j;                     y = y * 10 + d;                 }                  if(strcmp(str, "+") == 0)                 {                     b++;                     break;                 }             }         }          while(b == 1)         {             scanf("%s", str);              for(j = 0; j < 10; j++)             {                 if(strcmp(str, a[j]) == 0)                 {                     e = j;                     z = z * 10 + e;                 }                  if(strcmp(str, "=") == 0)                     break;             }              if(strcmp(str, "=") == 0)                 break;         }          if(y == 0 && z == 0)             return 0;          sum = y + z;         printf("%d\n", sum);     }      return 0; }

写得太繁琐~~~

#include<iostream> #include<cstring> using namespace std;    char judgeword(char c[],int i) {     if(c[i]=='o')     return 1;     else if(c[i]=='t'&&c[i+1]=='w')     return 2;     else if(c[i]=='t'&&c[i+1]=='h')     return 3;     else if(c[i]=='f'&&c[i+1]=='o')     return 4;     else if(c[i]=='f'&&c[i+1]=='i')     return 5;     else if(c[i]=='s'&&c[i+1]=='i')     return 6;     else if(c[i]=='s'&&c[i+1]=='e')     return 7;     else if(c[i]=='e')     return 8;     else if(c[i]=='n'&&c[i+1]=='i')     return 9;     else if(c[i]=='z')     return 0;  } int main() {     char a[100];     char b[100];     char c[100];               while(cin.getline(a,50))     {         int x=0;         int y=0;         int m=0;         int n=0;         int add1=0;         int add2=0;         //int z=judgeword(a,0);          //cout<<a<<endl<<judgeword(a,0)*1<<endl<<z<<endl;         //cout<<a[18]<<endl;          for(int i=0;i<strlen(a);i++)         {             if(a[i]==43)                 x =i;             else if( a[i]== 61)                 y=i;                    }           //cout<<x<<'\t'<<y<<endl;          for(int i=0;i<x-1;i++)         {             // b[n]=a[i];             // n++;             if(a[i]==32)                        {                   add1=judgeword(a,i+1)*1+judgeword(a,0)*10;                 break;             }             else                      add1=judgeword(a,0);         }         // cout<<b<<'\t'<<n<<endl;         for(int j=x+2;j<y-1;j++)         {             // c[m]=a[i];             // m++;             if(a[j]==32)                     {                 add2=judgeword(a,j+1)*1+judgeword(a,x+2)*10;                 //cout<<j<<endl;                 //cout<<judgeword(a,j+1)*1<<endl<<judgeword(a,x+2)*10<<endl;                 break;            }                 else              add2=judgeword(a,x+2);         }         // cout<<c<<'\t'<<m<<endl;         // for(int i=0;i<strlen(b);i++)         // {         //     if(b[i]==32)                     //     add1=judgeword(b,i+1)+judgeword(b,0)*10;                      //     else          //     add1=judgeword(b,0);         // }                    // for(int i=0;i<strlen(c);i++)         // {         //     if(c[i]==32)                    //    {         //         add2=judgeword(c,i+1)+judgeword(c,0)*10;         //         cout<<i<<endl;         //         cout<<judgeword(c,i+1)<<endl<<judgeword(c,0)*10<<endl;         //    }         //         else          //     add2=judgeword(c,0);          // }         //cout<<judgeword(c,0)<<endl;         //cout<<add1<<'\t'<<add2<<endl;             if(add1+add2==0)         break;           else cout<<add1+add2<<endl;                memset(a,0,sizeof(a));                 memset(b,0,sizeof(b));         memset(c,0,sizeof(c));      } return 0; }

网上找下AC的代码吧。 1.看看你们的输入输出格式是不是一致 2.多测试一些样例

两个小于100的正整数之和小于200

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

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h>  #define     MAX_STR_LEN     128 #define     DIGIT_NUM       10  const char *digit_str[DIGIT_NUM] = {     "zero", "one", "two", "three", "four",     "five", "six", "seven", "eight", "nine" };   int ret_idx(const char *src) {     assert(src != NULL);     int i;      for (i = 0; i < DIGIT_NUM; i++) {         if (!strncmp(src, digit_str[i], strlen(digit_str[i])))             break;     }      return i; }  int get_num(char *str) {     assert(str != NULL);      char *tmp, *save_str = NULL;     int num = 0, idx;      tmp = strtok_r(str, " ", &save_str);     if (tmp) {         idx = ret_idx(tmp);         if (idx >= DIGIT_NUM)             return -1;         num = idx;         tmp = strtok_r(save_str, " ", &save_str);         if (tmp) {             idx = ret_idx(tmp);             if (idx >= DIGIT_NUM)                 return -1;             num =num * 10 + idx;          }     } else {         return -1;     }      return num; } static int del_space(char *src) {     assert(src != NULL);     int i = 0, j = 0;     int len = strlen(src);      char *str = (char *)malloc(sizeof(char) * len + 1);     if (!str)         return -1;     while (src[i]) {         if (src[i] != ' ') {             str[j++] = src[i];         }         i++;     }     str[j] = 0;      memcpy(src, str, j+1);      free(str);     return 0; }  void separate_str(int *num1, int *num2, char *str) {     assert(num1 != NULL && num2 != NULL && str != NULL);      int i;     char *src1 = str, *src2;      int len = strlen(str);     //del_space(str);     for (i = 0; i < len; i++) {         if (str[i] == '=') {             str[i] = 0;             break;         }         if (str[i] == '+') {             str[i] = 0;             src2 = str+i+1;         }     }      *num1 = get_num(src1);     *num2 = get_num(src2); }   int switch_digit(int *array, int num) {     int i = 0;      while (num) {         array[i++] = num % 10;         num /= 10;     }      return i; }  void print_as_str(int *array, int digit_cnt) {     switch (digit_cnt) {         case 1:             printf("%s", digit_str[array[0]]);             break;          case 2:             printf("%s %s", digit_str[array[1]], digit_str[array[0]]);             break;          case 3:             printf("%s %s %s", digit_str[array[2]], digit_str[array[1]], digit_str[array[0]]);             break;          default:             printf("Not support!\n");             break;     }     /*     if (digit_cnt <= 1) {         printf("%s ", digit_str[array[0]]);     } else if (digit_cnt <= 2) {         printf("%s %s", digit_str[array[1]], digit_str[array[0]]);     } else if (digit_cnt == 3) {         printf("%s %s %s", digit_str[array[2]], digit_str[array[1]], digit_str[array[0]]);     } else {         printf("Not support!\n");     }     */ }  int main(void) {     char op_str[MAX_STR_LEN];     int digit_list[3];     int num1, num2, sum, digit_cnt;      fgets(op_str, MAX_STR_LEN-1, stdin);     op_str[strlen(op_str)-1] = 0;      separate_str(&num1, &num2, op_str);     if (num1 < 0 || num2 < 0) {         printf("Input error!\n");         return -1;     }     sum = num1 + num2;      digit_cnt = switch_digit(digit_list, sum);     print_as_str(digit_list, digit_cnt);     putchar(10);     return 0; }  用这个版本改一改就可以实现你的功能；  #include <stdio.h>  #define     DIGIT_NUM   10 const char *digit_str[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};  int switch_digit(int *array, int num); void print_as_str(int *array, int digit_cnt);  int main(void) {     int digit_cnt, num1, num2, sum;     int digit[DIGIT_NUM];      printf("Please input two num: ");     scanf("%d%d", &num1, &num2);      sum = num1 + num2;      digit_cnt = switch_digit(digit, num1);     print_as_str(digit, digit_cnt);     printf(" + ");     digit_cnt = switch_digit(digit, num2);     print_as_str(digit, digit_cnt);     printf(" = ");      digit_cnt = switch_digit(digit, sum);     print_as_str(digit, digit_cnt);     putchar(10);     return 0; }   int switch_digit(int *array, int num) {     int i = 0;      while (num) {         array[i++] = num % 10;         num /= 10;     }      return i; }  void print_as_str(int *array, int digit_cnt) {     switch (digit_cnt) {         case 1:             printf("%s", digit_str[array[0]]);             break;          case 2:             printf("%s %s", digit_str[array[1]], digit_str[array[0]]);             break;          case 3:             printf("%s %s %s", digit_str[array[2]], digit_str[array[1]], digit_str[array[0]]);             break;          default:             printf("Not support!\n");             break;     }     /*     if (digit_cnt <= 1) {         printf("%s ", digit_str[array[0]]);     } else if (digit_cnt <= 2) {         printf("%s %s", digit_str[array[1]], digit_str[array[0]]);     } else if (digit_cnt == 3) {         printf("%s %s %s", digit_str[array[2]], digit_str[array[1]], digit_str[array[0]]);     } else {         printf("Not support!\n");     }     */ }  这个是反过来的。  这样题目难到时不难，就是比较麻烦一些吧。主要是字符串的操作。如果不熟悉，多练习一下吧

边界值测判定， 异常输入判定，

这是题目原题


Question: 蓝桥杯报纸页数问题

引用 1 楼 adlay 的回复:假设报纸的总页数为 x, 则: 第一张的页码为:  1, 2, x-1, x 第二张的页码为:  3, 4, x-3, x-2 第三张的页码为:   5, 6, x-5, x-4 ... 第 N 张的页码为:  2N - 1, 2N, x - (2N -1), x - (2N - 2)  可见, 每张报纸的页码加起来 2N - 1 + 2N + x - (2N - 1) + x - (2N - 2)  = 2x + 2  于是就有 2x + 2 = 1125 + 1126 + 1727 + 1728 求解一下就得到 x = 2852 所以, 这份报纸一共有 2852 页   厉害了

现在流行互相伤害，不流行互相吹捧。

引用 2 楼 zhao4zhong1 的回复:[quote=引用 1 楼 adlay 的回复:] 假设报纸的总页数为 x, 则: 第一张的页码为:  1, 2, x-1, x 第二张的页码为:  3, 4, x-3, x-2 第三张的页码为:   5, 6, x-5, x-4 ... 第 N 张的页码为:  2N - 1, 2N, x - (2N -1), x - (2N - 2)  可见, 每张报纸的页码加起来 2N - 1 + 2N + x - (2N - 1) + x - (2N - 2)  = 2x + 2  于是就有 2x + 2 = 1125 + 1126 + 1727 + 1728 求解一下就得到 x = 2852 所以, 这份报纸一共有 2852 页 adlay当年在班上是学霸。我猜的没错吧。[/quote] 赵四老师当年肯定也是学霸吧。。

引用 2 楼 zhao4zhong1 的回复:[quote=引用 1 楼 adlay 的回复:] 假设报纸的总页数为 x, 则: 第一张的页码为:  1, 2, x-1, x 第二张的页码为:  3, 4, x-3, x-2 第三张的页码为:   5, 6, x-5, x-4 ... 第 N 张的页码为:  2N - 1, 2N, x - (2N -1), x - (2N - 2)  可见, 每张报纸的页码加起来 2N - 1 + 2N + x - (2N - 1) + x - (2N - 2)  = 2x + 2  于是就有 2x + 2 = 1125 + 1126 + 1727 + 1728 求解一下就得到 x = 2852 所以, 这份报纸一共有 2852 页 adlay当年在班上是学霸。我猜的没错吧。[/quote] 高中还可以算是吧, 大学就成渣了

引用 1 楼 adlay 的回复:假设报纸的总页数为 x, 则: 第一张的页码为:  1, 2, x-1, x 第二张的页码为:  3, 4, x-3, x-2 第三张的页码为:   5, 6, x-5, x-4 ... 第 N 张的页码为:  2N - 1, 2N, x - (2N -1), x - (2N - 2)  可见, 每张报纸的页码加起来 2N - 1 + 2N + x - (2N - 1) + x - (2N - 2)  = 2x + 2  于是就有 2x + 2 = 1125 + 1126 + 1727 + 1728 求解一下就得到 x = 2852 所以, 这份报纸一共有 2852 页 adlay当年在班上是学霸。我猜的没错吧。


Question: vs2013打开和创建c项目时失败：未经处理的异常在 Microsoft.VisualStudio.Shell.UI.Internal.dll 中发生

应该是安装出问题，建议重新安装或者换个编译器吧，vs有两面性


Question: malloc函数，求解

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

linux下的malloc是开源的。

说了你别不信，网上有个叫搜索引擎的东西： https://www.baidu.com/s?wd=malloc

malloc全称memory allocate即内存分配 参数有一个，类型是size_t,即需要分配的内存大小 返回值为void *,即分配来的内存首地址。


Question: 一个十分简单的c语言程序。。。但是我不知道哪儿错了。已经生成了可执行文件。。

如果你看过c plus你就明白了，里面讲得很详细

因为sum没有初始化，所以sum的值是随机的，很多人都认为声明一个变量后变量值就为0，其实不是

重新编译链接。

嗯嗯恩，sum没有初始化，但是用gdb调试的时候为什么会跳到第28行去了呢？搞出了一堆完全不知所云的东西

int main() {    .........     return 0;  // 或者你就干脆 void main() }

sum不赋个初值，鬼知道会取个什么值。


Question: 初学小白有个问题搞不懂请教大神

while ((cho = get_choice())!='q') 每次循环都执行一次  如果你写成 int cho = get_choice();  while ( cho !='q') // 仅执行一次get_choice()，如果cho不为q，那么会造成死循环

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

单步调试就很清楚程序怎么走的了

不同之处在于，一个的值是循环一次刷新一次；另一个是仅刷新一次，也就是说while条件表达式为一个固定值。

取值表达式在while里边时，它是循环取值的，每次都会判断； 取值表达式在while之前，它只会取一次，是个定值，所以还会死循环；


Question: 网上找的C模拟面向对象多态的方法例子，有个错误解决不了，请大神指点

引用 16 楼 user-2 的回复:[quote=引用 15 楼 xflltw 的回复:] [quote=引用 14 楼 xflltw 的回复:] [quote=引用 12 楼 user-2 的回复:] 为方便运行，我把所有文件放在一起，并把include 自定义文件注释掉了， 修改后的代码与运行结果见http://ideone.com/VgWWWg 你在base.h中加了“const void *Base;”，能不加这个么？[/quote] 谢谢[/quote] 不能。就靠这个为0定位到struct Base类。[/quote] 谢谢啦，我再看看

李涛你又调皮了

引用 15 楼 xflltw 的回复:[quote=引用 14 楼 xflltw 的回复:] [quote=引用 12 楼 user-2 的回复:] 为方便运行，我把所有文件放在一起，并把include 自定义文件注释掉了， 修改后的代码与运行结果见http://ideone.com/VgWWWg 你在base.h中加了“const void *Base;”，能不加这个么？[/quote] 谢谢[/quote] 不能。就靠这个为0定位到struct Base类。

引用 14 楼 xflltw 的回复:[quote=引用 12 楼 user-2 的回复:] 为方便运行，我把所有文件放在一起，并把include 自定义文件注释掉了， 修改后的代码与运行结果见http://ideone.com/VgWWWg 你在base.h中加了“const void *Base;”，能不加这个么？[/quote] 谢谢

引用 12 楼 user-2 的回复:为方便运行，我把所有文件放在一起，并把include 自定义文件注释掉了， 修改后的代码与运行结果见http://ideone.com/VgWWWg 你在base.h中加了“const void *Base;”，能不加这个么？

引用 11 楼 user-2 的回复:实测这样更改有效：  1。circleConstructor函数中增加， struct Base *p = (struct Base *)self->point; //self->point分配内存 self->point->Base = p;  因为在new函数把base指针最近的上一级，即point指针  2。 把privateCircle结构体中的point指针改名Base（circle_.c中使用point的地方也改成Base） Base结构体中也增加一个名为Base的指针并初始化为0(circle_.c与point_.c中也相应修改) 这样可以用来向上搜索到顶部 3。 new_.c中的draw函数改成 const struct Base *cp = (const struct Base *)self; while (cp->Base) { 	cp = *(const struct Base **) (cp);  } cp->draw(self);  好的，非常感谢，我正在看

引用 9 楼 xflltw 的回复:[quote=引用 7 楼 user-2 的回复:] 主要错在new函数中的这句*(const struct Base**)p = base; point直接继承自base，所以可以取到，circle隔开了，所以取不到 这一句应该是没问题的，“Circle Constructor: 3, 4, 5”都打印出来了 [/quote] circle constructor3 4 5可以打印出来是因为传给new函数是的Circle全局变量 而传给draw函数的是p2

引用 7 楼 user-2 的回复:主要错在new函数中的这句*(const struct Base**)p = base; point直接继承自base，所以可以取到，circle隔开了，所以取不到 这一句应该是没问题的，“Circle Constructor: 3, 4, 5”都打印出来了

引用 5 楼 user-2 的回复:我试了下，输出是： Circle Constructor: 3, 4, 5 new: draw Point draw: 1, 2 new: draw Segmentation fault (core dumped) 应该调用circle_.c的circleDraw方法

引用 3 楼 user-2 的回复:[quote=引用 2 楼 xflltw 的回复:] [quote=引用 1 楼 user-2 的回复:] 不是跑起来了吗，Here's the error, in new_.c, why can't invoke draw method in circle?就是程序输出的 应该调用circle的draw方法[/quote] Here's the error, in new_.c, why can't invoke draw method in circle 这句话就写在draw函数里面，所以已经调用了[/quote]  应该调用circle_.c的circleDraw方法

引用 2 楼 xflltw 的回复:[quote=引用 1 楼 user-2 的回复:] 不是跑起来了吗，Here's the error, in new_.c, why can't invoke draw method in circle?就是程序输出的 应该调用circle的draw方法[/quote] Here's the error, in new_.c, why can't invoke draw method in circle 这句话就写在draw函数里面，所以已经调用了

引用 1 楼 user-2 的回复:不是跑起来了吗，Here's the error, in new_.c, why can't invoke draw method in circle?就是程序输出的 应该调用circle的draw方法


Question: 如何把结构体变量输出到磁盘

谢谢，在你们的帮助下这个问题解决了。

你这样子输出是一块内存啊，明文当然是很难读懂的 fprintf(fp, "%s %d %d %s\n", na, num, age, add); 这样子试试

结构体输出到磁盘，结构体每个成员挨个输出就好了


Question: 小白疑问之对齐

引用 3 楼 who18 的回复:那个小数点也算的吗 算

那个小数点也算的吗

100.0 一共５个字母了，超过了4

说错了是像第一张图一样对齐不了 第一张是%4.1lf 第二张是%5.1lf 按理说我最大的100.0也只有4位啊为什么%4.1lf对齐不了 这个左右对齐是怎么计算宽度的


Question: 小白求助

#include <stdio.h>  void asc_sort(int *digit, int len); void des_sort(int *digit, int len); int seperate_digit(int *digit, int num); unsigned int new_num(int *digit, int len);  static void print_digit(int *digit, int len);  #define MAX_DIGIT_LEN   10  int main(void) {     int digit[MAX_DIGIT_LEN];     unsigned int  num, len, cycle_cnt = 0;     unsigned int big, small, diff;      printf("Please input a number: ");     scanf("%u", &num);     diff = num;      /*     len = seperate_digit(digit, num);     asc_sort(digit, len);     printf("Asc sort: \n");     print_digit(digit, len);     small = new_num(digit, len);     des_sort(digit, len);     printf("Des sort: \n");     print_digit(digit, len);     big = new_num(digit, len);     diff = big - small;     printf("%u-%u = %u\n", big, small, diff);     cycle_cnt++;     while (num != diff) {         num = diff;         len = seperate_digit(digit, num);         asc_sort(digit, len);         small = new_num(digit, len);         des_sort(digit, len);         big = new_num(digit, len);         diff = big - small;         printf("%u-%u = %u\n", big, small, diff);         cycle_cnt++;     }     */     do {         num = diff;         len = seperate_digit(digit, num);         asc_sort(digit, len);         small = new_num(digit, len);         des_sort(digit, len);         big = new_num(digit, len);         diff = big - small;         printf("%u-%u = %u\n", big, small, diff);         cycle_cnt++;     } while (num != diff);      printf("cycle num = %u, last num = %d\n", cycle_cnt, num);      return 0; }  /* int main(void) {     int n,i,j,a[4],x,t,k,b,c;      scanf("%d",&n);     while(n)     {         n--;         scanf("%d",&x);         a[0]=x/1000;         a[1]=x/100%10;         a[2]=x/10%10;         a[3]=x%10;         for(k=1;;k++)         {             for(i=0;i<4;i++)                 for(j=i+1;j<4;j++)                 {                     if(a[i]>a[j])                     {                         t=a[i];                         a[i]=a[j];                         a[j]=t;                     }                 }             c=a[0]*1000+a[1]*100+a[2]*10+a[3];             b=a[3]*1000+a[2]*100+a[1]*10+a[0];             if((b-c)==6147) break;         }         printf("%d",k);     }     return 0; } */ void des_sort(int *digit, int len) {     int i, j;     int tmp = 0;      for (i = 0; i < len; i++)         for (j = 0; j <len-i-1; j++)             if (digit[j] < digit[j+1]) {                 tmp = digit[j];                 digit[j] = digit[j+1];                 digit[j+1] = tmp;             } } void asc_sort(int *digit, int len) {     int i, j;     int tmp = 0;      for (i = 0; i < len; i++)         for (j = 0; j <len-i-1; j++)             if (digit[j] > digit[j+1]) {                 tmp = digit[j];                 digit[j] = digit[j+1];                 digit[j+1] = tmp;             } }  unsigned int new_num(int *digit, int len) {     int i, num = 0;;      for (i = 0; i < len; i++)         num = num *10 + digit[i];      return num; }  static void print_digit(int *digit, int len) {     int i;      for (i = 0; i < len; i++)         printf("digit[%d] = %d\n", i, digit[i]); }  int seperate_digit(int *digit, int num) {     int i = 0;      while (num) {         digit[i++] = num % 10;         num /= 10;     }      return i; }  我写的一个demo

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

自己找个例子代进去，在程序中加入printf打印需要查看的值，看程序执行到哪不符合你的预期

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


Question: 在写字板中写入matlab的符号函数，如何可以让程序可以知道该函数，并计算出函数值

6楼是1楼功能说明。

引用 3 楼 user-2 的回复:EBNF范式分析字符串，用boost的spirit解析处理 引用 8 楼 zhao4zhong1 的回复:学会1楼就足够了。 嗯的  谢了   我去学习 学习

学会1楼就足够了。

引用 10 楼 zhao4zhong1 的回复:6楼是1楼功能说明。OK

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

引用 4 楼 zhao4zhong1 的回复:[quote=引用 2 楼 qq_29809823 的回复:] [quote=引用 1 楼 zhao4zhong1 的回复:] http://www.codeproject.com/Articles/286121/Compiler-Patterns全英文啊，能大概帮我讲解下大概思路么，谢谢了。 我先自己去看看试试[/quote] 参考《编译原理》  英语也是一门计算机语言的说。 [/quote]  C:\>eval Command line program for the expression evaluation functions. usage: eval [-test] [-trace] ["expression_to_evaluate" [param1 [param2 ... ]]]    -trace causes a trace of the evaluation steps to be printed to the screen.    -test runs the automated test suite comparing results to known answers.  To see the result of an expression, put it in quotes, followed by the values of the replaceable parameters to be substituted for each p<i> within the expression (where <i> is an integer between 1 and 99; like p1 p01 p5 p98 etc.) -Example command line: >eval "p1>p2 ? sin(p1*pi) : sin(p2*pi)"  0.5  1.5  Available operators:  -- Grouping and replacement -- ()(parenthesis grouping), p1 .. p99 (replaced with parameters), pi (3.14159...)  -- Mathematical Operators --   ^ (exponentiation)    *    /    % (modulo)    +    -  -- Mathematical Functions (x and y are dummy args in the following list) --   abs(x)    acos(x)    asin(x)   atan(x)     atan2(y,x)   ceil(x)   cos(x)    cosh(x)    erf(x)    erfc(x)     exp(x)       fact(x)   floor(x)  gamma(x)   ln(x)     lngamma(x)  log10(x)     mod(x,y)   pow(x,y)  sin(x)     sinh(x)   sqrt(x)     tan(x)       tanh(x)  -- Comparative --   >   >=   <   <=   eq  == (same as eq)  not_eq  != (same as not_eq)  -- Logical --   and   or   not  -- Branching --   ?:(conditional, used like this: "z?x:y" if z is non-zero, x is evaluated,      otherwise, y is evaluated.)

引用 2 楼 qq_29809823 的回复:[quote=引用 1 楼 zhao4zhong1 的回复:] http://www.codeproject.com/Articles/286121/Compiler-Patterns全英文啊，能大概帮我讲解下大概思路么，谢谢了。 我先自己去看看试试[/quote] 参考《编译原理》  英语也是一门计算机语言的说。

EBNF范式分析字符串，用boost的spirit解析处理

引用 1 楼 zhao4zhong1 的回复:http://www.codeproject.com/Articles/286121/Compiler-Patterns全英文啊，能大概帮我讲解下大概思路么，谢谢了。 我先自己去看看试试


Question: 关于char的二维数组

#include <stdio.h> #include <stdlib.h> #include <string.h>  int main() {    char **pt;    int num,i;    char k[40];      printf("How many words do you wish to enter?");    scanf("%d",&num);    printf("\nEnter %d words now :",num);    pt = (char **)malloc(sizeof(char*)*num);    for( i =0;i<num;i++)    {        scanf("%s",k); 		pt[i] = (char *)malloc(strlen(k)+1);        strcpy(pt[i],k);    }    printf("Here are your words:\n");    for(i=0;i<num;i++)    { 		   printf("%s\n",pt[i]); 		   free(pt[i]);    } 	free(pt);     return 0; }

pt[i]其实指向的都是同一个地址（k数组）

pt[i]存放的地址值总是k数组的首地址，你的输入都是放到了数组k中，即后面的输入是覆盖到了k之前存放的数据。而所有pt指针都指向k数组，所以你输出的结果都是一样的。

for(int i =0;i<num;i++)    {        scanf("%s",k);        pt[i]=k; //你让pt[i]全部指向k，当然是一样的    }  下面这样子，记得用完的时候free     pt = (char **)malloc(sizeof(char*)*num);    for(int i =0;i<num;i++)    {        pt[i] = (char *)malloc(sizeof(char)*40);        scanf("%s",pt[i] );    }


Question: strlen()函数使用的一个小疑问

参考：《C和指针》  strlen()的方法签名中的返回值类型为size_t，size_t实际上是一个无符号整型。因此，下面的代码就会有问题：  if( strlen(x) - strlen(y) >= 0 ) ... ; if( strlen(x) - 10 >= 0) ... ; 这样，if语句永远都会执行，因为无符号数不存在负值。实际上，C中很多string相关函数返回值都是无符号数，在使用时要小心谨慎。

http://aoyouzi.iteye.com/blog/1914526 这里是一些算术操作中的隐式转换

strlen返回size_t，一般来说就是unsigned int。unsinged int和int比较，int提升为unsigned int，-1就成了unsigned int能表示的最大值。  这个和len = strlen(str);放哪没什么关系，len压根就没被用到过

隐式转换，strlen返回的是size_t即unsigned int, 右边的lenest是int型的 unsigned int与int相比较时，int会转成unsigned int，所以-1变成了很大的数  解决办法，将左边显式转成int,即 if ((int)strlen(str) > lenest){

请开启所有警告。编译器针对有符号无符号混合运算、变量类型范围导致的条件永为真或永为假判断都会给出警告。


Question: c语言中，打印数组的第1个name值无法显示

引用 楼主 xxchaohu 的回复:/*  * 读入身高和体重，计算并按身高由大到小显示  */  #include <stdio.h> #include <string.h>  typedef struct {     char    name[100];     double  height;     double  weight; } student;  void swap(student *x, student *y) {     student temp = *x;     *x = *y;     *y = temp; }  /*--- 对数组data的前n个元素按身主进行升序排列 ---*/ void sort(student data[], int n) {     int k = n -1;     while (k >= 0) {         int i, j;         for(i = 1, j = -1; i <= k; i++) {             if(data[i-1].height > data[i].height) {                 j = i - 1;                 swap(&data[i], &data[j]);             }         k = j;         }     } } int main(void) {     FILE    *fp;     int     ninzu = 0;  /* 人数 */     char    name[100];  /* 姓名 */     double  height, weight;  /*身高、体重*/      if((fp = fopen("hw.dat", "r")) == NULL)         printf("\a文件打开失败。\n");     else {         int i;         student std[] = {};         while (fscanf(fp, "%s%lf%lf", name, &height, &weight) == 3) {             strcpy(std[ninzu].name, name);             std[ninzu].height = height;             std[ninzu].weight = weight;             printf("std[%d].name=%s\n", ninzu, std[ninzu].name);  /*测试打印name值，可以正常显示*/             ninzu++;         }          sort(std, ninzu);  /* 排序也不正确*/          printf("std[%d].name=%s\n", 0, std[0].name); /*为空*/         for( i = 0; i < ninzu; i++)             printf("%-10s %5.1f %5.1f\n", std[i].name, std[i].height, std[i].weight);  /*第一个std[0].name无法显示*/         printf("---------------------\n");         fclose(fp);      }      return (0); }   显示结果为：  std[0].name=Aiba std[1].name=Kurata std[2].name=Masaki std[3].name=Tanaka std[4].name=Tsuji std[5].name=washio std[0].name=            160.0  59.3 Kurata     162.0  51.6 Masaki     182.0  76.5 Tanaka     170.0  60.7 Tsuji      175.0  83.9 washio     175.0  72.5   hw.dat文件的内容为  Aiba    160 59.3 Kurata  162 51.6 Masaki  182 76.5 Tanaka  170 60.7 Tsuji   175 83.9 washio  175 72.5   49		if((fp = fopen("hw.dat", "r")) == NULL) (gdb)  54			while (fscanf(fp, "%s%lf%lf", name, &height, &weight) == 3) { (gdb)  55				strcpy(std[ninzu].name, name); (gdb)  56				std[ninzu].height = height; (gdb)  57				std[ninzu].weight = weight; (gdb)  59				ninzu++; (gdb) i locals i = 0 std = 0x7fffffffe440 fp = 0x601010 ninzu = 0 name = "Aiba\000\000\000\000\236\344\377\377\377\177\000\000\237\344\377\377\377\177\000\000\001", '\000' <repeats 15 times>"\235, \a\351\364\062", '\000' <repeats 11 times>"\340, \n@", '\000' <repeats 13 times>"\343, \004@\000\000\000\000\000\330\345\377\377\377\177\000\000\000\000\000\000\000\000d@Aiba" height = 160 weight = 59.296886609127348  strcpy之后是可以显示的，我将排序注释掉之后，还是出现这个问题，所以不是排序导致的，我想是不是strcpy，但strcpy之后是可以打印出来的，难道打印出来之后就不见了？

排序问题也解决了，谢谢大家！

引用 7 楼 xxchaohu 的回复:[quote=引用 3 楼 jianwen0529 的回复:] swap使用深度拷贝  你这个swap根本就是错误的，你对栈上的对象赋予指针，不可能修改掉  你的数据本身就是排序好的，看起来像是那么一回事。你换下不是排序的数据测试，你结果完全没有变化  不是排序的问题，排序注释掉，仍然是这个结果[/quote]  谢谢，果然按照你做的就好了

student std[] = {};应该错在这里。这是什么用法，变长数组也需要指定长度？ 我改成 #define MAX 10  student std[MAX] = {}后就没问题了

引用 3 楼 jianwen0529 的回复:swap使用深度拷贝  你这个swap根本就是错误的，你对栈上的对象赋予指针，不可能修改掉  你的数据本身就是排序好的，看起来像是那么一回事。你换下不是排序的数据测试，你结果完全没有变化  不是排序的问题，排序注释掉，仍然是这个结果

引用 4 楼 qq423399099 的回复:代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。 (gdb) n 49		if((fp = fopen("hw.dat", "r")) == NULL) (gdb)  54			while (fscanf(fp, "%s%lf%lf", name, &height, &weight) == 3) { (gdb)  55				strcpy(std[ninzu].name, name); (gdb)  56				std[ninzu].height = height; (gdb)  57				std[ninzu].weight = weight; (gdb)  59				ninzu++; (gdb) i locals i = 0 std = 0x7fffffffe440 fp = 0x601010 ninzu = 0 name = "Aiba\000\000\000\000\236\344\377\377\377\177\000\000\237\344\377\377\377\177\000\000\001", '\000' <repeats 15 times>"\235, \a\351\364\062", '\000' <repeats 11 times>"\340, \n@", '\000' <repeats 13 times>"\343, \004@\000\000\000\000\000\330\345\377\377\377\177\000\000\000\000\000\000\000\000d@Aiba" height = 160 weight = 59.296886609127348  从while循环出来之后就无法打印str[0].name了，还请版主提示下这时怎么调试

改用qsort 吧 int cmp_height(void const *left, void const *right) { 	student *pleft = (student *)left; 	student *pright = (student *)right; 	if (pleft->height > pright->height) return -1; 	else if (pleft->height == pright->height) return 0; 	else return 1; } #include <stdlib.h>  int main() { //.....   qsort(stu, ninzu, sizeof(stu), cmp_height);  //...  }

是你写的sort函数不对导致后面第1个name无法显示


Question: 打印wireshark抓包软件数据

引用 23 楼 zfh19921230 的回复:大神,socket接收到的unsigned char 数组,怎么能再把这个数据同样的发送给客户端 send The Windows Sockets send function sends data on a connected socket.  int send (   SOCKET s,                 const char FAR * buf,     int len,                  int flags               );   Parameters s  [in] A descriptor identifying a connected socket.  buf  [in] A buffer containing the data to be transmitted.  len  [in] The length of the data in buf.  flags  [in] An indicator specifying the way in which the call is made.  Remarks The send function is used to write outgoing data on a connected socket. For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, which can be obtained by using getsockopt to retrieve the value of socket option SO_MAX_MSG_SIZE. If the data is too long to pass atomically through the underlying protocol, the error WSAEMSGSIZE is returned, and no data is transmitted.   The successful completion of a send does not indicate that the data was successfully delivered.  If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in a nonblocking mode. On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both client and server machines. The select, WSAAsyncSelect or WSAEventSelect functions can be used to determine when it is possible to send more data.  Calling send with a zero len parameter is permissible and will be treated by implementations as successful. In such cases, send will return zero as a valid value. For message-oriented sockets, a zero-length transport datagram is sent.  The flags parameter can be used to influence the behavior of the function beyond the options specified for the associated socket. The semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by or-ing the following values:  Value Meaning  MSG_DONTROUTE Specifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag.  MSG_OOB Send out-of-band data (stream-style socket such as SOCK_STREAM only. Also see DECnet Out-Of-band data for a discussion of this topic).    Windows CE: For IrSockets implementation, the Af_irda.h file must be explicitly included.  Return Values If no error occurs, send returns the total number of bytes sent, which can be less than the number indicated by len for nonblocking sockets. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.  Error Codes WSANOTINITIALISED A successful WSAStartup must occur before using this function.  WSAENETDOWN The network subsystem has failed.  WSAEACCES The requested address is a broadcast address, but the appropriate flag was not set. Call setsockopt with the SO_BROADCAST parameter to allow the use of the broadcast address.  WSAEINTR A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall.  WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.  WSAEFAULT The buf parameter is not completely contained in a valid part of the user address space.  WSAENETRESET The connection has been broken due to the "keep-alive" activity detecting a failure while the operation was in progress.  WSAENOBUFS No buffer space is available.  WSAENOTCONN The socket is not connected.  WSAENOTSOCK The descriptor is not a socket.  WSAEOPNOTSUPP MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only receive operations.  WSAESHUTDOWN The socket has been shut down; it is not possible to send on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH.  WSAEWOULDBLOCK The socket is marked as nonblocking and the requested operation would block.  WSAEMSGSIZE The socket is message oriented, and the message is larger than the maximum supported by the underlying transport.  WSAEHOSTUNREACH The remote host cannot be reached from this host at this time.  WSAEINVAL The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled.  WSAECONNABORTED The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable.  WSAECONNRESET The virtual circuit was reset by the remote side executing a "hard" or "abortive" close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable.  WSAETIMEDOUT The connection has been dropped, because of a network failure or because the system on the other end went down without notice.    QuickInfo   Windows NT: Yes   Windows: Yes   Windows CE: Use version 1.0 and later.   Header: Declared in winsock2.h.   Import Library: Link with ws2_32.lib.  See Also recv, recvfrom, select, sendto, socket, WSAAsyncSelect, WSAEventSelect

引用 26 楼 zfh19921230 的回复:现在遇到最后一个问题了,就是怎么将pcm数据转成mp3数据,不通过pcm数据转为pcm文件操作 使用bass库或者NCTAudioStudio控件。

嗯呢,这个我知道了,现在我想问怎么能一边写文件,一边从这个文件里读出来

百度搜相关关键字。

大神,知道ffmpeg怎么将实时说话的音频字节流转为.flv的格式的吗

没约定就约定啊。

引用 18 楼 zfh19921230 的回复:大神,知道怎么将字节流编码成pcm格式的文件吗 参考15楼。

大神,知道怎么将字节流编码成pcm格式的文件吗

发送方的就是字节流

我用那个方法保存到文件,然后文件里都是0000,我把sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);改成sprintf(binstr,"%s %04x",binstr,(unsigned char)buf[i])打印出了一点儿数据

如果数据本来对应发送方发送的某个文件比如mp3文件，将文件的扩展名由bin改为mp3

引用 5 楼 zfh19921230 的回复:void HexDump(char *buf,int len,int addr)我只想要里面的数据段,不要前后的描述的东西,怎么搞啊 参考1楼。

对方发的就是8进制的字节流,格式好像没有约定,接收到的都是8进制的数据

了解一下“bass库”

64-bit doubles (RAW) (*.dbl) 8-bit signed (*.sam) A/mu-Law Wave (*.wav) ACM Waveform (*.wav) Amiga IFF-8SVX (*.iff;*.svx) Apple AIFF (*.aif;*.snd) ASCII Text Data (*.txt) CD Digital Audio (*.cda) Cool Edit Loop (*.cel) Creative Sound Blaster (*.voc) Dialogic ADPCM (*.vox) DiamondWare Digitized (*.dwd) DVI/IMA ADPCM (*.wav) ……

引用 11 楼 zfh19921230 的回复:现在可以用8进制的形式打印出发送的流的数据,怎么把它转化成能播放的MP3或者wav等音频播放的文件格式 这完全决定于发送方和接收方对传输的字节流的格式约定。 比如： DATA_FORMAT_DIALOGIC_ADPCM	 DATA_FORMAT_ALAW			 DATA_FORMAT_G726			 DATA_FORMAT_MULAW			 DATA_FORMAT_PCM				 DATA_FORMAT_G711_ALAW		 DATA_FORMAT_G711_MULAW		 DATA_FORMAT_G721			 DATA_FORMAT_DIALOGIC_ADPCM_U ……

求助大神了啊


Question: 关于字符串队列的奇怪问题

我调用如下函数，又出现同样问题  LinkQueue testqueue; 在调用下面函数前做了队列初始化。  void printQuere(uint8_t *str) {   insertQueue(&testqueue, str);   traverQueue(testqueue); }

谢谢赵老师，另外请教下，如果需要通过串口一条条接收字符串，然后每接收一条就入队，并且遍历一次，又该如何处理呢？也就是事先不知道有多少次入队。  谢谢

#include <stdio.h> #include <stdlib.h> typedef unsigned char uint8_t; typedef unsigned short uint16_t; #define QueueError 255  #define ElemType        uint8_t*  typedef struct QNode {   ElemType data;   struct QNode *next; }QNode, *Queue;  typedef struct LinkQueue {   Queue front;   Queue rear; }LinkQueue;  //队列初始化 uint8_t initQueue(LinkQueue *queue) {   queue->front = queue->rear = (Queue)malloc(sizeof(QNode));   if (NULL == queue->front)   {     return QueueError;   }   queue->front->next = NULL;   return 0; }  //入队 uint8_t insertQueue(LinkQueue *queue, ElemType data) {   Queue q = (Queue)malloc(sizeof(QNode));   if (NULL == q)   {     return QueueError;   }   //插入数据   q->data=data;   q->next=NULL;   //rear 总是指向队尾元素   queue->rear->next=q;   queue->rear=q;   return 0; }  //遍历 void traverQueue(LinkQueue queue)  {   uint16_t i = 1;   Queue q = queue.front->next;      while (q != NULL)   {     printf("队列第%d个元素是：%s\r\n", i, q->data);     q = q->next;     i++;   } }  void test1(void) {   uint8_t *str0=(uint8_t *)"node0";   uint8_t *str1=(uint8_t *)"node1";   uint8_t *str2=(uint8_t *)"node2";   uint8_t *str3=(uint8_t *)"node3";   uint8_t *str4=(uint8_t *)"node4";  //ElemType sdat;   LinkQueue testqueue;    printf("初始化队列 queue\r\n");   initQueue(&testqueue);   traverQueue(testqueue);    insertQueue(&testqueue, str0);   traverQueue(testqueue);   insertQueue(&testqueue, str1);   traverQueue(testqueue);   insertQueue(&testqueue, str2);   traverQueue(testqueue);   insertQueue(&testqueue, str3);   traverQueue(testqueue);   insertQueue(&testqueue, str4); }  void test2(void) { //ElemType sdat;   LinkQueue testqueue;   uint8_t strtemp[4][6];    printf("初始化队列 queue\r\n");   initQueue(&testqueue);   traverQueue(testqueue);    for(uint8_t i=0; i<4; i++)   {     sprintf((char *)(strtemp[i]),"node%d",i);     insertQueue(&testqueue, strtemp[i]);     traverQueue(testqueue);   } } int main() {     test1();     test2();     return 0; } //初始化队列 queue //队列第1个元素是：node0 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第3个元素是：node2 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第3个元素是：node2 //队列第4个元素是：node3 //初始化队列 queue //队列第1个元素是：node0 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第3个元素是：node2 //队列第1个元素是：node0 //队列第2个元素是：node1 //队列第3个元素是：node2 //队列第4个元素是：node3 //


Question: 串口发送数据，怎么判断数据和已有数组相等？

void HexDump(char *buf,int len,int addr) {     int i,j,k;     char binstr[80];      for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%08x -",i+addr);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             printf("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         printf("%s\n",binstr);     } }  电脑内存或文件内容或传输内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容或传输内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……

引用 1 楼 user-2 的回复:直接比较，或逐字节比较(memcpy) 打错了，是memcmp

直接比较，或逐字节比较(memcpy)


Question: grep函数中参数的顺序

用8楼代码。

引用 7 楼 zcmerlin 的回复:[quote=引用 6 楼 wangcg123 的回复:] 你就把代码里使用参数的地方的索引换一下就好了啊 就是argv[2] 和argv[1] 颠倒一下 并不行= =[/quote] 不可能，这么简单一个问题，你逐句调试下，看看argv[1]和argv[2]是什么值，你就明白了

argv[0] 是执行命令， argv[1] ,argv[2].....分别是你执行命令后跟的内容 如果你按这样执行：命令名称 被查找文件 字符串 结果文件          那么argv[1]就是被查找文件，argv[2]是字符串，argv[3]是结果文件； 如果你想按这样执行：命令 字符串 被查找文件  结果文件             那么这时argv[1]的内容就是字符串，argv[2]的内容就是被查找文件，argv[3]就是结果文件（也就是你需要在代码中把相应的argv[1]和argv[2] 换下就行） 注：简单来说就是命令后的第一个内容就是 argv[1],第二个就是argv[2].....以此类推

argv[]数组是你输入的字符串的地址。 比如，你执行时是这样的：./app src.txt  hello dst.txt argv[0]是可执行文件名即./app, argv[1]是源文件，即src.txt argv[2]是要查找的字符串，即hello argv[3]是要拷贝至的文件，即dst.txt; 要想知道每个argv[]是什么，可以通过输出来，以便方便查看。比如以下代码：  #include <stdio.h>  int main(int argc, const char *argv[]) {     int i;      for (i = 0; i < argc; i++)         printf("argv[%d] = %s\n", i, argv[i]);      return 0; }

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <locale.h> int main(int argc,char**argv) {     FILE *fsource, *foutcome;     char buf[1024];     int n;      setlocale(LC_ALL,"chs");     if (argc<4) {         printf("缺少参数\n    参考格式: \"%s\" \"要查找的字符串\" \"被查找文件\" \"结果文件\"\n",argv[0]);         return -1;     }     if ((fsource = fopen(argv[2], "r")) == NULL) {         printf("打开被查找文件 %s 错误原因:%s!\n", argv[2], strerror(errno));         return -1;     }     if ((foutcome = fopen(argv[3], "a+")) == NULL) {         printf("打开结果文件 %s 错误原因:%s!\n", argv[3], strerror(errno));         return -1;     }     n = 0;     while (1) {         if (NULL==fgets(buf, sizeof(buf), fsource)) break;         n++;         if (NULL!=strstr(buf, argv[1])) {              printf(          "Line %5d: %s", n, buf);             fprintf(foutcome, "Line %5d: %s", n, buf);             break;         }     }     fclose(foutcome);     fclose(fsource);     return 0; }

引用 6 楼 wangcg123 的回复:你就把代码里使用参数的地方的索引换一下就好了啊 就是argv[2] 和argv[1] 颠倒一下 并不行= =

引用 3 楼 jianwen0529 的回复:[quote=引用 2 楼 jianwen0529 的回复:]  if((foutcome = fopen(argv[3], "a+")) == NULL) //第三个参数是一个文件路径，追加方式读写         {             printf("打开文件 %s 错误原因:%s!\n", argv[3], strerror(errno));             return -1;         }         if((fsource = fopen(argv[1], "r")) == NULL) //第一个参数是一个文件路径，只读方式。         {             printf("打开文件 %s 错误原因:%s!\n", argv[1], strerror(errno));             return -1;         }     }           /*循环读取文件,直至结尾*/     while(!feof(fsource))     {         fgets(buf, sizeof(buf), fsource);         n++;         pstr = buf;           /*对每行文本进行检索,查找指定字符串*/         while(*pstr != NULL)         {             if(strncmp(pstr, argv[2], sizeof(argv[2])) == 0) //参数2 跟 读取文件的某一行进行比较  参数2说错了，并不是行。[/quote]  代码理解没太大问题  我想问的是执行时，参数的顺序为什么是 ：命令 文件 字符串 文件  如果我想用：命令 字符串 文件 文件   这样的顺序行不行，应该怎么改

引用 1 楼 zhao4zhong1 的回复:http://bbs.csdn.net/topics/390469280 谢谢老师 我还是有点不明白，您帖子里用的就是dos本身的命令，它有固定的顺序 但我的是找代码编译出来的程序，其中参数的顺序难道不应该在代码里有体现吗

引用 2 楼 jianwen0529 的回复:if((foutcome = fopen(argv[3], "a+")) == NULL) //第三个参数是一个文件路径，追加方式读写         {             printf("打开文件 %s 错误原因:%s!\n", argv[3], strerror(errno));             return -1;         }         if((fsource = fopen(argv[1], "r")) == NULL) //第一个参数是一个文件路径，只读方式。         {             printf("打开文件 %s 错误原因:%s!\n", argv[1], strerror(errno));             return -1;         }     }           /*循环读取文件,直至结尾*/     while(!feof(fsource))     {         fgets(buf, sizeof(buf), fsource);         n++;         pstr = buf;           /*对每行文本进行检索,查找指定字符串*/         while(*pstr != NULL)         {             if(strncmp(pstr, argv[2], sizeof(argv[2])) == 0) //参数2 跟 读取文件的某一行进行比较  参数2说错了，并不是行。


Question: PAT乙级--1057. 数零壹(20)

如果sum初始就为0的话，上面的while就不会执行了，下面的do...while会执行一次

不要使用 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;  //... } 类似的例子还可以举很多。

谢谢了


Question: C语言编译后无法导出DLL函数怎么回事？

项目类型错误？

D:\CProject\yjx\test63\edr\Release\edr.lib 明显不是你查看的路径：...\CProject\yjx\test63\edr\edr\Release


Question: 移码在浮点数中是怎么运用的？

引用 5 楼 wenpinglaoyao 的回复:题主，我可以给您一个小工具，使用它您就会明白浮点数的表示原理。  什么工具呢？能够清楚说明问题吗？

引用 6 楼 u014132659 的回复:[quote=引用 5 楼 wenpinglaoyao 的回复:] 题主，我可以给您一个小工具，使用它您就会明白浮点数的表示原理。  什么工具呢？能够清楚说明问题吗？[/quote]  名字叫IEE，比如您输入一个十进制，然后让它帮您转换成二进制，您可以对比看看，看懂很利于您的理解。可以加我QQ

题主，我可以给您一个小工具，使用它您就会明白浮点数的表示原理。

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

原来负位的高位是1,用移码整体往前移一半后，负数高位是0,正数高位是1,这样可以直接比较大小。

一般用做浮点数的阶码，引入的目的是为了保证浮点数的机器零为全0。


Question: strcpy的实现

2.  为什么要单个赋值 如 *strdestination++=*strsouce++ (直接把 strsouce 的值给strdestination :strdestination=strsouce ?) 1）有可能strsource是某个硬件设备的内部空间在DRAM的映射地址，虽然你能够用*strsource来访问，但有可能易变，而如果不copy到真正的strdestination的dram的话，过会儿后，硬件设备的实际strsource就被改变了。所以不同访问时间就会导致数据的未知改动。 2）同样的道理适用于share memory

引用 7 楼 幻夢之葉的回复:[quote=引用 6 楼 software_breeze 的回复:] [quote=引用 4 楼 FD_2013的回复:]这里指针就不能当作字符串值来理解了，这里只是单纯的指针位置偏移，复制一份，ret指向的是字符串首地址，dst后面当作偏移指针来使用，做了++操作，指向的已经不是字符串首地址了 如果直接 dst=src不就可以了吗 为什么还要设置偏移指针？[/quote] 两块不同的内存啊，你直接 dst = src 只是浅拷贝。 也就是说让 dst 指向scr的内存块，当src 被修改或者被销毁的时候，那么你用dst 的时候，轻则数据错误，重则程序崩溃  strcpy做的是深度拷贝，把src的每一个char复制过来[/quote] 我懂了 谢谢

你这样只是多了一个可以访问src的指针，但是没有把src复制到dst的空间里面，没有达到复制的目的！

引用 6 楼 software_breeze 的回复:[quote=引用 4 楼 FD_2013的回复:]这里指针就不能当作字符串值来理解了，这里只是单纯的指针位置偏移，复制一份，ret指向的是字符串首地址，dst后面当作偏移指针来使用，做了++操作，指向的已经不是字符串首地址了 如果直接 dst=src不就可以了吗 为什么还要设置偏移指针？[/quote] 两块不同的内存啊，你直接 dst = src 只是浅拷贝。 也就是说让 dst 指向scr的内存块，当src 被修改或者被销毁的时候，那么你用dst 的时候，轻则数据错误，重则程序崩溃  strcpy做的是深度拷贝，把src的每一个char复制过来

引用 4 楼 FD_2013的回复:这里指针就不能当作字符串值来理解了，这里只是单纯的指针位置偏移，复制一份，ret指向的是字符串首地址，dst后面当作偏移指针来使用，做了++操作，指向的已经不是字符串首地址了 如果直接 dst=src不就可以了吗 为什么还要设置偏移指针？

引用 1 楼 自信男孩的回复:用ret指针保存dst目标串的首地址，因为后面*dst++是地址偏移了，dst就不能指向目标串的首地址了。 *dst++= *src++是字符赋值并且将源串和目标串的地址都自增1，即源串和目标串都指向各自串的下一个字符地址。 *是取值，即去地址指向的内存空间里的字符。 我懂了        谢谢

1.  要返回一个指向目的字符串指针 （不是已经将源字符串保存在 目的字符串里了吗？） 为了支持链式操作。  2.  为什么要单个赋值 如 *strdestination++=*strsouce++ (直接把 strsouce 的值给strdestination :strdestination=strsouce ?) 逐个赋值是深拷贝，直接指针赋值，而且是传值参数赋值，不会有任何效果。  3. 为什么 还要中间定义一个 char* 的变量 来存储strdestination的值？ 因为后面dst变化了，只能在最开始的时候保存下来，以方便返回。

自己读读代码，基础


Question: openssl 关于sm2的添加及证书生成

唉，sm2这个轮子。  github 上有个 https://github.com/guanzhi/GmSSL, 不知道可以不


Question: C语言ACM新手题，求解这个算法有什么没考虑到的地方。

确定，，还没学到哪呢，题目说 Otherwise, even though it may cause some of the next cake to no longer be able to make, she will still make this kind of cake.

你确定这不是最大匹配题么

按顺序检测，不考虑使用某个配方的后果。 同一个配方是指现在检查的配方A所需的所有食材都被某个配方B占用。 同时确保配方A，和配方B的M相同，就能判断是相同配方。

是说最大可行的配方个数？  “检查：一个配方的食材都可用或者都被同一个配方占用了，如果被占用了，两个配方的M相等。两个检查都为真，那么这个配方就可行” 看不懂。什么叫同一个配方？是指配方完全相同？


Question: 关于指针的牛角尖概念问题！

引用 24 楼 zhao4zhong1 的回复:[quote=引用 23 楼 btz201601 的回复:] [quote=引用 22 楼 zhao4zhong1 的回复:] 只能学习计算机组成原理和汇编语言的基本知识，别无它途。  出来混，总是要还的； 缺的课，总是要补的。  可以推荐本计算机组成原理的书吗？最近也在看，不过觉得手上这本不太好[/quote] 先囫囵吞枣不求甚解快速看一遍， 再带着疑问挑重点章节精读＋百度＋上机实际操作，吃透重要的概念。 学生不需要挑教材和老师的错，只要把自己该学的学会就行了。[/quote] 谢谢

引用 23 楼 btz201601 的回复:[quote=引用 22 楼 zhao4zhong1 的回复:] 只能学习计算机组成原理和汇编语言的基本知识，别无它途。  出来混，总是要还的； 缺的课，总是要补的。  可以推荐本计算机组成原理的书吗？最近也在看，不过觉得手上这本不太好[/quote] 先囫囵吞枣不求甚解快速看一遍， 再带着疑问挑重点章节精读＋百度＋上机实际操作，吃透重要的概念。 学生不需要挑教材和老师的错，只要把自己该学的学会就行了。

引用 22 楼 zhao4zhong1 的回复:只能学习计算机组成原理和汇编语言的基本知识，别无它途。  出来混，总是要还的； 缺的课，总是要补的。  可以推荐本计算机组成原理的书吗？最近也在看，不过觉得手上这本不太好

引用 20 楼 zhao4zhong1 的回复:理解和讨论之前请先学会如何观察！ 不懂汇编如何观察？ 只会用vs的F10 F11观察一下变量的值 比如alt+8后      7: 	p = &i; 01204E85 8D 45 EC             lea         eax,[i]   01204E88 89 45 F8             mov         dword ptr [p],eax   没有汇编只是根本不知道这写的是什么啊  alt+5 +6 +7更是不知所云，如何看懂？

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

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

过后再看题目才发现有两个问题  如果将int *看作一个整体，那么int * p,q;的含义实际是声明一个整型指针变量p和整型变量q。（这是否和赋值表达式语句的结合律是从右往左有关系。） 如果将*p看作是一个整体，那么取地址的时候应写成p = &i; 而不是*p = &i;（这也是谭c的解释）  第一句括号中的内容跟前面根本没关系，哪有赋值表达式的事！不知道当时怎么想的，认为是 int = *p,q。 第二句后面写倒了，应该是：那么取地址的时候应写成*p = &i; 而不是p = &i;  学习的过程中，经常纠结于这种概念问题，其实没有必要，问题暂告一段落，看完了《C和指针》再说。

说实话，我都是一行只定义一个变量

按照 C 的语法，一个声明的形式是：   declaration:     declaration-specifiers init-declarator-list(opt) ;  declaration-specifiers:     storage-class-specifier declaration-specifiers(opt)     type-specifier declaration-specifiers(opt)     type-qualifier declaration-specifiers(opt)     function-specifier declaration-specifiers(opt)  init-declarator-list:     init-declarator     init-declarator-list , init-declarator  init-declarator:     declarator     declarator = initializer   简化一下(去掉了不少东西)，就是：  type-specifier declarator, declarator, declarator;  type-specifier 包括： type-specifier: void char short int long float double signed unsigned _Bool _Complex _Imaginary struct-or-union-specifier enum-specifier typedef-name  而 *p[100] 等等的部分都属于 declarator 。  另见：http://en.cppreference.com/w/c/language/declarations

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

p就是一个变量，它的类型是int *;根据变量的类型确定变量在内存里存放什么数据。指针类型在内存中存放的是该类型变量的地址。

参考： 《深入理解C指针》

好吧 我是冲着100分来的。。。  int * p;   C Primer Plus 6th：p是一个指针，*p是int类型 p是一个指针：翻译：p是一个指针变量的变量名，这p这个变量的类型是int * *p是int类型：翻译：对变量p解引用（注意这里的“*”，是解引用运算符，不是指针类型），*p是一个int类型的值  郝斌C教程：p是变量的名字，int * 表示p变量存放的是int类型变量的地址 p是变量的名字：翻译：同上 int * 表示p变量存放的是int类型变量的地址：翻译：p这个变量里面存的值，是一个int类型变量的地址  谭浩强：指针变量前面的"*"表示该变量的类型为指针型变量。指针变量名是p，而不是*p。 指针变量前面的"*"表示该变量的类型为指针型变量：翻译：这句话有前提，在变量声明时，"*"表示变量是一个指针类型的变量 指针变量名是p，而不是*p：翻译：同上

作为一个错误的典型，9楼不是一般的成功！

引用 13 楼 SK_AJIE 的回复:9楼亮了 关键还用这么激萌的头像。

9楼亮了

哇，机器人具备 lexer 能力了

作为一个错误的典型，9楼很成功。


Question: APUE里面第10章，关于信号的这段代码不理解。请指教

楼主，我也想学，这本书和The Linux Programming Interface哪本好啊

As shown by this example, if we call a nonreentrant function from a signal handler, the results are unpredictable. 书上说是结果是不可预知的。因为getpwnam返回了静态区的数据，是个不可重入的函数。  我试了下，就输出了一句in signal handler,然后就卡住了

引用 4 楼 chenzhp 的回复:[quote=引用 3 楼 user-3 的回复:] 第１个问题：　1楼已经回答了， 是通过strerror(errno)得到的 第２个问题：　因为err_sys中调用了exit所以返回了  谢谢回复。 但是我想知道一点，当主函数里面调用signal函数，处理信号，这个我自己定义的信号函数里面 static void my_alarm(int signo) {     struct passwd *rootptr;     printf("IN signal handler\n");       if((rootptr = getpwnam("root")) == NULL)         err_sys("getpwnam(root) error");     alarm(1); }   有一句，printf  in signal handler，但是在调用的时候，屏幕无输出。按理说必须进这里面来啊。[/quote] 先进入主函数中的for,由于用户名找不到，所以退出了。把两处"sar"换成你的用户名就可以了

引用 3 楼 user-3 的回复:第１个问题：　1楼已经回答了， 是通过strerror(errno)得到的 第２个问题：　因为err_sys中调用了exit所以返回了  谢谢回复。 但是我想知道一点，当主函数里面调用signal函数，处理信号，这个我自己定义的信号函数里面 static void my_alarm(int signo) {     struct passwd *rootptr;     printf("IN signal handler\n");       if((rootptr = getpwnam("root")) == NULL)         err_sys("getpwnam(root) error");     alarm(1); }   有一句，printf  in signal handler，但是在调用的时候，屏幕无输出。按理说必须进这里面来啊。


Question: 读写文件的bug?

#include<stdio.h> int main() { 	FILE *fp; 	fopen("D:\新建文件夹\Dec\1.txt", "r"); 	if (fp == NULL) 		return -1; 	else 		printf("file open success!");	 	fclose(fp); 	return 0;   } 我发现刚开始这段就有问题，路径没问题的话，段错误吗

谢谢回复！关于return的返回值的问题已经改过来了，程序能够运行出结果，但是会报错。

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

#include <stdio.h> #include<stdlib.h> #include<string.h> #define N 10  typedef struct {     int **p;     int row;     int col; }Matrix;  int input_mat(FILE *fp, Matrix *mat);            //输入矩阵 int get_row_col(FILE *fp, Matrix *mat, int len); //获取多个矩阵各自的行数、列数 void delete_mat(Matrix *mat, int mat_number);       //释放给矩阵分配的空间 Matrix get_product(Matrix *mat, int mat_num); Matrix get_product_2(Matrix mat1, Matrix mat2); void fopen_s(FILE **fp, const char *filename, const char *openmode);  int main() {     FILE *fp; //打开文件     fopen_s(&fp, "1.txt", "r");     if (fp == NULL)         return -1;     Matrix mat[N];    // 定义一个一维的结构数组     int mat_number;     mat_number = input_mat(fp, mat);     printf("%d", mat_number);     Matrix product = get_product(mat, mat_number);     delete_mat(mat, mat_number);     delete_mat(&product, 0);     //关闭文件     fclose(fp);     return 0; }  int input_mat(FILE *fp, Matrix *mat) {     int mat_number = get_row_col(fp, mat, N);     rewind(fp);     for (int i = 0; i <= mat_number; ++i)     {         mat[i].p = (int **)malloc(sizeof(int *) * mat[i].row);    //分配内存         for (int j = 0; j < mat[i].row; ++j)         {             mat[i].p[j] = (int *)malloc(sizeof(int) * mat[i].col);             for (int k = 0; k < mat[i].col; ++k)             {                 fscanf_s(fp, "%d", &(mat[i].p[j][k]));             }         }     }     return mat_number; } int get_row_col(FILE *fp, Matrix *mat, int len) {     for (int i = 0; i < len; ++i) //初始化？     {         mat[i].col = 0;         mat[i].row = 0;     }     int ch;     int state_row = 0;     int state_col = 0;     int index_arr = 0;     while ((ch = fgetc(fp)) != EOF)     {         if (ch != '\n' && ch != ' ' && state_col == 0)         {             ++mat[index_arr].col;         }         else if (ch != '\n' && ch != ' ' && state_col == 1)         {             state_row = 0;         }         else if (ch == '\n' && state_row == 0)         {             state_row = 1;             state_col = 1;             ++mat[index_arr].row;         }         else if (ch == '\n' && state_row == 1)         {             state_row = 0;             state_col = 0;             ++index_arr;         }     }      return index_arr;    /*return index_arr应该放在while外面，不然index_arr应该只会为1或者为0*/ } Matrix get_product(Matrix *mat, int mat_number) {     Matrix product = mat[0];     for (int i = 1; i <= mat_number; ++i)     {         product = get_product_2(product, mat[i]);     }     int i, j;     FILE *fp1;     fopen_s(&fp1, "H:\\2.txt", "w");     if (fp1 == NULL)         exit(0);     else         for (i = 0; i < product.row; i++)         {             for (j = 0; j < product.col; j++)             {                 fprintf(fp1, "%d", product.p[i][j]);             }             printf("\n");         }     fclose(fp1);     return product; }  Matrix get_product_2(Matrix mat1, Matrix mat2) {     Matrix product;     product.col = mat1.col;     product.row = mat2.row;      product.p = (int **)malloc(sizeof(int *) * product.row);     for (int i = 0; i < product.col; ++i)     {         product.p[i] = (int *)malloc(sizeof(int) * product.col);     }     for (int i = 0; i < product.row; ++i)     {         for (int j = 0; j < product.col; ++j)         {             product.p[i][j] = 0;             for (int k = 0; k < mat1.row; ++k)             {                 product.p[i][j] += mat1.p[i][k] * mat2.p[k][j];             }         }     }      return product; } void delete_mat(Matrix *mat, int mat_number)  //？ {     for (int i = 0; i <= mat_number; ++i)     {         for (int j = 0; j < mat[i].row; ++j)         {             free(mat[i].p[j]);             mat[i].p[j] = NULL;         }         free(mat[i].p);         mat[i].p = NULL;     } }  注意看一下get_row_col()函数，里面返回值是否有问题。

请问这个小程序问题出在哪里啊


Question: 大神帮帮忙，大一的程序设计作业

程序给你改了改，我是在Linux修改和编译的，目前没有语法错误； 编程不得发进步很慢。你的程序有那么多语法错误，自己得慢慢解决呀，不然怎么进步呢 有问题再沟通吧；将你的邮箱通过私信发给我，我给你发过去。

卧槽发错了尴尬。。http://pan.baidu.com/s/1qYauqHe


Question: 浮点数精度为什么有6位，也有7位

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

4位二进制和1位16进制 8位二进制和2位16进制 是完全对等的

引用 1 楼 akirya 的回复:那么4位二进制表示十进制中的1位 这个是错的啊 十进制二进制转换不是这么转的  请说明一下，谢谢

23 * log(2) / log(10)    大约 6.9 位精度,  考虑到中间过程会损失一部分精度,  算 6位精度比较合适.

那么4位二进制表示十进制中的1位 这个是错的啊 十进制二进制转换不是这么转的


Question: gcc编译共享库怎么不报错啊

引用 10 楼 imarshal 的回复:[quote=引用 9 楼 ipqtjmqj 的回复:] 你具体用了math.h中的哪个函数，传的给那个函数的参数是常数还是变量。  就是sin和cos，gcc好像是这样处理共享库[/quote]  关键是传的是常数还是变量，如果是常数，可能不需要动态库了

引用 9 楼 ipqtjmqj 的回复:你具体用了math.h中的哪个函数，传的给那个函数的参数是常数还是变量。  就是sin和cos，gcc好像是这样处理共享库

你具体用了math.h中的哪个函数，传的给那个函数的参数是常数还是变量。

引用 5 楼 cfjtaishan 的回复:编译时加-Wall试试，加不加-lm提示有没有错误，主要还要看程序里有没有使用数学函数库  不提示错误的

引用 4 楼 mLee79 的回复:加链接选项   -Wl,--no-undefined  不提示错误的

引用 3 楼 imarshal 的回复:现在是用ldd -r手动查看共享库，可以显示缺少的库，有没有其他方法啊，还是不知道gcc为什么不报错 多使用ldd才是正道。

加链接选项   -Wl,--no-undefined

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

引用 14 楼 mLee79 的回复:前后应该无所谓..  -Wl 是传递给 ld 的参数, 你也可以用  ld  --no-undefined -shared -o 1.so 1.o  链接, 就不需要 -Wl 的前缀.  一般主流的是放哪啊

引用 12 楼 mLee79 的回复:在生产 .so 的时候用, 怎么可能没用  function run { echo $*; $*; }; run cat 1.c; run gcc -fPIC -c -o 1.o 1.c; run gcc -shared -o 1.so 1.o; run gcc -shared -o 1.so 1.o  -Wl,--no-undefined cat 1.c #include <math.h>  double foobar(double x) {    return sin(x); }  gcc -fPIC -c -o 1.o 1.c gcc -shared -o 1.so 1.o gcc -shared -o 1.so 1.o -Wl,--no-undefined 1.o: In function `foobar': 1.c:(.text+0x1b): undefined reference to `sin' collect2: error: ld returned 1 exit status  哦，原来是lmn的l，我以为是IJK的I，多谢了，还有这个选项一般是写在gcc后面还是最后啊

引用 1 楼 user-5 的回复:那就静态库喽  gcc为什么不报错啊，有没有选项能让gcc报错或者警告，还是说共享库都是这样的，缺少的库让最后的可执行一起添加，不过还是感觉逻辑有问题

那就静态库喽


Question: gcc自带函数是什么意思，函数名冲突怎么解决啊

gcc a.c -o a.out -fno-builtin

引用 1 楼 user-1 的回复:自带函数冲突是什么，原文就是这么说的？  应该是你的conj这个函数的参数类型 不匹配吧  conj是我自己定义的，gcc编译报warning: conflicting types for built-in function 'conj'，我搜了下，gcc确实有这个内置函数，怎么把这个警告去掉啊，总不会要我改自己的函数名啊