Question: Windows的shell到底是个啥？

win+R 输入cmd 回车

引用 24 楼 六道佩恩 的回复:[quote=引用 23 楼 早打大打打核战争 的回复:] shell是操作系统提供给用户直接使用操作系统功能而不需要编程(也可以支持简单编程，比如批处理、cshell之类的)的若干程序，可以是命令行接口，比如Dos的command.com、Windows的cmd.exe也可以是GUI，比如Windows的explorer.exe。shell也是调用操作系统API实现功能的，广义来说可以归入应用程序一类 对于Windows的explorer.exe这种，是通过函数接口调用的（通用对话框函数？），还是说通过解释器做的进程通信？[/quote]  主要是COM接口

引用 23 楼 早打大打打核战争 的回复:shell是操作系统提供给用户直接使用操作系统功能而不需要编程(也可以支持简单编程，比如批处理、cshell之类的)的若干程序，可以是命令行接口，比如Dos的command.com、Windows的cmd.exe也可以是GUI，比如Windows的explorer.exe。shell也是调用操作系统API实现功能的，广义来说可以归入应用程序一类 对于Windows的explorer.exe这种，是通过函数接口调用的（通用对话框函数？），还是说通过解释器做的进程通信？

解释器是指命令识别或者指令识别吧？界面的概念要复杂许多。

引用 20 楼 luj_1768 的回复:shell 是用户调用系统功能和应用程序的接口。其调用权限的配设方案，是其核心设计。在界面下可以使用什么级别的功能，功能的控制方案和性能指标、以及可以占用的系统资源都由此决定。windows 的权限配设方案很复杂。但是，图形界面和命令行界面肯定使用的是完全不同的两套方案。 命令行应该是指解释器的方案吧？  图形界面的话，应该也可以用解释器吧，解释器只需要和对应功能的进程通信就可以了（可行否？）  这么看，光解释器这一种设计也都可以实现呀

https://baike.baidu.com/item/shell/99702 感觉是个解释器

引用 17 楼 丁劲犇 的回复:shell 我理解是指一个交互的方式，即通过ASCII的指令交互的方式。记得以前看到一个德国的车床，上面把telnet登录上去维护设备的那个小接口也叫做shell，里面支持ftp上传固件等几个很有限的命令。另外，玩过通信芯片的，估计都记得通过串口9600波特登上去写AT指令的那个界面，也是shell。  所以，shell 字面上就是外壳，在核心功能的外面包着shell，为了和外部的人交互。广义上，现代SOC都用网页了，那也是个shell，只是图形化了。 但是“外壳”的解释太宽泛了，我只是想知道它是 解释器 还是 解释器+函数接口 ，通过你的描述我分辨不出来，感觉那个小接口可以调用一个函数（函数接口），也可以去加载一个程序来运行（解释器），后面那个AT指令，一看就是解释器吧

windows是消息驱动学系统，除了硬件中断，并没有去监听什么

引用 14 楼 luj_1768 的回复:windows 的命令行界面好像和图形界面是两个不同的系统，二者的运行权限方案是不同的。其他的区别不算重要，大多与兼容有关。  那么哪个才是windows的shell？还是说windows的shell在命令行和图形界面中各占一部分？在命令行中的话，shell应该是指解释器对吧？那么在图形界面中，是一套函数接口吗？

引用 10 楼 早打大打打核战争 的回复:shell可以是命令行接口，也可以是GUI的 “可以是GUI”这句话的意思是？是指调用GUI程序，还是提供GUI的中转接口？  既然windows的shell也是解释器，那么运行的对象也都是可执行程序对吧？那么WH_SHELL钩子所监视的什么？所有程序的启动、退出以及关键事件？  MSDN的windows shell那个我早就看了，但实在没搞懂他讲的是啥，而看WH_SHELL钩子的描述我也不确定它到底针对的是什么，监视的是什么消息，所以它监视的对象是我上一段所说的吗？

引用 12 楼 六道佩恩 的回复:“可以是GUI”这句话的意思是？是指调用GUI程序，还是提供GUI的中转接口？  既然windows的shell也是解释器，那么运行的对象也都是可执行程序对吧？那么WH_SHELL钩子所监视的什么？所有程序的启动、退出以及关键事件？  MSDN的windows shell那个我早就看了，但实在没搞懂他讲的是啥，而看WH_SHELL钩子的描述我也不确定它到底针对的是什么，监视的是什么消息，所以它监视的对象是我上一段所说的吗？ WH_SHELL钩子时监是SHELL的消息  WH_SHELL Installs a hook procedure that receives notifications useful to shell applications. For more information, see the ShellProc hook procedure.  ShellProc The ShellProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The function receives notifications of Shell events from the system.  有5种情况就触发SHELL消息 1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁； 2. 当Taskbar需要重画某个按钮； 3. 当系统需要显示关于Taskbar的一个程序的最小化形式； 4. 当目前的键盘布局状态改变； 5. 当使用者按Ctrl+Esc去执行Task Manager（或相同级别的程序）  不知道你所说的监视对象是指什么？

shell可以理解为一个控制台(终端)。 玩黑时，就是拿shell.拿站就是拿webshell. webshell往往是低级权限，还要提权。拿system

shell可以是命令行接口，也可以是GUI的

引用 8 楼 千梦一生 的回复:所以，shell，约等于接口？ 或者就是？

所以，shell，约等于接口？

简单说是 包装一个系统, 包装后肯定需要提供接口让用户控制, windows是图形化, 所以多数控制是鼠标多, 键盘少  这个包装可以说是一个shell, 翻译可能为"外壳", windows的shell偏向图形化,  linux的shell偏向命令方式 windows的cmd也是命令方式, 可以说是一个命令方式的shell, cmd有很多内置命令, 也有很多命令是通过调用exe实现


Question: 输出结果少好多数据怎么改正呀？

for(;j<len2-1;j++)  if(flag=0) 这两处  #include<stdio.h> #include<string.h> int main(){ 	char str1[80],str2[80]; 	gets(str1); 	gets(str2); 	int len1,len2; 	len1=strlen(str1); 	len2=strlen(str2); 	if(len1<len2){ 	    printf("no reason\n"); 	} 	int i,j=0,k=0,flag=0; 	for(i=0;i<len1-1;i++){ 		for(j = 0;j<len2-1;j++){ 			if(str1[i]==str2[j]){ 				k++; 			}	 		} 		if(k==len2-1){ 			printf("%d ",i-len2+2); 			k=0; 			flag=1; 		} 	} 	if(flag==0){ 		printf("no\n"); 	} 	return 0; }


Question: HELP：关于使用函数 gets_s 的问题

引用 1 楼 user-1 的回复:在编译选项里面配置c11支持 理论上是这样，设置了“ -std=c11”，但无效。

在编译选项里面配置c11支持


Question: 一个程序里面可以用两次begin....goto语句吗？

那请问还有其他办法返回上一步吗?

不能写两个begin: 吧？ 写一个试试

状态机咯，goto不友好

在同一个函数总，语句的标号要唯一，不能重复。这是基本的语法规定。

scanf("%d",&x);         while(x>3 || x < 1)         {                   printf("违反规则，请重新输入：");                  scanf("%d",&x);          }


Question: 求助！输出结果总是多一些莫名其妙的东西，不知道怎么改正

引用 4 楼 m0_46659544 的回复:[quote=引用 3 楼 baidu_28726667 的回复:] char s[100] ={0}；  or  memset(s,0x00,sizeof(s));还是不太对啊？ [/quote]  你for循环往前移动字符的时候，并没有解决原来的字符问题。你移动了两次。包括原来最后的r. 所以最后一共打印了3个r

引用 3 楼 baidu_28726667 的回复:char s[100] ={0}；  or  memset(s,0x00,sizeof(s));还是不太对啊？

引用 1 楼 user-2 的回复:删除完之后，在新的字符串末尾加个'\0' void delchar(char s[],char c){ 	int len,i,j; 	len = strlen(s); 	for(i=0;i<len;i++){ 		if(s[i]==c){ 			for(j=i;j<len-1;j++){ 				s[j]=s[j+1]; 			} 		} 	} 	len = strlen(s); 	s[len-1]='\0';  } 改成这样还是不对哎

删除完之后，在新的字符串末尾加个'\0'

#include<stdio.h> #include<string.h> #include <Windows.h> void delchar(char s[], char c) { 	int seek = 0; 	int len, i, j; 	len = strlen(s); 	for (i = 0; i<len; i++) { 		if (s[i] == c) { 			for (j = i; j<len - 1; j++) { 				s[j] = s[j + 1]; 			 			} 			seek++; 		} 	}  	s[len - seek] ='\0'; } int main() { 	char s[100] = "hapay new aear"; 	char c;  	scanf("%c", &c); 	delchar(s, c); 	printf("%s\n", s); 	system("pause"); 	return 0; }    记录次数，最后补个'\0'截断它


Question: 请问 easylogger这个库能把日志只打印到 文件上吗？(不想在屏幕显示)

TypedConfigurations::toStandardOutput

在官方自带的elog_port.c文件中将printf屏蔽掉后，就可以打印在文件中不在屏幕上显示了。

请问您是怎么讲日志打印到文件上的，我的只能在屏幕实时打印，谢谢！


Question: 新手求帮忙，大哥看看这个问题怎么解决

case 必须是常量

改一下试试  int x = x1>x2?x1:x2

引用 3 楼 user-3 的回复:switch结合三目运算，如果x1>x2就返回1，x1<x2就返回-1，x1==x2就会返回0  switch(x1>x2 ? 1 : (x2>x1 ? -1 : 0)) {     case -1:         printf("B方案更优");         break;     case 1:         printf("A方案更优");         break;     default:         printf("两种方案相同");         break;     } 好的，谢谢哥。做出来了，万分感谢

引用 1 楼 5250 的回复:改一下试试  int x = x1>x2?x1:x2 行

好的，谢谢哥


Question: 动态分配出错

引用 1 楼 user-1的回复:gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。 if(t=(char*)malloc(sizeof(char))==NULL) 这一句看上去只分配了一个字符的空间 那要这么改？

不用maolloc直接定义个字符数组


Question: 关于DEBUGHOOKINFO结构体的问题（DEBUG HOOK的结构体）

引用 8 楼 六道佩恩 的回复:[quote=引用 6 楼 zgl7903 的回复:] id 说明了就是线程ID 句柄的话一般不会用指针类型， 尽可能兼容64位系统 这些头文件里句柄的原型不就是指针吗？  如果是线程ID的话，那么就是MSDN的说明错了，是吧？[/quote]  抱歉， 误写, 本来是想说句柄不会用DWORD，用指针，尽可能兼容64为系统

引用 3 楼 user-3 的回复:按句柄的本质来看，应是8字节的指针 这个理解明显错误, 你可以尝试CreateFile, OpenProcess,等打开一个句柄, 然后看这个实际值是多少  句柄的本质就是指针啊，这是几个头文件中对句柄的定义： ntdef.h:  typedef void *HANDLE; ntdef.h:  typedef PVOID HANDLE; winnt.h:  typedef void *HANDLE; winnt.h:  typedef PVOID HANDLE; wtypesbase.h:  typedef void *HANDLE;  你不能根据它值的大小来说事啊，你对变量取地址得到的值一般也不到4字节上限，但显然不能因为它的值总是在4字节以内而拿4字节整型来存储吧？

id 说明了就是线程ID 句柄的话一般不会用指针类型， 尽可能兼容64位系统

引用 4 楼 六道佩恩 的回复:[quote=引用 3 楼 user-3 的回复:] 按句柄的本质来看，应是8字节的指针 这个理解明显错误, 你可以尝试CreateFile, OpenProcess,等打开一个句柄, 然后看这个实际值是多少  句柄的本质就是指针啊，这是几个头文件中对句柄的定义： ntdef.h:  typedef void *HANDLE; ntdef.h:  typedef PVOID HANDLE; winnt.h:  typedef void *HANDLE; winnt.h:  typedef PVOID HANDLE; wtypesbase.h:  typedef void *HANDLE;  你不能根据它值的大小来说事啊，你对变量取地址得到的值一般也不到4字节上限，但显然不能因为它的值总是在4字节以内而拿4字节整型来存储吧？[/quote] 要学习内核知道，要学会用windbg,OD等调试工具而不是强行理解，强行解释。

引用 7 楼 六道佩恩 的回复:[quote=引用 5 楼 gouyanfen 的回复:] 要学习内核知道，要学会用windbg,OD等调试工具而不是强行理解，强行解释。 您能给出解答吗？[/quote] 怎么还在这里如果呢，你弄个双机调试，去调试一下，看看他指向的东西具体是句柄还是id。我给你解释不了这个，我也没用到这个结构。

引用 6 楼 zgl7903 的回复:id 说明了就是线程ID 句柄的话一般不会用指针类型， 尽可能兼容64位系统 这些头文件里句柄的原型不就是指针吗？  如果是线程ID的话，那么就是MSDN的说明错了，是吧？

引用 5 楼 gouyanfen 的回复:要学习内核知道，要学会用windbg,OD等调试工具而不是强行理解，强行解释。 您能给出解答吗？

引用 1 楼 user-3 的回复:变量命名每个人习惯不一样, msdn也是人写的, 应该以说明为准 对于DWORD，HANDLE, 在内核来说都是一样的东西, 很多系统底层的东西都是这样  你的意思应该认为是句柄？ 按句柄的本质来看，应是8字节的指针，而DWORD只有4字节，怎么也不可能是句柄吧，既然是人写的，我是认为他们写错了


Question: 没搞懂为什么会这样

数组崩溃，一般是下标越界了

数组越界，sizeof了指针，你可以用strncpy或者其他的，做好越界保护处理机制

引用 3 楼 Simple-Soft 的回复：数组崩溃，一般是下标越界了我debug的时候是realloc出的问题，所以我一直没想明白为什么

引用 2 楼 chxchxkkk 的回复：我觉得传入的是 input数组的地址，sizeof(input)并不能得到数组的大小，只得到了指针的大小跟sizeof没啥关系

引用 1 楼 focuslight 的回复：能查一下调用堆栈吗？ 或者你搜一下串里有几个分隔符， 一次性分配splitstruct->str的空间，别重新申请了因为每次输入不一样所以不能一次分配，我也没想太明白为什么会core dump


Question: 各位大神，能不能帮忙看看，为啥数组读不进去啊

论坛有帖代码的工具不用，你总要给人一个好的阅读感。

这个排版感人完全没法看

确实有点感人


Question: C语言scanf

你牛逼，自己为难自己

scanf("a=%d,b=%d",&a,&b);留下了一个'\n' 由于scanf("%f,%e",&x,&y);只读取浮点数忽略了'\n',同时该语句剩余一个'\n'没读 scanf("%c%c%c",&c1,&c1,&c2);读取了'\n'赋值给c1,接下来应该输入 c1和c2的值,所以该语句读取的仍然是两个字符,赋值给c1和c2

因为'\n'正好和第一个%c匹配

删掉一个不就行了

可以不用输入二次呀，修改一下就ok


Question: 初学，求指点一下，为什么我的循环走歪路啊

scanf遇到非整数就停止了，因此输入15.5，num读到15，n为1；缓冲区里还剩下.5，再执行scanf读小数点发生错误，n为0，程序结束。

初学，但是通过多运行几个，各种尝试性输入，证明你这种解释是合理的。


Question: 关于多文件之间的问题 初学者

引用 1 楼 user-1 的回复:最好不要用#include cpp的方式来使用，把函数的什么和实现分块，.h文件中进行函数什么，在cpp中实现，使用的时候保护h文件就可以。请问能详细一点讲一下吗，我不是很懂，谢谢！


Question: C语言编写函数做矩阵算法之后，无法输出全部答案？

我觉得b[]在子函数结束后就被释放了，传出来的指针指向的数组也不存在了

函数的返回值是int。是一个整数。


Question: 请教大佬

1.定义一个判断最小公倍数的函数 2.循环从90~99，判断n和其中数的最小公倍数 3.定义2个变量，一个保存当前数，一个保存当前数的最小公倍数 4.如果循环的最小公倍数比3中最小公倍数大，更新3中的2个变量。 5.循环结束后，输出3中个变量  就是你要的结果


Question: 请教大佬

引用 2 楼 弦之弈的回复:先写一个函数判断是不是素数 int judge_prime(int num) {  for()  //2到num-1  {   能否整除   if(能) break; return 0;  }  return 1; }  int judge = judge_prime(num) if(judge==) sum = sum+num*num; 大概是这样，放在循环里面就可以 感谢大佬呀！

把代码发出来看看哪儿不对


Question: 萌新求解

// 单词加密：使用指针方式，将任意单词的第一个字母移到该单词的末尾，再加上"ay"。 #include <stdio.h> #include <stdio.h>  int main() { 	char first_c, str[100], *p; 	scanf("%s", str); 	p = str; 	first_c = *p++;			//保存第一个字符  	for ( ; *p!='\0'; p++ ) 	{	*(p-1) = *p;		 	} 	*(p-1) = first_c;		//将第一个字符移到最后  	strcpy(p, "ay");		//拼接后缀ay  	printf("%s", str); 	return 0; }


Question: 为什么C语言编的程序无缘无故就自己结束呢？

引用 9 楼 chenqiqideshanzi 的回复:我现在再反馈给大家一下吧，现在我已经把中文逗号改掉了，也把%c改成%d了，最后我也每次使用完scanf都及时清空输入缓存： scanf("%*[^\n]"); scanf("%*c");  但是现在情况是在输入顶点序号后，停顿一两秒，它就自动结束了。   scanf("%c",G.vexs[i]); 第60行的代码为什么不加&   其他的地方都加了 是瞧不起这个函数嘛

谢谢大家对我的指正，我的程序已经可以运行了！

你输得是中文逗号

谢谢大家给我的指导，我现在就去试一试！

scanf是从输入缓存中读取指定类型的输入数据，保存到你的目标地址当中，你在读完两个int之后，缓存里面还残存着许多垃圾数据，比如输完数据点的回车(也就是'\n'字符)，你后面再来一堆scanf("%c", &xxx)读取的都是之前输入缓存中剩下的垃圾数据  每次使用完scanf都应该及时清空输入缓存： scanf("%*[^\n]"); // 读走输入缓存中'\n'前的所有字符 scanf("%*c"); // 读走输入最后剩下的字符(通常是'\n')  在输入多个int类型数据的时候，应当避免使用逗号进行间隔 应当尽可能避免在一个scanf中读取多个数据 应当竟可能避免使用scanf("%c", &xxx)

Status CreateUDN(MGraph G) {     VertexType v1, v2;     int w, i, j, k;     int a[3];     printf("请输入无向网G的顶点数，弧数，并用逗号隔开\n");     scanf("%d,%d", &G.vexnum, &G.arcnum);     printf("请依次输入无向网G的顶点名称，用空格隔开\n");  //getchar();    读入一个字符想干嘛 删掉     for (i = 0; i < G.vexnum; ++i)     {   scanf("%d", &G.vexs[i]);     //输入的是整形     }     for (i = 0; i < G.vexnum; ++i)     {         for (j = 0; j < G.vexnum; ++j)         {             G.arcs[i][j].adj = INFINITY;         }     }

引用 3 楼 user-4 的回复:把scanf(“%c”, G.vexs[i]) 改成scanf(“%d”, &G.vexs[i])  注意类型是vexs的类型是int，而且scanf的参数是&G.vexs[i]（地址形式） 这个也改了，但是没什么影响，之前存在的代码跳过的问题现在还是有

引用 1 楼 user-4 的回复:你的输入值里是不是用了中文的逗号了？你在输入完顶点数后打印一下G.vexnum看看，是不是和输入值一样 试过了，打印的G.vexnum和输入值一样，现在的问题就是在输入完顶点名称之后，敲击回车，过一两秒就直接结束了，中间那些代码都不运行了，不知道咋回事


Question: 统计二叉树的叶结点个数并判断两棵树是否相等

void  InOrderTraverse(BiTree T)  //输出中序遍历结果 {    if(T)      {  InOrderTraverse(T->lchild);           printf("%c",T->data);                   InOrderTraverse(T->rchild);      } } 这是中序遍历的算法，逐个计数/比较即可

可以采用中序遍历的思想，用递归实现。


Question: 问题求助

引用 1 楼 user-1 的回复:#include <stdio.h>  int main ( ) {       unsigned char  ch,  n=0;    while((ch = getchar()) != '\r')  {     if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))    {         n++;    }  }     printf("n=%d\n",  n);      return  0;  } /************************************************************************************/ #include <stdio.h>  int main ( )  {   unsigned char  ch,  n=0;      for( ch=getchar();  ch != '\r';  ch = ch )      {          if((ch >= 65 && ch <= 90) || ch>=97 && ch<=122 )   n++;      }      printf("n=%d\n",  n);      return  0;  }  回车好像是'\n’，把'\r'替换成'\n’


Question: 一个问题，请大佬们帮忙看下

楼上的正解，写代码要仔细。你这题就出现在仔细不仔细上。

char name;只能装一个字符（没法存字符串，也就是多个字符），且是个字符变量（在读取指针的地方会出现问题），按照楼上的方法改应该是对的

吧char name定义成char name[20]


Question: 结构体-不进入写好的排序算法。

引用 7 楼 火花20180731 的回复:请参考以下排序算法代码：  /* 冒泡排序 */ void bubble_sort(int *data, int size) {     int i;     for (i = 0; i < size - 1; ++i)     {         int ordered = 1;         int j;         for (j = 0; j < size - 1 - i;++j)         {             if (data[j+1] < data[j])             {                 int swap = data[j];                 data[j] = data[j+1];                 data[j+1] = swap;                 ordered = 0;             }         }         if (ordered)         {             break;         }     } } /* 插入排序 */ void insert_sort(int* data, int size) {     int i;     for (i = 1; i < size; ++i)     {         int inserted = data[i];         int j;         for (j = i; (j > 0) && (inserted < data[j-1]); --j)         {             data[j] = data[j-1];         }         if (j != i)         {             data[j] = inserted;         }     } } /* 选择排序 */ void select_sort(int* data, int size) {     int i;     for (i = 0; i < size - 1; ++i)      {         int min = i, j;         for (j = i + 1; j < size; ++j)         {             if (data[j] < data[min])             {                 min = j;             }         }         if (min != i)         {             int swap = data[i];             data[i] = data[min];             data[min] = swap;         }     } } /* 快速排序 */ void quick_sort(int* data, int left, int right) {     int p = (left + right) / 2;     int pivot = data[p];     int i = left, j = right;     while (i < j)     {         for (; ! (i >= p || pivot <data[i]); ++i);         if (i < p)         {             data[p] = data[i];             p = i;         }         for (; ! (j <= p || data[j]< pivot); --j);         if (j > p)         {             data[p] = data[j];             p = j;         }     }     data[p] = pivot;     if (p - left > 1)     {         quick_sort (data, left, p - 1);     }     if (right - p > 1)     {         quick_sort (data, p + 1, right);     } }根据您所提供的算法，我作了如下修改，可还是不能 排序 double computerAvg(struct student stu, int n) {     int i;     double sum = 0.0;     for (i = 0; i < n; i++)     {         sum += stu.sc[i].score;              }     return sum / n; } double maxavg(struct student *stu)  /* 找最大的平均分 */ {     struct student temp;     int index;     int i=0,j;     stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */     for (i = 0; i < 8; i++) //冒泡排序算法 	{         index=i; 		for (j = i+1; j < 9; j++) 		{              			if (stu[j].cavg>stu[index].cavg) 			{ 				index=j; 			} 		}         temp=stu[index];         stu[index]=stu[i];         stu[i]=temp; 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); } void printinfos(struct student stu) {     printf("sno:%s", stu.sno);     printf("name:%s", stu.name); } 引用 7 楼 火花20180731 的回复:请参考以下排序算法代码：  /* 冒泡排序 */ void bubble_sort(int *data, int size) {     int i;     for (i = 0; i < size - 1; ++i)     {         int ordered = 1;         int j;         for (j = 0; j < size - 1 - i;++j)         {             if (data[j+1] < data[j])             {                 int swap = data[j];                 data[j] = data[j+1];                 data[j+1] = swap;                 ordered = 0;             }         }         if (ordered)         {             break;         }     } } /* 插入排序 */ void insert_sort(int* data, int size) {     int i;     for (i = 1; i < size; ++i)     {         int inserted = data[i];         int j;         for (j = i; (j > 0) && (inserted < data[j-1]); --j)         {             data[j] = data[j-1];         }         if (j != i)         {             data[j] = inserted;         }     } } /* 选择排序 */ void select_sort(int* data, int size) {     int i;     for (i = 0; i < size - 1; ++i)      {         int min = i, j;         for (j = i + 1; j < size; ++j)         {             if (data[j] < data[min])             {                 min = j;             }         }         if (min != i)         {             int swap = data[i];             data[i] = data[min];             data[min] = swap;         }     } } /* 快速排序 */ void quick_sort(int* data, int left, int right) {     int p = (left + right) / 2;     int pivot = data[p];     int i = left, j = right;     while (i < j)     {         for (; ! (i >= p || pivot <data[i]); ++i);         if (i < p)         {             data[p] = data[i];             p = i;         }         for (; ! (j <= p || data[j]< pivot); --j);         if (j > p)         {             data[p] = data[j];             p = j;         }     }     data[p] = pivot;     if (p - left > 1)     {         quick_sort (data, left, p - 1);     }     if (right - p > 1)     {         quick_sort (data, p + 1, right);     } } 引用 7 楼 火花20180731 的回复:请参考以下排序算法代码：  /* 冒泡排序 */ void bubble_sort(int *data, int size) {     int i;     for (i = 0; i < size - 1; ++i)     {         int ordered = 1;         int j;         for (j = 0; j < size - 1 - i;++j)         {             if (data[j+1] < data[j])             {                 int swap = data[j];                 data[j] = data[j+1];                 data[j+1] = swap;                 ordered = 0;             }         }         if (ordered)         {             break;         }     } } /* 插入排序 */ void insert_sort(int* data, int size) {     int i;     for (i = 1; i < size; ++i)     {         int inserted = data[i];         int j;         for (j = i; (j > 0) && (inserted < data[j-1]); --j)         {             data[j] = data[j-1];         }         if (j != i)         {             data[j] = inserted;         }     } } /* 选择排序 */ void select_sort(int* data, int size) {     int i;     for (i = 0; i < size - 1; ++i)      {         int min = i, j;         for (j = i + 1; j < size; ++j)         {             if (data[j] < data[min])             {                 min = j;             }         }         if (min != i)         {             int swap = data[i];             data[i] = data[min];             data[min] = swap;         }     } } /* 快速排序 */ void quick_sort(int* data, int left, int right) {     int p = (left + right) / 2;     int pivot = data[p];     int i = left, j = right;     while (i < j)     {         for (; ! (i >= p || pivot <data[i]); ++i);         if (i < p)         {             data[p] = data[i];             p = i;         }         for (; ! (j <= p || data[j]< pivot); --j);         if (j > p)         {             data[p] = data[j];             p = j;         }     }     data[p] = pivot;     if (p - left > 1)     {         quick_sort (data, left, p - 1);     }     if (right - p > 1)     {         quick_sort (data, p + 1, right);     } }根据您提供的算法，我做了如下修改，还是不能排序。 double computerAvg(struct student stu, int n) {     int i;     double sum = 0.0;     for (i = 0; i < n; i++)     {         sum += stu.sc[i].score;              }     return sum / n; } double maxavg(struct student *stu)  /* 找最大的平均分 */ {     struct student temp;     int index;     int i=0,j;     stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */     for (i = 0; i < 8; i++) //冒泡排序算法 	{         index=i; 		for (j = i+1; j < 9; j++) 		{              			if (stu[j].cavg>stu[index].cavg) 			{ 				index=j; 			} 		}         temp=stu[index];         stu[index]=stu[i];         stu[i]=temp; 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); } void printinfos(struct student stu) {     printf("sno:%s", stu.sno);     printf("name:%s", stu.name); }

引用 10 楼 火花20180731 的回复:[quote=引用 9 楼 风吟xqy 的回复:] 还是折腾出来了，就是多加了一段循环，和之前只改变了平均分的位置，没改变学号和姓名 double computerAvg(struct student stu, int n) {     int i;     double sum = 0.0;     for (i = 0; i < n; i++)     {         sum += stu.sc[i].score;              }     return sum / n; } double maxavg(struct student *stu)  /* 找最大的平均分 */ {     struct student temp;     int index;     int i,j;     for (int k = 0; k < 8; k++)     {         stu[k].cavg = computerAvg(stu[k], 3);  /* !!!!!!!!! */     }     for (i = 0; i < 8; i++) //冒泡排序算法 	{         index=i; 		for (j = i+1; j < 9; j++) 		{              			if (stu[j].cavg>stu[index].cavg) 			{ 				index=j; 			} 		}         temp=stu[index];         stu[index]=stu[i];         stu[i]=temp; 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%.2lf",stu[0].cavg); }  所以你的问题不在于排序算法，而在于平均值的复制不对，不是所有的结构体对象都被赋予了平均值[/quote]是的，只获取了一个平均值，无法进行比较。

引用 9 楼 风吟xqy 的回复:还是折腾出来了，就是多加了一段循环，和之前只改变了平均分的位置，没改变学号和姓名 double computerAvg(struct student stu, int n) {     int i;     double sum = 0.0;     for (i = 0; i < n; i++)     {         sum += stu.sc[i].score;              }     return sum / n; } double maxavg(struct student *stu)  /* 找最大的平均分 */ {     struct student temp;     int index;     int i,j;     for (int k = 0; k < 8; k++)     {         stu[k].cavg = computerAvg(stu[k], 3);  /* !!!!!!!!! */     }     for (i = 0; i < 8; i++) //冒泡排序算法 	{         index=i; 		for (j = i+1; j < 9; j++) 		{              			if (stu[j].cavg>stu[index].cavg) 			{ 				index=j; 			} 		}         temp=stu[index];         stu[index]=stu[i];         stu[i]=temp; 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%.2lf",stu[0].cavg); }  所以你的问题不在于排序算法，而在于平均值的复制不对，不是所有的结构体对象都被赋予了平均值

引用 3 楼 xws245925587 的回复:double maxavg(struct student *stu)  /* 找最大的平均分 */ {     int temp;     int i,j;                                                        //========================》i  并没有赋值，vs居然不报错，神奇     stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */  //===》就用stu[i] ？？？ 用这个不应该是 stu+i ？？要么就是 &(stu[i])     for (i = 0; i < 8; i++) //冒泡排序算法     {         for (j = i; j < 8; j++)         {             if (stu[i].cavg< stu[j].cavg)             {                 temp = stu[i].cavg;         /*交换数组元素*/                 stu[i].cavg = stu[j].cavg;                 stu[j].cavg = temp;             }         }     }     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); }   你这个写法有问题啊，所以大佬，我应该改成什么？

引用 4 楼 风吟xqy 的回复:[quote=引用 1 楼 ?Victor.?? 的回复:] double maxavg(struct student *stu)  /* 找最大的平均分 */ {     student temp;     int i,j;     for(i = 0; i < 8; i++)     	stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */     for (i = 0; i < 8; i++) //冒泡排序算法 	{ 		for (j = i; j < 8 - i - 1; j++) 		{ 			if (stu[i].cavg< stu[j].cavg) 			{ 				temp = stu[i];         /*交换数组元素*/ 				stu[i] = stu[j]; 				stu[j] = temp; 			} 		} 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); }这样改了不会哎[/quote]  引用 1 楼 ?Victor.?? 的回复:double maxavg(struct student *stu)  /* 找最大的平均分 */ {     student temp;     int i,j;     for(i = 0; i < 8; i++)     	stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */     for (i = 0; i < 8; i++) //冒泡排序算法 	{ 		for (j = i; j < 8 - i - 1; j++) 		{ 			if (stu[i].cavg< stu[j].cavg) 			{ 				temp = stu[i];         /*交换数组元素*/ 				stu[i] = stu[j]; 				stu[j] = temp; 			} 		} 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); }我这样改了不对

引用 1 楼 ?Victor.?? 的回复:double maxavg(struct student *stu)  /* 找最大的平均分 */ {     student temp;     int i,j;     for(i = 0; i < 8; i++)     	stu[i].cavg = computerAvg(stu[i], 3);  /* !!!!!!!!! */     for (i = 0; i < 8; i++) //冒泡排序算法 	{ 		for (j = i; j < 8 - i - 1; j++) 		{ 			if (stu[i].cavg< stu[j].cavg) 			{ 				temp = stu[i];         /*交换数组元素*/ 				stu[i] = stu[j]; 				stu[j] = temp; 			} 		} 	}     printf("The Avg max is ");     printinfos(stu[0]);     printf("cavg:%lf",stu[0].cavg); }这样改了不会哎

double computerAvg(struct student stu, int n) ==》》 double computerAvg(struct student *stu, int n) 或 double computerAvg(struct student stu[], int n)


Question: C语言

A，第一个for里面是逗号运算符，顺序执行

第二个for语句()后面有个 ; 号，不起作用，只有第一个for语句起作用

第一个for循环2次（2个i++，相当于i以2递增） 第二个for也是循环2次 所以一共打印4个*

无论什么，两个for循环都不影响print。print只执行一次。


Question: C语言

因为SUB宏，那条语句展开后变成 d=(a+b) - (a+b) *c

宏定义只是把表达式展开， SUB(a+b)展开为 (a+b) - (a+b) 外层没有括号的，所以整个表达式展开为 (a+b) - (a+b) *c 如果想要得到0，那就(SUB(a+b))*c 自己在SUB外层加括号


Question: 求助C语言简单函数实训题

#include<stdio.h>  int perfect(int n) { 	int i,s = 0; 	for(i = 1; i < n; i++) 	{ 		if(n % i == 0) 		s+=i; 	} 	if(n == s) 	    return 1;         else             return 0; }  int main() { 	int i; 	for(i = 1;i <= 1000;i++)        	    if(perfect(i)==1)                 printf("%4d",i); 	return 0; }


Question: 求助C语言简单函数实训题

#include<stdio.h>  int prime(int n) {     int i;     for(i = 2; i < n; i++)     {         if(n % i == 0)             return 0;      }      return 1; }  int main() {     int i;     for(i = 100; i < 1000; i++)         if(prime(i) == 1)              printf("%4d",i);     return 0; }


Question: 为什么第一行平均值是真确的，后面两行就错了，求指出程序的错误。

引用 2 楼 Knight-9hz 的回复:[quote=引用 1 楼 ?Victor.??的回复:]s=s+*(x+4*j+i);  为什么是4*j  应该是20吧 二维数组不是可以这样表示吗[/quote]  1L说的没错，你这个二维数组的是固定20*20，你只是没用完，只用到了3*2，但不代表每一行只有2个元素，也就是说每一行还是20个元素，只是你只用到了每一行的2个元素，所以你计算每行的第一个元素的地址的时候，相对偏移距离还是要用20  其实没必要这么把问题复杂还，没每次给average传参数的时候，直接传每行的首地址就可以了  float average(int *x,int l) //去掉j参数 {     int i;     float s=0.0;     for(i=0;i<l;i++)     {         s=s+*(x+i);     }     s=s/l;     return s; } int main() {     int h,l,a[20][20],i,j;     printf("输入数组的行数：");     scanf("%d",&h);     printf("输入数组的列数：");     scanf("%d",&l);     printf("输入数组：\n");     for(i=0;i<h;i++)         for(j=0;j<l;j++)             scanf("%d",a[i]+j);     for(i=0;i<h;i++)     {         printf("第%d行的平均值为：%f\n",i+1,average(a[i],l)); //直接传每行的首地址     }     return 0; }

引用 2 楼 Knight-9hz 的回复:[quote=引用 1 楼 ?Victor.??的回复:]s=s+*(x+4*j+i);  为什么是4*j  应该是20吧 二维数组不是可以这样表示吗[/quote]  是可以这样表示，但是每行长度是20，要把4改成20

引用 1 楼 ?Victor.??的回复:s=s+*(x+4*j+i);  为什么是4*j  应该是20吧 d ij =*(d(0)+4*i+j)

引用 1 楼 ?Victor.??的回复:s=s+*(x+4*j+i);  为什么是4*j  应该是20吧 二维数组不是可以这样表示吗

s=s+*(x+4*j+i);  为什么是4*j  应该是20吧


Question: 求助C语言简单函数实训题

我的第一行是C++的万能头文件，就是一个顶全部的那种，不过代码都是C的代码没用C++的东西。

刚学没多久，只能做到这了 #include <stdio.h> long long  digit(long long n) { 	long p = 1; 	while (n > 0) 	{ 		n = n / 10; 		p = p * 10; 	} 	return p; } long long fun(long long n)  { 	while(1) 	if (n*n%digit(n)==n) 		return 1; 	else 		return 0; } int main() {long long n = 1; 	while (1) { 		if (fun(n)) 			printf("%ld是守形数。\n", n); 		n += 1; 	} 	return 0; }

引用 1 楼 名字在哪啊 的回复:#include<bits/stdc++.h> #define ll long long using namespace std;  const int maxn=1e5+5; const int inf=0x3f3f3f3f; bool fun(ll n){     ll m=n*n;     while(n){         if(m%10!=n%10)return false;         m/=10,n/=10;     }     return true; } int main() {     ll n     while(~scanf("%lld",&n)){         if(fun(n))printf("%lld是守形数\n");         else printf("%lld不是守形数\n");     }     return 0; }第一行我都看不懂。。。不应该是#include<stdio.h>吗


Question: 请问C语言中结构体的问题？

C++这样没问题，C 语言就不行了。建议用C语言编译试一下，看看是否还能通过语法检查～

编译器的问题，建议最好按正确大众化的规则来写。

这里讨论的是c语言，在c++中当然能过。

引用 2 楼 qiu_shaofeng 的回复:typedef是定义新类型，前面可以不写struct。 不写typedef，前面就要写struct。  你这说法不对, struct PNode{ int data; PNode *a; } ;这样写可以编译通过，不信你试

跟编译器有关，有的gcc版本就不行，vc没问题


Question: PTA程序报错：运行超时

根据题目分析，用一百万大小的byte数组表示所有的学生提交记录即可，大约需要内存1MB，查询时间复杂度为O（1）。

要是内存足够，也可以bitmap的方式

因为是排好序的，所以可以用二分查找，一个id最多几十次就结束了

n=2000000 m=10000 那你两层循环就是n*m=20000000000次 这肯定超时啊 Ai <=1000000，你用数组标记学生是否提交过，应该就可以


Question: 救救孩子吧，单链表太难了

引用 2 楼 Tryagain2006 的回复：        while (temp->next != NULL)             {             temp = temp->next;         }         //这个while循环是什么意思？是否可以删去？  这个循环的意思是：当 temp 没有 指向最后 一个结点时 一直执行循环。退出循环时，指针 temp 指向链表的最后一个结点。可是我删去之后程序还可以正常运行，那这个while循环是不是可有可无？

引用 1 楼 真相重于对错 的回复：找到末尾，把新的节点添加到链表那是否可以删去呢？我删去之后程序还是可以照常运行

找到末尾，把新的节点添加到链表


Question: 新人求助！[Error] invalid conversion from 'int' to 'int*' 这个不知道怎么改正

int dele 这里要不就得改成 int *dele才能和主函数的b对应上

2处修改，可运行，但输出最后一个元素会补0 int * dele(int *a,int len,int d){//2 return  a;//12 再改2处，符合样例 删除a[j]=0; for(i=0;i<len-1;i++){//修改         printf("%d ",b[i]);

有函数定义 int dele(int *a,int len,int d) 。。可以知道，函数 dele 的返回值应该为 int 类型。 而在 main 函数内部，变量 b 为指针，所以， b=dele(num,len,d); 是有问题的。


Question: 求助C语言简单函数实训题

#include<stdio.h> #include<math.h>  double triangle(double a, double b, double c) {     double p = (a + b +c) / 2;     return abs(p* (p - a) * (p - b) * (p - c)); }  int main() {     double a, b, c;     scanf("%lf%lf%lf", &a, &b, &c);     printf("面积 = %f", triangle(a, b, c));     return 0; }


Question: VS读取访问权限冲突0xcccccc的变量初始化问题

引用 1 楼 user-1 的回复：这就是没有初始化导致的，p->next还是没有初始化初始化不是令p->next=NULL么，需要怎么修改呢

这就是没有初始化导致的，p->next还是没有初始化


Question: c语言

这是作业，最好自己来动手做做。

最好有完整的程序，谢谢


Question: 求助C语言简单函数实训题

海伦公式 （p=(a+b+c)/2）  S=sqrt[p(p-a)(p-b)(p-c)]


Question: 为什么编译不了，求助

在第一行 #pragma warning(disable:4996)  或者 第一行#define _CRT_SECURE_NO_WARNINGS


Question: 为什么i的返回值是每次是不相同的，小白求解答。

那为什么我的不对🤔🤔，请教一下。

我这样写，结果正确 #include <stdio.h> int i=0; int num_digit(int n) { 	if(n==0) 	{ 		if(i==0) 		{ 			return 1; 		} 		else 		{ 			return i; 		} 	} 	else 	{ 		i++; 		num_digit(n/10); 	} }  int main() { 	int num; 	scanf("%d",&num); 	printf("%d",num_digit(num)); }

LZ的递归逻辑不对  int num_digit(int n) {     if (n==0)     {         if (i==0) return 1;         return i;     }     i++;     return num_digit(n/10); //这里return就好了 }  其实用非递归就可以了 int num_digit(int n) {     if (n==0) return 1;     i = 0;     while(n!=0)     {         n /= 10;         i++;     }     return i; }

递归函数错误了

递归函数错误了


Question: c语言中如果准确读取txt文件中的一部分数据，求大神指点

你是文本文件还是二进制文件，如果是文本文件，就不好移动指针，因为不好计算，可以一行一行的读，如果是二进制文件，只要知道位置，直接seek就可以，任意位置都可以

引用 1 楼 user-1 的回复:先定位到要读的那一行，然后读取自己需要的部分 那如何定位到那一行呢  我只知道用Fseek移动文件指针，但是不能跨区域移动啊

先定位到要读的那一行，然后读取自己需要的部分


Question: 钩子是不是都是通过注入来实现的？

引用 20 楼 _mervyn 的回复:  本来还想加到六七百分的，结果最大只能四百分，只能这样结贴了。非常感谢您的帮助！

引用 20 楼 _mervyn 的回复:  一万个感谢！  恐怕除了您也没人愿意花这么多时间和精力来给我讲这么详细了  我这里积分不够，等我再多攒点积分再结贴

注入和钩子是两回事，钩子只是注入的一种方式 而且看上面的答复，感觉LZ主要是讨论windows的hook  微软的官方文档对Hook的解释 A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.  翻译过来就是，hook是系统消息机制的一个挂钩点，通过它能够安装一个子程序来管理消息传送和处理关键类型的消息，在消息被发送到目标窗口程序前。也就是可以简单的把hook理解为一个系统消息的拦截过滤器。  windows提供了好几种消息钩子，每种消息钩子有自己的钩子链，安装一个钩子就是把你的回调函数挂入相应类型的钩子链，在消息发送到目标窗口前，这些钩子链的回调函数会先被调用，这样就可以达到对消息的拦截和过滤。  而注入是指在原有的处理流程中插入一段（想要注入的）处理，从而可以改变原有的处理流程。 注入的方式就很多，LS也做了一些回答了，还可以参考以下了解更多的注入方式 https://blog.csdn.net/Sagittarius_Warrior/article/details/52164204 https://www.freebuf.com/articles/system/187239.html  通过上面对hook和注入的解释可以知道，hook能拦截过滤系统消息，在消息到达目标窗口前插入自己的处理，所以它也是一种注入；但是注入不仅仅只有hook方式，只要到达这个注入目的的任何手段都可以称为注入。所以不要搞混着两个概念，要理解它们的联系和区别。

您说的这些中，有两点我还是有疑问：  引用 13 楼 Yofoo 的回复:不过我总觉得有哪里不对，比如系统消息队列，这个应该是独立于所有进程的吧？那么为什么WH_JOURNALRECORD会无效？还是说我测试的方法不对？ ->消息队列, 一般是说窗体的消息队列, 实际实现是在线程中实现, 在内核的线程结构TEB中, 但是实际引擎的循环是在用户层, 是否需要进程加载dll, 跟前面说的一样, 系统是按尽量简单的逻辑, 事件处理在用户层的进程被隔离, 没办法才这样处理, 否则没那么傻, 故意搞这么麻烦 WH_JOURNALRECORD钩子的描述确实是监视系统消息队列呀，不是线程消息队列。  引用 13 楼 Yofoo 的回复:->死循环的dll注入植物大战僵尸来获取无限阳光, 实际实现如:用远线程注入, dllmain创建一个线程, 线程中死循环写内存, 这样没任何问题 钩子是实时的, 是不会故意开个线程去调用, 很多钩子的回调函数异常时, 会导致整个系统卡死, 由于系统有保护才可以卡了一会又恢复 下面是dll的代码和注入的方式，显然是没有用到线程的，总不可能这个注入工具可以在dll中新开线程吧？

MSDN的文档中就有说明  Hook Scope  WH_CALLWNDPROC Thread or global  WH_CALLWNDPROCRET Thread or global  WH_CBT Thread or global  WH_DEBUG Thread or global  WH_FOREGROUNDIDLE Thread or global  WH_GETMESSAGE Thread or global  WH_JOURNALPLAYBACK Global only  WH_JOURNALRECORD Global only  WH_KEYBOARD Thread or global  WH_KEYBOARD_LL Global only  WH_MOUSE Thread or global  WH_MOUSE_LL Global only  WH_MSGFILTER Thread or global  WH_SHELL Thread or global  WH_SYSMSGFILTER Global only    For a specified hook type, thread hooks are called first, then global hooks.   The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. All global hook functions must be in libraries. Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.

引用 7 楼 六道佩恩 的回复:还有个问题就是，还有哪些类型的钩子是不需要dll的？WH_SYSMSGFILTER？这个你是怎么知道的？我看这几个钩子的共同特点是只能用作全局钩子，你是不是根据这点来说的？那么只要是全局钩子就不需要dll，还是只能用作全局的钩子才能不需要dll？  钩子的意思就是，系统提供了一个挂钩，可以将自己的代码钩上去。执行到这个位置的时候，先执行自己的程序，不执行默认的程序。自己的程序从哪里来？从DLL里面提供啊，当然如果你能用其他的方式提供自己的程序也行啊。

引用 14 楼 _mervyn 的回复: 大佬您太牛了！！！  非常感谢您花了这么多时间回答了这么多详细的干货！  真的太感谢了，我会多花时间多读几遍的！  不过我还是有些疑问，有些也是对您的回应： 1. 关于植物大战僵尸注入的死循环dll，我在16楼里贴了，您看看。我专门确认了一下，这个视频也就十多分钟，没有敲任何创建线程的代码，就是写了这么个函数后，生成dll，然后将dll注入了植物大战僵尸的程序就直接运行了，这就是我觉得匪夷所思的地方。至于“注入是注入，执行是执行”，有时候我也想了解原理，所以这里想问的确实只是注入，还有它成功执行的原理，这里应该不是用的SetWindowHookEx，线程注入的话，它这里又确实没有创建线程，我能想到的方式是，它其实注入了两个dll，一个是这个软件自带的dll，目的就是创建一个新的线程并运行新dll的指定函数，不知道是不是这样。  2. 注入实现的原理，注入的时候会执行dll的DLLMain，按理说被执行的线程只是一个单一的顺序流，执行了DLLMain就意为着顺序流跳到了dll这里，我能想到的实现方式是，由当前执行的指令跳转到指定dll函数，最后再跳转回原地方，但原程序的指令都在内存紧密排列着，不好插入跳转指令吧？那么是由中断实现的吗？还有这种DLL注入的中断？  3. MSDN说的可在自己线程直接用的钩子包括了WH_JOURNAL *，网上的说法也有它，但是我测试却收不到相关消息，或者说钩子没被调用，不知道是什么原因，这是代码（换键盘和鼠标的低级钩子就能正常工作）：  #include "windows.h" LRESULT fun1 ( int code , WPARAM wParam , LPARAM lParam ) { 	printf("按键消息：%x\n", wParam ); 	return CallNextHookEx( NULL, code, wParam, lParam ); }  LRESULT fun2 ( int code , WPARAM wParam , LPARAM lParam ) { 	EVENTMSG *p = (EVENTMSG *)lParam; 	printf("消息：%x\n", p->message );  	return CallNextHookEx( NULL, code, wParam, lParam ); } int main( void ) { 	HHOOK hhook1 = SetWindowsHookEx ( WH_KEYBOARD_LL, fun1, GetModuleHandle(NULL), NULL ); 	HHOOK hhook2 = SetWindowsHookEx ( WH_JOURNALRECORD, fun2, GetModuleHandle(NULL), GetCurrentThreadId() ); 	MSG msg; 	while( GetMessage( &msg , NULL , 0, 0 ) ) 	{     		DispatchMessage(&msg); 	} 	return 0; }   4. 关于您说的系统这个有相关的书籍推荐吗？（希望能通俗易懂点的）       您的我还会仔细阅读的，我说下看了后的一些理解，您看对吗：     每个进程都相当于有系统（核心的管理程序）的备份，当调用系统的API后，顺序流就会进入这些系统核心代码运行，最后再跳回程序代码。系统自己也会运行一些重要的进程来保持系统的正常运作，这样，即便所有普通进程都不调用系统API，通过CPU切换时间片也最终可以调用到系统的这些核心进程，以此保证正常的运作。比如当我们点击鼠标后，由于硬件中断会切换到系统进程（或者直接调用当前进程中的系统映射部分？）来处理。你看这样的说法对吗？  5. 关于系统消息队列那里，消息队列不是有“系统消息队列”和“线程消息队列”之分吗？WH_JOURNALRECORD的说明也明确说的是“the system message queue”？

引用 3 楼 gouyanfen 的回复：exe为什么不能注入？dll可以，exe也可以，只不过地址重定位稍复杂些。 注入为什么执行这个要去看看dll加载消息机制。获得执行权限之后，想做什么就发挥你的想像力了，线程也可以，跳转法也可以+1

引用 17 楼 六道佩恩 的回复:不过我还是有些疑问，有些也是对您的回应： 1. 关于植物大战僵尸注入的死循环dll，我在16楼里贴了，您看看。我专门确认了一下，这个视频也就十多分钟，没有敲任何创建线程的代码，就是写了这么个函数后，生成dll，然后将dll注入了植物大战僵尸的程序就直接运行了，这就是我觉得匪夷所思的地方。至于“注入是注入，执行是执行”，有时候我也想了解原理，所以这里想问的确实只是注入，还有它成功执行的原理，这里应该不是用的SetWindowHookEx，线程注入的话，它这里又确实没有创建线程，我能想到的方式是，它其实注入了两个dll，一个是这个软件自带的dll，目的就是创建一个新的线程并运行新dll的指定函数，不知道是不是这样。 我看了下你16楼贴的了，其实很简单，关键是你的那个注入工具，你看它可以接受一个“ 加载时执行函数” 的参数。 而你在写go（）的时候，注释里也明确说你的dll需要导出这个函数。所以，你猜的基本八九不离十了： 1、这个工具利用某种方法注入自己软件附带的dll（常见的方法应该就是我在14楼说的方法三：使用远程线程来注入）。 2、它的dll内部可以和自己的软件通信，一旦收到自己的软件发来的注入命令（命令带上待注入dll、注入时需要调用的函数、卸载时需要调用的函数） 3、它的dll创建了一个线程来执行自己软件发来的命令，即，调用LoadLibaray加载待注入dll（你的dll），用GetProcAddress获得你的dll的导出函数（go），调用之。 你可以用一些工具（比如Process Explorer）来看PlantsVsZombies.exe是否被注入了他软件自己的dll，来印证自己的猜测。 Process Explorer下载地址： https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer 引用 17 楼 六道佩恩 的回复:2. 注入实现的原理，注入的时候会执行dll的DLLMain，按理说被执行的线程只是一个单一的顺序流，执行了DLLMain就意为着顺序流跳到了dll这里，我能想到的实现方式是，由当前执行的指令跳转到指定dll函数，最后再跳转回原地方，但原程序的指令都在内存紧密排列着，不好插入跳转指令吧？那么是由中断实现的吗？还有这种DLL注入的中断？ 你关键就是不理解到底是谁来执行dll的DllMain吧，其实我之前已经有说过了，谁加载的dll就是谁调用的dll的入口函数。这就跟注入手法有关了。以我在14楼举的那3个最常见的方法为例： 1、使用注册表注入。目标程序启动时，加载系统库User32.dll的那条线程会调用User32.dll的DllMain，在这个DllMain中该线程又会LoadLibaray加载待注入dll，于是该dll的DllMain又会被该线程调用。调用堆栈： ---InjectedDll::DllMain(...) ---.... ---kernel32::LoadLibaray( InjectedDll ...) ---user32::DllMian(...) ---.... ---某个加载user32的线程，一般来说那就是这个进程的主线程，在调用exe的main之前。    （因为一般来说，user32都是隐式依赖的，进程启动后main函数之前，会初始化所有全局变量以及加载所有隐式依赖的dll）     （那么如果user32是该程序LoadLibaray动态加载的，那这里就是调用LoadLibaray的那条线程了）。  2、使用SetWindowsHookEx来注入。这个我后面给答案，你可以以你现在的理解再回过头去看一下那个步骤，想一想是哪个线程去调用的DllMain，再来看我的答案。  3、使用远程线程来注入dll。也是显而易见的，你的程序在调用CreateRemoteThread为目标进程创建了一条线程。这条线程的入口就是LoadLibaray，于是这条线程就会去调用你的dll的DllMain。  然后这里说下第2种方法的答案，其实就是重复说一下SetWindowsHookEx之后，目标线程发生的事情： 1、进程B中的 目标线程C 准备调用 GetMessage 或 PeekMessage 获取一条消息 2、系统（线程C）检查该线程是否已经安装了WH_GETMESSAGE挂钩 3、系统（线程C）检查钩子函数所在的dll是否已经被映射到进程B的地址空间中 4、如果dll尚未被映射，系统（线程C）会强制将该dll映射到进程B的地址空间中。（LoadLibaray（dll）--> call dll.DllMain）所以是目标线程C调用的DllMain 5、系统（线程C）调用钩子函数。 6、线程C从钩子函数中返回到GetMessage 或 PeekMessage ，继续接下来的功能 7、线程C从GetMessage 或 PeekMessage返回  线程C进入GetMessage之后的大致调用堆栈 ---InjectedDll::DllMain(...) ---.... ---kernel32::LoadLibaray( InjectedDll ...)  （类似或就是调用的LoadLibaray） ---.... (系统代码： 当检查到 钩子函数所在dll还未加载  ) ---.... (系统代码： 当检查到 当前线程被挂钩  ) ---user32::GetMessage(...)  当然，以上是 当前线程被挂钩且dll未被加载的情况下会走一次，加载dll完毕后，或者 当再次进入GetMessage后，执行流当然直接就进入钩子函数了：  ---InjectedDll::GetMsgProc (...) （dll中的钩子函数） ---.... (系统代码： 当检查到 钩子函数所在dll已加载  ) ---.... (系统代码： 当检查到 当前线程被挂钩  ) ---user32::GetMessage(...)  [/quote]  引用 17 楼 六道佩恩 的回复:3. MSDN说的可在自己线程直接用的钩子包括了WH_JOURNAL *，网上的说法也有它，但是我测试却收不到相关消息，或者说钩子没被调用，不知道是什么原因，这是代码（换键盘和鼠标的低级钩子就能正常工作）： 我没有用过这个功能，我猜是，你还没有触发这个功能吧。我看了msdn，没看懂它说的WH_JOURNALRECORD和WH_JOURNALPLAYBACK这两个触发条件。msdn应该是说WH_JOURNALRECORD这个钩子在 records input messages posted to the system message queue. 时会被调用。  你明白什么是 records input messages  吗？ 好像是说 系统日志 相关的东西。 有windows系统日志产生的时候才会被调用吧。  引用 17 楼 六道佩恩 的回复:4. 关于您说的系统这个有相关的书籍推荐吗？（希望能通俗易懂点的） 可以看 windows核心编程 这本书。看完后对windows会有一个比较清晰的了解。  引用 17 楼 六道佩恩 的回复:每个进程都相当于有系统（核心的管理程序）的备份，当调用系统的API后，顺序流就会进入这些系统核心代码运行，最后再跳回程序代码。系统自己也会运行一些重要的进程来保持系统的正常运作，这样，即便所有普通进程都不调用系统API，通过CPU切换时间片也最终可以调用到系统的这些核心进程，以此保证正常的运作。比如当我们点击鼠标后，由于硬件中断会切换到系统进程（或者直接调用当前进程中的系统映射部分？）来处理。你看这样的说法对吗？ 应该没错了。 起码我觉得就是这样的。 再细节的东西我也不甚了解了。  引用 17 楼 六道佩恩 的回复:5. 关于系统消息队列那里，消息队列不是有“系统消息队列”和“线程消息队列”之分吗？WH_JOURNALRECORD的说明也明确说的是“the system message queue”？ 我查了一下，你说的应该是对的。 确实有 “系统消息队列” ，且应该是指专门用来处理硬件输入的队列：系统硬件输入队列（System Hardware Input Queue），那么我之前的说处理底层键盘鼠标消息的说法可能有部分错误。那应该是一个系统进程（我猜是System.exe 但我没查到明确的说法）处理并分发到对应的进程中去的。

低级钩子（低级键盘和低级鼠标，不知道还有没有其他的，WH_JOURNALRECORD测试不通过，单独的exe中没被调用）所反应的是硬件的消息，由于是硬件的，不和其他任何进程相关，所以系统单独发给一个进程就没有问题。其他钩子都是要和其他进程沟通的，所以要用独立的dll？ ->基本正确  不过我总觉得有哪里不对，比如系统消息队列，这个应该是独立于所有进程的吧？那么为什么WH_JOURNALRECORD会无效？还是说我测试的方法不对？ ->消息队列, 一般是说窗体的消息队列, 实际实现是在线程中实现, 在内核的线程结构TEB中, 但是实际引擎的循环是在用户层, 是否需要进程加载dll, 跟前面说的一样, 系统是按尽量简单的逻辑, 事件处理在用户层的进程被隔离, 没办法才这样处理, 否则没那么傻, 故意搞这么麻烦  还有个很大的问题是关于有死循环的注入函数的，我详细描述下： 首先我认为dll注入的hook函数是由系统调用的，消息进入进程时先调用对应的钩子过程，然后再交给进程处理（不知道对不对）； ->这个说法对钩子系统来说当然最简单的, 但是实际事件可能产生或处理就在用户层, 根本没有进到内核, 所以这个要看具体事件类型  但是我看到有人写一个死循环的dll注入植物大战僵尸来获取无限阳光（阳光低于一定值时就恢复到某个值），如果按上述的理解，显然是不可行的，我不太明白这类注入和钩子的注入是否是同一类，它又是怎么实现的？另开线程吗？可是这个注入的函数又是在什么时候调用的，是在注入的时候立刻另开线程且立刻运行吗？ ->死循环的dll注入植物大战僵尸来获取无限阳光, 实际实现如:用远线程注入, dllmain创建一个线程, 线程中死循环写内存, 这样没任何问题 钩子是实时的, 是不会故意开个线程去调用, 很多钩子的回调函数异常时, 会导致整个系统卡死, 由于系统有保护才可以卡了一会又恢复

仔细看了一下你的回复，你有很多误区，你可以先看下我在14楼的回答。  然后，我在这楼回答下你的疑问。 引用 2 楼 六道佩恩 的回复:1. 我没用dll，使用全局钩子也是成功的 你指的是WH_KEYBOARD_LL、WH_MOUSE_LL、WH_JOURNALRECORD、WH_JOURNALPLAYBACK吧？这几个是特例，你可以去看msdn的解释，每个都在remark中有说的，这里摘一下LowLevelMouseProc钩子remark： 摘自https://docs.microsoft.com/zh-cn/previous-versions/windows/desktop/legacy/ms644986(v=vs.85)#remarks中remark的第二段：  This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop. 该挂钩在安装它的线程（调用SetWindowsHookEx的线程）中被调用。通过向安装钩子的线程（调用SetWindowsHookEx的线程）发送消息来进行调用。因此，安装挂钩的线程（调用SetWindowsHookEx的线程）必须具有消息循环。  因此，这几个特殊钩子的实现是 “被安装钩子的线程”在收到对应消息且检查到被安装钩子时会通过SendMessage（或类似实现）向 “调用SetWindowsHookEx安装钩子的线程“  发送该消息使其钩子函数被调用。  引用 2 楼 六道佩恩 的回复:2. 为什么注入的函数能够执行.....钩子是从哪里注入的？ 我在14楼说了，注入有很多种方式，如果你指的是SetWindowsHookEx，又指WH_KEYBOARD_LL、WH_MOUSE_LL、WH_JOURNALRECORD、WH_JOURNALPLAYBACK这几个特例，看上文。  如果是其他消息，看14楼。  引用 2 楼 六道佩恩 的回复:还有就是，我看别人注入的是一个死循环函数，这都能成功，那是不是说，注入的函数其实是新开的线程执行的？ 你这边又似乎再说其他注入方式了。你要明确一点的是，注入是注入，执行是执行，不要混为一谈。 如果只是通过VirtualAllocEx和WriteProcessMemory来仅仅注入一段函数代码。 那么想让它正确的去执行还是需要一些复杂的手段的。 所以一般简单的注入都是注入dll（方法见14楼），因为dll被加载时，DllMain就会被“加载该dll的线程”调用。这时，你就可以在DllMain函数中调用CreateThread（已经在目标进程了）创建自己的线程了，请确认你说的死循环函数是否说的是在这个线程里，如果是，那这是你自己创建的。 如果你说的还是SetWindowsHookEx，那你的说法就是有错误的，我在14楼有说，该方法注入的是整个dll，没有注入函数一说。且同时SetWindowsHookEx提供的也就那几个函数可以被钩，函数形式是被定死的，你指的“死循环函数”又是何意呢？是指在那几个函数中写了死循环，永不退出吗？ 请确认是否真是这样？如果真是这样，我去看了msdn，我只在WH_KEYBOARD_LL和WH_MOUSE_LL的钩子类型中，也就是LowLevelKeyboardProc和LowLevelMouseProc这两个钩子函数的remark中看到有明确写明系统有超时保护，如果你的钩子函数超过了这个时间，那么在Win7以前，系统直接就不会等你了，在win7及以后，系统会直接删除这个钩子。  这里的“系统”是指目标线程，即被挂勾线程。上文说了这几个特殊的钩子是通过消息通信实现的，钩子函数在你自己安装钩子的线程里执行的，如果被挂勾函数长时间得不到回复，是可以直接不理你的，必要时自动删除钩子。 但如果是其他类型的钩子，那势必会导致目标进程卡死，因为其他类型的钩子是被钩线程自己直接执行的。  引用 6 楼 六道佩恩 的回复:处于系统和程序之间的话，那还算是注入吗？本来按我的理解，这些应该都是归系统调用的，如果全都注入，那么系统里这么多运行的程序，如果每新增一个全局hook都要注入一遍，那太麻烦了，所以我以为全局hook不是注入的，SetWindowsHookEx单独指定某条线程时才会注入，我主要就是想确认是否是这样。 是否注入，和全不全局完全没有关系，只和你的钩子类型有关，上面说了就那几个不需要注入。 其他类型，是必须要注入的，详细看我14楼二方法第4步，如果被钩线程所在进程的钩子函数所在的dll还未注入，被钩线程才会去加载该dll（这时才注入了）。另外再说一句，进程自己就是所谓的“系统”的一部分，当然，有些系统功能确实在某些系统进程中，通过进程间通信调用，但大多数功能其实就是进程自己完成的。  引用 7 楼 六道佩恩 的回复:还有个问题就是，还有哪些类型的钩子是不需要dll的？W 详细看msdn官方说明。对应回调函数页的remarks中有说明 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw 引用 12 楼 六道佩恩 的回复:低级钩子（低级键盘和低级鼠标，不知道还有没有其他的，WH_JOURNALRECORD测试不通过，单独的exe中没被调用）所反应的是硬件的消息，由于是硬件的，不和其他任何进程相关，所以系统单独发给一个进程就没有问题。其他钩子都是要和其他进程沟通的，所以要用独立的dll？ 键盘鼠标消息，一定是和当前拥有焦点的进程相关的，否则谁来处理这个消息？我的理解是底层键盘鼠标消息是所有进程共用的那一块内核代码中的驱动得到的，并判断了当前进程是否拥有焦点，没有焦点的进程则抛弃了这些消息。拥有焦点的那个进程则再将消息传递到其用户态。又或者是, 只有当进程拥有焦点时，其内核态的代码才会去获取或者监听到底层鼠标和键盘的消息，并将其传递给自己的用户态。  至于挂勾这两个消息为何处理不太一样，我想就是简单的因为，这两个消息产生时机还在内核态，目标进程本身就没什么太大的必要在这一刻转到用户态加载dll什么的，这样效率高不了。所以就采用了直接发送消息给钩子安装者了，消息跨线程通信本身效率也不高，所以这个钩子更加要求钩子安装者尽快返回了。而其他钩子类型又为什么不这么做了呢？还是同理，其他钩子的消息产生就在用户态，完全可以直接加载dll在自己进程内执行，提高效率。而采用消息跨线程通信，效率太低。  引用 12 楼 六道佩恩 的回复:不过我总觉得有哪里不对，比如系统消息队列，这个应该是独立于所有进程的吧？  其他钩子需要用dll我觉得我应该是理解的，也许它应该是不允许消息跨进程传输吧？比如交给这个进程处理后再发给另一个进程，所以需要一个公用的dll。 你所谓的 “系统消息队列” 就是指线程的消息队列，一旦一个线程调用了GetMessage或者PeekMessage，消息队列就会被创建。何来独立于所有进程一说？只要是GUI进程就拥有消息队列。 至于消息哪来的？有自己进程的高位地址内核态代码产生的底层消息，有自己线程其他API的调用产生（如CreateWindow会产生WM_PAINT），有其他线程发送的消息（如其他线程调用了PostThreadMessage）等。  引用 12 楼 六道佩恩 的回复:还有个很大的问题是关于有死循环的注入函数的，我详细描述下： 首先我认为dll注入的hook函数是由系统调用的，消息进入进程时先调用对应的钩子过程，然后再交给进程处理（不知道对不对）； 但是我看到有人写一个死循环的dll注入植物大战僵尸来获取无限阳光（阳光低于一定值时就恢复到某个值），如果按上述的理解，显然是不可行的，我不太明白这类注入和钩子的注入是否是同一类，它又是怎么实现的？另开线程吗？可是这个注入的函数又是在什么时候调用的，是在注入的时候立刻另开线程且立刻运行吗？ 你对“系统”和进程的理解有很大的误区，前面已经详细描述了，就不多说了。 注入是注入，hook是hook，是两个概念。 一般我们注入的都是整个dll，很少只注入一个函数，前面说过，只注入函数的话，并让其运行是很复杂的。起码你讨论的SetWindowsHookExW是做不到的，它会将整个dll都注入，这种方法同时还完成特定功能的hook（其实它的主要目的是hook，注入才是顺带的）。而其他方法（见14楼），就只是单纯的注入dll了，hook要另外单独自己写。不管哪种方法，一旦注入了dll（让目标进程将dll映射进其地址空间），这个dll的DllMain入口函数就会被调用，你可以在这里干任何事情了，比如自己开线程，自己去调用该dll的其他任何函数。

引用 11 楼 Yofoo 的回复:钩子简单来说就是一个回调函数,  一个进程发生了一个事件, 如果安装有回调函数就会执行这个函数, 系统会查找这个进程是否有这个函数, 如果没这个函数, 就会让进程再加载dll来取得函数  为什么要进程加载dll, 因系统的进程在空间上是隔离的, 在用户空间发生的事件简单来说就是这个方法 如果是在内核传递出来的事件, 那么可以单一进程获取全部事件, 因为这个不存在隔离问题, 如你们说的低级键盘钩子  操作系统也也许可以做到不加载dll的全钩子, 但是系统没有这么做, 这样只是逻辑复杂些: 系统可以把进程的事件传递到内核, 内核再传递给回掉进程  您看下能否这样理解： 低级钩子（低级键盘和低级鼠标，不知道还有没有其他的，WH_JOURNALRECORD测试不通过，单独的exe中没被调用）所反应的是硬件的消息，由于是硬件的，不和其他任何进程相关，所以系统单独发给一个进程就没有问题。其他钩子都是要和其他进程沟通的，所以要用独立的dll？  不过我总觉得有哪里不对，比如系统消息队列，这个应该是独立于所有进程的吧？那么为什么WH_JOURNALRECORD会无效？还是说我测试的方法不对？  其他钩子需要用dll我觉得我应该是理解的，也许它应该是不允许消息跨进程传输吧？比如交给这个进程处理后再发给另一个进程，所以需要一个公用的dll。  还有个很大的问题是关于有死循环的注入函数的，我详细描述下： 首先我认为dll注入的hook函数是由系统调用的，消息进入进程时先调用对应的钩子过程，然后再交给进程处理（不知道对不对）； 但是我看到有人写一个死循环的dll注入植物大战僵尸来获取无限阳光（阳光低于一定值时就恢复到某个值），如果按上述的理解，显然是不可行的，我不太明白这类注入和钩子的注入是否是同一类，它又是怎么实现的？另开线程吗？可是这个注入的函数又是在什么时候调用的，是在注入的时候立刻另开线程且立刻运行吗？

注入是指把一段代码注入到指定的程序中，即完成了注入，严格的来说，如何让注入的代码得到运行不在概念之内。  但一般来说，在windows中，注入代码最容易的方法就是注入dll，即，让目标进程加载一个dll。它的好处是，注入的代码很容易就可以运行。因为，dll在被任何一个进程加载时，其入口函数DllMain就会被调用（由加载该dll的线程调用），我们一般会在DllMain的DLL_PROCESS_ATTACH通知时，开线程（这样，就相当于为目标进程新开了一个我们自己的线程），然后在新的线程中写一个主循环，处理业务。  windows中，注入有很多种方式，你先明确你想讨论的是哪种? 一、使用注册表注入。windows在注册表的某一路径下有一个AppInit_DLLs键和一个LoadAppInit_DLLs键，当后者为1时，前者即生效。当一个程序需要加载系统库User32.dll时（所有基于GUI的程序都会使用，但那些基于CUI，没有界面的程序则不会），User32.dll会被映射到对应的进程，该进程加载User32.dll的线程会调用User32.dll的DllMain函数。该函数会收到进程加载通知（第2个参数的值为DLL_PROCESS_ATTACH），User32.dll对它进行处理的时候，会取得上述AppInit_DLLs键的值，并调用LoadLibaray来载入这个字符串值中指定的每个DLL。 所以你只要将你写的dll的全路径，写入这个键值中，所有GUI程序在启动时，都将载入你的dll，即完成了注入。同样的，你的dll的DllMain同样得到了执行。  二、使用SetWindowsHookEx来注入。（看你后面的回复，你貌似是在讨论这种，我着重说一说）。它的用法具体可以看msdn，它的功能就像是向系统注册你自己的回调，在系统要做某些功能前有机会来调用你的代码。而一个功能或者说一段代码想要得到执行，必须得有一条线程去执行，所以SetWindowsHookEx是需要指定线程id的（后文我们称之为目标线程）。至于b]系统[/b]中该目标线程做哪些功能前可以调用我们注册的回调，那是有限的（WH_CALLWNDPROC、WH_GETMESSAGE、WH_MOUSE_LL等等），但它们都有一个共同点，就是都需要目标线程拥有消息队列（目标线程调用过GetMessage or PeekMessage ，这样系统就会强制为该线程创建消息队列）。 如果你的目标线程在当前进程，那么你的回调函数（后文我们称之为钩子函数）可以在当前进程的任意模块内。如果你的目标线程在其他进程，那么你的钩子函数必须在dll内。为什么？在了解系统在这种情况下是如何做的，就会明白了。我们以WH_GETMESSAGE为例，假设我们程序的一个线程调用SetWindowsHookEx并传入另一个线程的线程id，通过给这个参数传0，我们告诉系统要给系统中所有GUI线程安装钩子函数（GUI线程一定会调用GetMessage或PeekMessage）。那么接下来会发生什么： 1、进程B中的一个线程准备向一个窗口派送一条消息 2、系统检查该线程是否已经安装了WH_GETMESSAGE挂钩 3、系统检查钩子函数所在的dll是否已经被映射到进程B的地址空间中 4、如果dll尚未被映射，系统会强制将该dll映射到进程B的地址空间中。（我们的dll就在这一刻完成了注入，同时我们dll的DllMain也会得到运行，我们同样可以在这里做些什么） 5、由于dll的HINSTANCE（基址）是在进程B中被映射的，而我们给SetWindowsHookEx的第3个参数HINSTANCE hmod 传入的是dll在进程A中的地址，因此，系统还会对此进行检查，看两者位置是否相同。    如果相同，那么在两个进程的地址空间中，钩子函数位于相同的位置。在这种情况下，系统可以直接在B的地址空间中调用钩子函数。    如果不相同，那么系统必须确定钩子函数在进程B的地址空间中的虚拟内存地址。这个地址不难得出：          钩子函数B = HINSTANCE B + （钩子函数A - HINSTANCE A）        通过把钩子函数A所在地址减去dll在A内的基址可以得到钩子函数在dll内的偏移量，把这个偏移量加上dll在B内的基址就可以得到钩子函数在B内的地址了。 6、系统在B的地址空间中调用钩子函数。  所以一旦系统把钩子函数所在的dll注入或者说映射到地址空间中时，会映射的是整个dll，而不仅仅是钩子函数。这意味着该dll内的所有函数都存在于进程B中，能够为进程B中的任何线程调用。  另外我要说的是，你可能发现了我给上面出现的所有“系统”二字都加粗了，因为我认为你可能不理解的是究竟什么是“系统”？ 我们知道，一段代码想要得到执行，必须有一条线程去跑。 我在上面一直在说“系统”怎么怎么样，“系统”怎么怎么做，“系统”做这些做那些，那“系统”到底是如何有机会做这些做那些的？“系统”不可能在我们不知道的情况下凭空给我们的进程产生线程吧？“系统”或者说“系统”的代码在哪里？“系统”到底是啥？我们回过头仔细想想，最基本的规则：一段代码想要得到执行，必须有一条线程去跑。线程是最小的执行单元。 那么“系统”或者说“系统”的代码其实肯定就在我们自己写的程序里面。   我们知道，windows中有虚拟内存的概念，以32位进程为例，每个进程有4GB虚拟内存，每个进程看到的虚拟内存是不完全相同的，这是因为每个进程的物理内存到该进程虚拟内存地址的映射是不同的。而这4GB虚拟内存分为两部分，虚拟内存地址0~0x7FFFFFFF为用户模式地址，而0x80000000~0xFFFFFFFF为内核模式的地址。啥区别呢？，我们写的“一般”的程序，我们自己的代码，函数也好，运行态申请的空间也好，都在用户模式地址上。而系统写的代码，或者我们写的“不一般”的程序（驱动），就都在内核模式的地址上了。两者结合之后，共同组成了我们的程序。另外要注意的是，它们还有一个最大的区别就是：windows规定所有进程内核模式下的虚拟内存的映射方式是完全一样的，这样也就是说，每个进程中的顶端2GB的内核模式地址的数据是完全一致的。所以每个进程是共用的是同一套系统代码，它就在你的32位程序的高2GB地址空间中。那么它如何得到执行呢？windows为我们提供了很多很多用户态的API来帮助我们利用系统代码。像kernel32.dll user32.dll gdi32.dll 等等。 所以，看到这里，你可以带着这个所谓的系统的概念，再看一遍我上述的（二）方法。相信会更好理解。当然我上面加粗的“系统”，可能一部分还是会包含在用户态的API里做的，里面细节究竟是怎样那就只有微软自己知道了。  三、使用远程线程来注入dll。用上面两个方法注入都对目标有限制（1、目标必须依赖user32.dll,2、目标必须有消息循环），而这个方法的好处是，对目标没有任何限制。其原理就是用了微软提供的几个API： 1、使用VirtualAllocEx为目标进程申请空间A 2、使用WriteProcessMemory为目标进程的地址空间A中写入字符串，内容为我们的dll路径 3、使用CreateRemoteThread为目标进程创建线程，线程地址为LoadLibrary的地址（系统API的地址，在每个进程内的虚拟地址都是一样的），而LoadLibrary的形式正好和线程函数的形式一致。所以给LoadLibrary的参数（即线程函数的参数）传入1种申请的A的地址。 这样我们为目标进程创建出来的线程就会加载我们的dll，同时就会调用我们的dll的DllMain，我们还是可以在这里开始我们的业务。一般来说，如果我们啥都不做，那我们dll内的其他代码就不可能被执行的。这时候需要用hook技术了。 我们得已知目标进程会调用什么函数，该函数在目标进程地址空间中的哪里，我就可以在那里做文章进行跳转hook，当然一般就是系统API的hook了。  就不详细展开了。  四、还有其他很多方法。。。不一一赘述了。 在回到你提的问题，我不知道你是否还有问题。 尤其看了我在（二）中后面的解释。 你要从原理上看，钩子函数代码是谁在跑？是如何开始跑的？什么叫全局？我把我的dll注入到所有进程中，每个进程都会在他们各自的地址空间中用各自的线程跑我的钩子函数，是否就叫全局钩子了呢？ 这都是人为定义的。就比如你说的WH_KEYBOARD_LL和WH_MOUSE_LL，你说不需要dll，直接可以在你安装挂钩的exe里跑，我没用过不知道，如果你实验了确实是这样，那也许就是内核模式下的鼠标键盘驱动在发出消息，在应该处理这个消息的线程处理它之前，先让你的线程处理，再去它应该去的地方。这是否也叫全局钩子呢

引用 7 楼 六道佩恩 的回复:还有个问题就是，还有哪些类型的钩子是不需要dll的？WH_SYSMSGFILTER？这个你是怎么知道的？我看这几个钩子的共同特点是只能用作全局钩子，你是不是根据这点来说的？那么只要是全局钩子就不需要dll，还是只能用作全局的钩子才能不需要dll？ 这个为啥有些需要dll，有些不需要，没深入看过，直接看的网上的结论。我研究hook也只是为了解决工作上的事情，用到的也都是一些常用的，需要dll的类型（全局和非全局的，都用dll的那种）。

引用 6 楼 六道佩恩 的回复:处于系统和程序之间的话，那还算是注入吗？本来按我的理解，这些应该都是归系统调用的，如果全都注入，那么系统里这么多运行的程序，如果每新增一个全局hook都要注入一遍，那太麻烦了，所以我以为全局hook不是注入的，SetWindowsHookEx单独指定某条线程时才会注入，我主要就是想确认是否是这样。  另外就是，我有点不太理解注入为何能实现，dll注入是加入某个进程的空间是吧？那么执行这个注入的函数的是谁？是系统还是这个进程？按理说应该是这个进程，但即便这个进程只有一条顺序流且注入的函数是个死循环，它都是正常运行的，所以，如果是在原进程的某个命令后加入跳转代码到这个注入函数，最后再跳转回去的这个猜测应该是不对的，毕竟一条顺序流会陷死在这个注入函数的死循环里；所以，它的实现原理是另开了条线程，还是由系统执行？如果系统执行，钩链还好理解，要固定调用的，但这个函数注入的时候应该不是通过hook（我看到的演示没有hook相关字样），所以由系统执行的猜测感觉也不太靠谱，毕竟总不可能记录每个注入的函数然后专门去调用吧（甚至可能要单开线程）；所以，是通过在进程内另开线程的方式执行的吗？这个多开的线程，在任务管理器里能看到吗？  然后，，hook不是api吗？  新增一个全局hook的话，是每个进程都会注入的。进程加载dll的时间不是你调用SetWindowsHookEx的时间，而是消息发生的时间，比如你hook全局的WH_GETMESSAGE，某个进程有窗体消息时，就会加载这个dll。至于怎么加载，我没深入研究过，感觉应该类似loadlibrary的方式（有哪位大侠懂的，可以补充下）。具体的情况，可以通过pchunter来观察 楼主一直在说的hook，其实是在windows的消息链上增加一环。可以理解为，windows有个总的消息循环，然后向指定的进程发送消息，发送这个消息是需要进过windows消息链的。然后hook，就是让消息链多了一环。  API HOOK是修改api的地址，也就是让程序调用某个函数的时候先跳转到自己的函数，然后再跳回到原来的地址。网上比较多的例子是将MessageBox。Hook MessageBox 进阶 跨进程Hook  API HOOK和SetWindowsHookEx还是很不一样的。

引用 1 楼 轻箬笠 的回复: 老哥，知道的话回答下可以吗？我可以再加一两百分。

引用 2 楼 六道佩恩 的回复:问你两个问题： 1. 我没用dll，使用全局钩子也是成功的，总不可能exe也能注入吧？ 2. 为什么注入的函数能够执行，我想不通，原来的程序有自己的执行顺序，钩子是从哪里注入的？是不是从哪里截获了顺序流，然后执行完又让顺序流回到原来的地方？我看有的人用软件注入一个dll，这个软件没看到标明是哪个钩子，估计是线程注入，但问题同上？其实我估计的是，这个注入会不会只是数据共享，从原程序的某个地方跳转执行，然后跳转回来，只是从哪里跳转的，这是个问题。还有就是，我看别人注入的是一个死循环函数，这都能成功，那是不是说，注入的函数其实是新开的线程执行的？  做全局注入的时候，我没用过不使用dll的情形，不过从文件结构上看，exe作为源头似乎也不是不行（个人猜测）。另外，有些钩子是不需要dll的（比如WH_JOURNALPLAYBACK，WH_JOURNALRECORD，WH_KEYBOARD_LL，WH_MOUSE_LL），具体没实现过，就不评论了。 钩子的位置的话，应该在windows系统和程序之间。比如system->hook->process，这里的hook是一个链表，我们调用hook就是往链表里面加一条记录。所以hook不会影响程序内部的顺序流，但是会影响哪些system消息进入这个顺序流。就像河水在流，你往里面扔石头，hook能阻止石头进入河里，但是河水还是会流。 至于“从原程序的某个地方跳转执行，然后跳转回来”，这话听着感觉楼主想表达api hook？？

引用 5 楼 轻箬笠 的回复:有些钩子是不需要dll的（比如WH_JOURNALPLAYBACK，WH_JOURNALRECORD，WH_KEYBOARD_LL，WH_MOUSE_LL）  还有个问题就是，还有哪些类型的钩子是不需要dll的？WH_SYSMSGFILTER？这个你是怎么知道的？我看这几个钩子的共同特点是只能用作全局钩子，你是不是根据这点来说的？那么只要是全局钩子就不需要dll，还是只能用作全局的钩子才能不需要dll？

引用 5 楼 轻箬笠 的回复:[quote=引用 2 楼 六道佩恩 的回复:] 问你两个问题： 1. 我没用dll，使用全局钩子也是成功的，总不可能exe也能注入吧？ 2. 为什么注入的函数能够执行，我想不通，原来的程序有自己的执行顺序，钩子是从哪里注入的？是不是从哪里截获了顺序流，然后执行完又让顺序流回到原来的地方？我看有的人用软件注入一个dll，这个软件没看到标明是哪个钩子，估计是线程注入，但问题同上？其实我估计的是，这个注入会不会只是数据共享，从原程序的某个地方跳转执行，然后跳转回来，只是从哪里跳转的，这是个问题。还有就是，我看别人注入的是一个死循环函数，这都能成功，那是不是说，注入的函数其实是新开的线程执行的？  做全局注入的时候，我没用过不使用dll的情形，不过从文件结构上看，exe作为源头似乎也不是不行（个人猜测）。另外，有些钩子是不需要dll的（比如WH_JOURNALPLAYBACK，WH_JOURNALRECORD，WH_KEYBOARD_LL，WH_MOUSE_LL），具体没实现过，就不评论了。 钩子的位置的话，应该在windows系统和程序之间。比如system->hook->process，这里的hook是一个链表，我们调用hook就是往链表里面加一条记录。所以hook不会影响程序内部的顺序流，但是会影响哪些system消息进入这个顺序流。就像河水在流，你往里面扔石头，hook能阻止石头进入河里，但是河水还是会流。 至于“从原程序的某个地方跳转执行，然后跳转回来”，这话听着感觉楼主想表达api hook？？[/quote]  处于系统和程序之间的话，那还算是注入吗？本来按我的理解，这些应该都是归系统调用的，如果全都注入，那么系统里这么多运行的程序，如果每新增一个全局hook都要注入一遍，那太麻烦了，所以我以为全局hook不是注入的，SetWindowsHookEx单独指定某条线程时才会注入，我主要就是想确认是否是这样。  另外就是，我有点不太理解注入为何能实现，dll注入是加入某个进程的空间是吧？那么执行这个注入的函数的是谁？是系统还是这个进程？按理说应该是这个进程，但即便这个进程只有一条顺序流且注入的函数是个死循环，它都是正常运行的，所以，如果是在原进程的某个命令后加入跳转代码到这个注入函数，最后再跳转回去的这个猜测应该是不对的，毕竟一条顺序流会陷死在这个注入函数的死循环里；所以，它的实现原理是另开了条线程，还是由系统执行？如果系统执行，钩链还好理解，要固定调用的，但这个函数注入的时候应该不是通过hook（我看到的演示没有hook相关字样），所以由系统执行的猜测感觉也不太靠谱，毕竟总不可能记录每个注入的函数然后专门去调用吧（甚至可能要单开线程）；所以，是通过在进程内另开线程的方式执行的吗？这个多开的线程，在任务管理器里能看到吗？  然后，，hook不是api吗？


Question: C语言怎样在主函数输出子函数变量值

void insertion_sort(int arr[], int len,int *nc) {     int i,j,frr[19];     for ( i = 1; i < len; i++)     {         int temp = arr[i];         for (j = i-1; j >= 0 && arr[j] > temp; j--)         {             arr[j+1] = arr[j];         }         arr[j+1] = temp;         frr[i-1]=i-j+1;     }     for ( i = 0; i < len-2; i++)     {         *nc = *nc+frr[i];     } }  int main() {     int nc=0;     insertion_sort(arr,N, &nc);     printf("%d",nc) } 供参考～  用一重指针，然后传nc地址到函数里。

因为直接在子函数中int nc，是值传递，传到子函数里面，就变成值的拷贝，这样，在子函数中的nc并不是主函数中的nc。  所以你应该用指针传递，即地址传递，这样子函数中的nc的值和主函数中nc的值就是同一个值。 void insertion_sort(int arr[], int len, int *nc) { 	int i, j, frr[19]; 	for (i = 1; i < len; i++) 	{ 		int temp = arr[i]; 		for (j = i - 1; j >= 0 && arr[j] > temp; j--) 		{ 			arr[j + 1] = arr[j]; 		} 		arr[j + 1] = temp; 		frr[i - 1] = i - j + 1; 	} 	for (i = 0; i < len - 2; i++) 	{ 		*nc = *nc + frr[i]; 	} } int main() { 	int nc = 0; 	insertion_sort(arr, N, &nc); 	printf("%d", nc); 	return 0; }  或者你将nc设置成全局变量。但这样不规范。 int nc = 0; void insertion_sort(int arr[], int len, int nc) { 	int i, j, frr[19]; 	for (i = 1; i < len; i++) 	{ 		int temp = arr[i]; 		for (j = i - 1; j >= 0 && arr[j] > temp; j--) 		{ 			arr[j + 1] = arr[j]; 		} 		arr[j + 1] = temp; 		frr[i - 1] = i - j + 1; 	} 	for (i = 0; i < len - 2; i++) 	{ 		nc = nc + frr[i]; 	} } int main() {  	insertion_sort(arr, N, nc); 	printf("%d", nc); 	return 0; }  并且建议，主函数用int main，并且返回return 0；


Question: 大佬们求助，使用C语言做出这道题

引用 1 楼 自信男孩 的回复:深度优先遍历和广度优先遍历的问题。课本上就有源码，网上也有很多。 大佬，能不能给一个啊，我翻遍了课本，只有简化版，看不太懂，网上的大都是C++，C语言的也是少之又少。

深度优先遍历和广度优先遍历的问题。课本上就有源码，网上也有很多。


Question: `scanf`在读入字符串时为什么不需要在数组名前加取地址符号

数组名就是数组的首地址，因此不需要。

数组名代表数组的首地址，本身就可以理解为一个地址或者指针

数组名本身就是数字的首地址了，再取址就成了地址的地址了，就不对了。但如果你愿意，还是可以写成&a[0]，就也有取址号了！


Question: VS访问冲突，VC正常运行（球球大佬看一眼吧）

0xC0000005大多是指针越界或者访问未分配的地址导致。 字符数组全都是烫，是因为数组没有初始化，结构体申请完后， 需要memset下

#include <stdio.h> #include <stdlib.h> //#include <windows.h>  #define MAX 100  //书结构体 struct Book {     char book_name[30];     unsigned int book_id;     double book_price; };  //书录结构体 struct library {     struct Book book_array[MAX];     unsigned int book_num; };  //显示菜单 void show_menu() {     printf("SSSSSSSSSSSSSSSSSSSSSSSSSSS\n");     printf("                           \n");     printf("    图书超市管理系统v1.0   \n");     printf(" 1.图书基本信息管理        \n");     printf(" 2.购书结算处理            \n");     printf(" 3.售书历史记录            \n");     printf(" 0.退出系统                \n");     printf("                           \n");     printf("EEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); }  //添加图书 void add_book(struct library * lib) {     if (lib->book_num >= MAX)     {         printf("书的数量已达最大值。\n");         system("pause");         system("cls");         return;     }     fflush(stdin);     printf("请输入书的名称:\n");     //scanf_s("%s", lib->book_array[lib->book_num].book_name);     scanf_s("%s", lib->book_array[lib->book_num].book_name, 30);     printf("请输入书的ID:\n");     //scanf_s("%ud", &lib->book_array[lib->book_num].book_id);     scanf_s("%u", &lib->book_array[lib->book_num].book_id);     printf("请输入书的价格:\n");     scanf_s("%lf", &lib->book_array[lib->book_num].book_price);     lib->book_num++;     printf("添加成功!\n");     system("pause");     system("cls"); }  //显示图书 void show_book(struct library * lib) {     if (lib->book_num == 0)     {         printf("当前记录为空。\n");         system("pause");         system("cls");         return;     }     int i = 0;     printf("书名\tID\t售价\n");     for (i = 0; i < lib->book_num; i++)     {         printf("%s\t%u\t%.2lf\n", lib->book_array[i].book_name, lib->book_array[i].book_id, lib->book_array[i].book_price);     }     system("pause");     system("cls"); }  //查找图书位置 int find_book(struct library * lib) { }  //图书基本信息管理 void book_management(struct library * lib) {     int choise;     system("cls");     while (1)     {         printf("***************************\n");         printf("*    图书基本信息管理     *\n");         printf("*1.添加图书               *\n");         printf("*2.删除图书               *\n");         printf("*3.修改图书               *\n");         printf("*4.查找图书               *\n");         printf("*5.展示图书               *\n");         printf("*0.退出功能               *\n");         printf("***************************\n");         scanf_s("%d", &choise);         switch (choise)         {             case 1:                 add_book(lib);                 break;             case 2:                 break;             case 3:                 break;             case 4:                 break;             case 5:                 show_book(lib);                 break;             case 0:                 return;             default:                 printf("输入错误，请重新选择！\n");                 system("pause");                 break;         }         system("cls");     } }  int main() {     int choise;     struct library lib;     lib.book_num = 0;     system("color f0");     printf("***************************\n");     printf("***************************\n");     printf("*                         *\n");     printf("*欢迎使用图书超市管理系统!*\n");     printf("*                         *\n");     printf("***************************\n");     printf("***************************\n");     system("pause");     system("cls");     while (1)     {         show_menu();         scanf_s("%d",&choise);         switch (choise)         {             case 1:                 book_management(&lib);                 break;             case 2:                 break;             case 3:                 break;             case 0:                 return 0;             default:                 printf("输入错误，请重新选择！");                 system("pause");                 break;         }         system("cls");     } } 供参考～  scanf_s对于%s需要多一个参数


Question: 求解答

give you a 思路  https://blog.csdn.net/qq_45861670/article/details/104109693  主要就是随机数

这是我们老师，写的，不过好像没写完整

include <stdio.h> #include <stdlib.h> #include <time.h> int get_random1(void); int get_random2(void); void multitable(int a,int b); int input(); int main(void) { 	srand(time(NULL)); 	int sum = 0; 	int score = 10; 	printf("*구구단 문제*\n"); 	for (int i = 1; i <= 10; ++i) { 		int in = input(); 		int a = get_random1, 			b = get_random2; 		printf("%d号 问题：", i); 		multitable(a, b); 		in; 		if (a*b == in) 		{ 			printf("答案%d 正确.", in); 			sum += score; 		} 		else printf("答案%d 错误”，a*b); 		} 	    	printf("总分:%d分", sum); 	return 0; } int get_random1(void) { 	return rand() % 9 + 1; } int get_random2(void) { 	return rand() % 9 + 1; } void multitable(int a,int b) { 	{ 		printf("%d*%d= \n",  a, b); 	} } int input(void) { 	int in; 	scanf_s("%d", &in); 	return in; }

include <stdio.h> #include <stdlib.h> #include <time.h> int get_random1(void); int get_random2(void); void multitable(int a,int b); int input(); int main(void) { 	srand(time(NULL)); 	int sum = 0; 	int score = 10; 	for (int i = 1; i <= 10; ++i) { 		int in = input(); 		int a = get_random1, 			b = get_random2; 		printf("%d号问题: ", i); 		multitable(a, b); 		in; 		if (a*b == in) 		{ 			printf("答shi%d 正确.", in); 			sum += score; 		} 		else printf("답은 %d 오답입니다.", a*b); 		}  	printf("점수:%d점", sum); 	return 0; } int get_random1(void) { 	return rand() % 9 + 1; } int get_random2(void) { 	return rand() % 9 + 1; } void multitable(int a,int b) { 	{ 		printf("%d*%d= \n",  a, b); 	} } int input(void) { 	int in; 	scanf_s("%d", &in); 	return in; }


Question: perl生成汇编

perl和C一样 也是一门编程语言  至于编译工具和书籍 百度一下


Question: realloc函数报错

发完整代码出来吧，暂时没看出什么问题。 另外，建议对malloc/realloc和strtok的返回值做判断

你的InputSplit结构体怎么定义的？参数怎么传进来的？ 另外， Splitstruct->str[i] = (char*)malloc(strlen(word)+1 * sizeof(char)); //长度计算有错，注意加减乘除的优先级 Splitstruct->str[i] = (char*)malloc((strlen(word)+1) * sizeof(char));


Question: 趣味程序设计＿13高次方数求助

这样应该是可以的 #include<bits/stdc++.h> #define ll long long using namespace std;  const int maxn=1e5+5; const int inf=0x3f3f3f3f; ll pow_(ll a,ll b){     ll ans=1;     while(b){         if(b&1)ans=(ans*a)%1000;         a=(a*a)%1000;         b>>=1;     }     return ans; } int main() {     ll n;     while(~scanf("%lld",&n)){         printf("%03lld\n",pow_(13,n));     }     return 0; }

这个相当于是13的n次方对1000取模，应该可以用快速幂

LZ的代码基本可以，只是n用int不对，130000000000超过了int范围 另外，输入循环不对while(scanf("%d",&n)!=EOF) 改成 scanf("%d",&n)==1，好好查看一下scanf的返回值

#include<stdio.h> int main() {     int s, i, n;      	while( scanf("%d",&n)==1 )     {   s=1;         n = n%1000;		//	最后3位          for ( i=0; i<n; i++ )     	{	s = s*13%1000;     	}     	printf("%03d\n",s);     }     return 0; }


Question: 求助！！！！兄弟们来看看为什么我打印出来的第一个字符总是消失

程序员数数要从0开始不是1

引用 1 楼 user-3 的回复：for(i=3;i<=n;i++)为什么要从3开始？不从0开始当时从0开始结果更不靠谱 索性找了个相对靠谱的数字3哈哈哈

引用 3 楼 weixin_41991157 的回复：程序员数数要从0开始不是1大一刚刚学 有点懵逼

引用 2 楼 自信男孩 的回复：#include<stdio.h>  #define N 100  //void main(void) int main(void) {     int i=0,j=0,n=0,t=0;     int a[N];     printf("请输入要输入数字的个数 \n\r");     scanf("%d",&n); #if 1     while (i < n) {         printf("请输入数字: \n");         scanf("%d",&a[i]);         if (a[i] < 0)             break;         i++;     }     for (i = 0; i < n; i++)         for (j = 0; j < n - i -1; j++)             if (a[j] > a[j+1]) {                 t = a[j];                 a[j] = a[j+1];                 a[j+1] = t;             }      printf("排序后的顺序是：\n");     for (i = 0; i < n; i++)         printf("%5d",a[i]); #else     /*     do     {         printf("请输入数字: \n");         scanf("%d",&a[i]);         i++;     }     while(a[i-1]>=0) ;     */       for(i=1;i<n;i++)    //变量i代表比较的趟数         for(j=1;j<n+1-i;j++)//变最j代表每趟两两比较的次数             if(a[j]>a[j+1])             {                 t=a[j]; //产利用中间变童实现两值互换                 a[j]=a[j+1];                 a[j+1]=t;             }      printf("排序后的顺序是：\n");     for(i=3;i<=n;i++)         printf("%5d",a[i]); #endif     printf("\n");     return 0; } 供参考～  建议用while代替do ... while，因为如果n输入的是0，那么会是什么结果？ 排序也有问题， 输出也有问题，对比代码找出自己的问题吧谢谢


Question: 为什么我的atof不能成功将字符串转换为浮点型，是我的结构数组里面字符串指针用错了吗

结构体要么给那两个 char* 改为char [大小]; 要么改为 double,然后把printf和scanf的相关格式化改下 。 你把这个程序放到vs里面跑 ，按F5 很好调的

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h>  typedef struct good//单一商品结构 {      char name[32];     //char *inprice;     //char *outprice;     char inprice[16];     char outprice[16];     int numbers;//商品库存量 }GOOD;  void fun1(){     printf("\n");     int choice;     int i=0;      GOOD goods;      FILE *fp ;     fp=fopen("商品库存表.txt" , "a+");//打开文件     if ( fp == NULL )     {         printf("文件打开失败!\n") ;     }       do//商品信息录入     {           printf("请输入入库商品的名称\n");//商品名          scanf("%s", goods.name);         //getchar();          printf("请输入商品进货价格\n");//商品进货价格          //scanf("%s", &goods.inprice);         scanf("%s", goods.inprice);          printf("请输入商品销售价格\n");//商品销售价格          //scanf("%s",&goods.outprice);         scanf("%s", goods.outprice);         //getchar();          printf("请输入入库商品的数量\n");//商品库存数量         scanf("%d", &goods.numbers);          fwrite( &goods , sizeof(GOOD), 1, fp ); //将信息写入文件           printf("是否继续录入?(按数字1继续，数字0退出)");//判断是否继续录入？         scanf("%d", &choice);//读取用户选择         //getchar();//吃回车     }     while(choice==1);      fclose(fp);//关闭文件夹 }  void fun3(){     char names[10];//用户购买商品名     int i=0;     double f;     int b,j,xuanze=0;     int count,chioce;     int m=0;     int c=0;     double sum=0;       GOOD goods[1000];      FILE *fp ;     fp=fopen("商品库存表.txt" , "a+");//打开文件     if ( fp == NULL )     {         printf("文件打开失败!\n");     }     rewind(fp);//指针位置重置     do     {          count=fread(&goods[m],sizeof(GOOD),1,fp); //从文件中读所有商品的数据         if(count==1)         {             printf("成功读入第%d个\n",m+1);             m++;         }     }while (!feof (fp));//判断是否读到文件尾     fclose(fp);     printf("系统准备完毕!\n");     do{         printf("请输入要购买的商品名:\n");         scanf("%s",names);         getchar();          for(j=0;j<m;j++)//通过商品名查询价格         {             if(strcmp(names,goods[c].name) != 0)             {                 xuanze=1;             }             c++;         }         if(xuanze!=1)             exit(0);          printf("请输入需要购买商品的数量\n");         scanf("%d",&b);         //getchar();    //为啥要加呢          if(b<=goods[i].numbers)//库存足够         {             printf("商品购买成功!");         }         f=atof(goods[i].outprice);         printf("%lf", f);         sum+=f*b;          printf("是否需要继续购买？(1继续购买，0结算)\n");         scanf("%d",&chioce);         //getchar();    //为啥要加呢？     }while(chioce==1);      printf("正在结算，请稍等.....\n");      printf("您一共需要支付%.2f元!\n",sum);      printf("感谢您的光顾，祝您生活愉快!");     getchar(); }     //void main() int main() {     int choice;     while(1)     {         printf("\n\n\n");         printf("****欢*迎*使*用*商*品*销*售*管*理*系*统****\n");         printf("*                                         *\n");         printf("*             1.库存表数据录入            *\n");         printf("*             2.销售表数据录入            *\n");         printf("*             3.销售商品                  *\n");         printf("*             4.库存表查询                *\n");         printf("*             5.销售表查询                *\n");         printf("*             0.退出                      *\n");         printf("*                                         *\n");         printf("*******************************************\n");         printf("please choice(0-5):");         scanf("%d",&choice);         switch(choice)         {             case 0:    exit(0);  // 头文件定义 <stdlib.h>,结束程序             case 1:    fun1()       ;break;             case 2:   // fun2()       ;break;             case 3:    fun3()       ;break;             case 4:   // fun4()       ;break;             case 5:    //fun5();                        break;          }      } } 供参考～  楼主不止一次问这个程序了吧。 之前给你改的，你没有完全领会呀。结构体声明里用的是指针，在scanf之前为什么不申请空间，不申请空间进出价变量都是野指针呢。  要么声明时就用数组，不用指针。 另外atof不对的原因可能是读取到的就有问题，读取有问题，那么写入的就会有问题。建议先把商品的文件删掉，重新运行我改的程序。

刚才改了，执行到输出atof的返回值时，还是不能继续了

把inprice和outprice改成字符数组


Question: 自定义类型

typedef int NUM [10];这是把类型个int [10]起个别名NUM，即NUM就代表int [10]即10个int类型元素的类型。 NUM a;即定义了一个int类型的包含10个元素的数组。即int a[10];

引用 2 楼 其实一开始我是拒绝的 的回复:[quote=引用 1 楼 user-4的回复:]这书直接丢了，什么书籍名？ C语言程序设计第三版，课本里面错了？[/quote] 书上没错， typedef 声明提供一种声明标识符为类型别名的方式，以用于替换可能复杂的类型名。 例如struct ,函数指针，都可以用typedef 简化声明和定义。

引用 3 楼 tianyabaiwei的回复:我的理解是，只是改了个数组名字，数组里面的数据存放是没有变动的。因为数组名称即是数组数据的存放的指针名称，这个操作仅仅是数组的名字从a换成了NUM。至于具体的可以电脑上试试，个人认为没什么实际意义。 好............

引用 1 楼 user-4的回复:这书直接丢了，什么书籍名？ C语言程序设计第三版，课本里面错了？

这书直接丢了，什么书籍名？


Question: 自定义类型

这个typedef关键字，就是类型别名的意思。  你书上的例子已经说的很清楚了 #include <stdio.h>  typedef int myNum1;//以后可以用myNum1代替int typedef int myNum2[10];//以后可以用myNum2代替int []  int main() { 	myNum1 a1=0;//等价于int a1=0; 	myNum2 a2 = {0,1,2,3,4,5,6,7,8,9};//等价于int a2[10]= {0,1,2,3,4,5,6,7,8,9};  	printf("%d\n", a1);  	for (int i = 0; i < 10; ++i) { 		printf("%d ", a2[i]); 	} 	return 0; }


Question: C语言

B         verygood

那什么情况下是修改p所指的只能，p前面加上间接寻址运算符吗？

ps是指针，里面存放的是地址值，即谁把地址给了ps，它就只想哪里。 ps怎么修改，只要不对数据区域做修改，都不会影响到s. ps += 4;和ps = "nice";都是在修改ps的地址值，没对s数据（或者称为内容）部分做任何修改。

B verygood ps="nice"是把ps指针指向了别的地址，和原来的s没有半毛关系


Question: 求解

这个问题就是数据结构中经典的题目：将一棵二叉排序树变换为一个按升序排列的二叉链表。

中序遍历。。。。。


Question: 各位大佬们，我跪了，fwrite写入结构数组，为什么frean读出后数据不对

引用 4 楼 NICEBOY97 的回复:为什么写入后读出的信息还是不一致，里面有些信息还是读入的烫字，那个int类型写入在文本里面无法正常显示吗？  读之前对buf  memset一下

#include <stdio.h> #include <stdlib.h> #include <string.h>  //#define NUMBER 1000;//可录入商品总数    #为啥要加分号 #define NUMBER 1000   //可录入商品总数  typedef struct good//单一商品结构 {     int number;//商品编号     char name[32];//={'\0','\0','\0','\0'};//商品名     char inprice[4];//={'\0','\0','\0','\0'};//商品进货价格     char outprice[4];//={'\0','\0','\0','\0'};//商品销售价格     int numbers;//商品库存量 }GOOD;  void fun1(){     printf("\n");     int o;     int choice;     int i=0;     /*     typedef struct good//单一商品结构     {         int number;//商品编号         char name[4];//={'\0','\0','\0','\0'};//商品名         char inprice[4];//={'\0','\0','\0','\0'};//商品进货价格         char outprice[4];//={'\0','\0','\0','\0'};//商品销售价格         int numbers;//商品库存量     }GOOD;     */     GOOD goods;      FILE *fp ;     fp=fopen("商品库存表.txt" , "a+");//打开文件     if ( fp == NULL )     {         printf("文件打开失败!\n") ;     }       do//商品信息录入     {         goods.number=0;         goods.number+=1;          printf("请输入入库商品的名称\n");//商品名         //scanf("%s",&goods.name);         scanf("%s", goods.name);         //getchar();          printf("请输入商品进货价格\n");//商品进货价格         //scanf("%s",&goods.inprice);         scanf("%s", goods.inprice);         //getchar();          printf("请输入商品销售价格\n");//商品销售价格         //scanf("%s",&goods.outprice);         scanf("%s", goods.outprice);         //getchar();          printf("请输入入库商品的数量\n");//商品库存数量         scanf("%d", &goods.numbers);          o=fwrite( &goods , sizeof(GOOD), 1, fp ); //将信息写入文件         printf("%d\n",o);          printf("是否继续录入?(按数字1继续，数字0退出)");//判断是否继续录入？         scanf("%d", &choice);//读取用户选择         //getchar();//吃回车     }     while(choice==1);      fclose(fp);//关闭文件夹 }  void fun3(){     char names[10];//用户购买商品名     int i=0;     int b,j,xuanze=0;     int count;     int m=0;     int c=0;      /*     typedef struct good//单一商品结构     {         int number;//商品编号         char name[10] ;//商品名         char inprice ;//商品进货价格         char outprice;//商品销售价格         int numbers;//商品库存量     }GOOD;     */     //GOOD *p;     GOOD goods[1000];      FILE *fp ;     fp=fopen("商品库存表.txt" , "a+");//打开文件     if ( fp == NULL )     {         printf("文件打开失败!\n");     }     rewind(fp);//指针位置重置     do     {         //count=fread(&goods,sizeof(GOOD),1,fp); //从文件中读所有商品的数据         count=fread(&goods[m],sizeof(GOOD),1,fp); //从文件中读所有商品的数据         if(count==1)             m++;     }while (!feof (fp));//判断是否读到文件尾     fclose(fp);     printf("系统准备完毕!\n");      printf("请输入要购买的商品名:\n");     scanf("%s",names);     getchar();      for(j=0;j<m;j++)//通过商品名查询价格     {         if(strcmp(names,goods[c].name) != 0)         {             xuanze=1;         }         c++;     }     if(xuanze!=1)         exit(0);      printf("请输入需要购买商品的数量\n");     scanf("%d",&b);     getchar();      if(b<=goods[i].numbers)//库存足够     {         printf("ok");     }     else         printf("%d",goods[i].number);  }    //void main() int main() {     int choice;     while(1)     {         printf("\n\n\n");         printf("****欢*迎*使*用*商*品*销*售*管*理*系*统****\n");         printf("*                                         *\n");         printf("*             1.库存表数据录入            *\n");         printf("*             2.销售表数据录入            *\n");         printf("*             3.销售商品                  *\n");         printf("*             4.库存表查询                *\n");         printf("*             5.销售表查询                *\n");         printf("*             0.退出                      *\n");         printf("*                                         *\n");         printf("*******************************************\n");         printf("please choice(0-5):");         scanf("%d",&choice);         switch(choice)         {             case 0:    exit(0);  // 头文件定义 <stdlib.h>,结束程序             case 1:    fun1()       ;break;             case 2:   // fun2()       ;break;             case 3:    fun3()       ;break;             case 4:   // fun4()       ;break;             case 5:    //fun5();                        break;          }      } } 供参考～  为什么声明两个结构体呢？ 还在每个函数里声明同名但不一样的结构体。 还要两个结构体在一个函数里运用？  fread/fwrite的是以二进制形式读取和写入的，因此打开文件内容会出现乱码。如果fscanf/fprintf不会，因为这对函数是格式话文本形式读写文件的。

开始用的二进制，然后读出来信息对应不上，转换成txt,里面用一些烫烫字

读写结构体，要采用二进制读写！打开方式用ab+


Question: 求助，程序输出界面是空白的，而且得到的student2.txt也是是空白的，是哪里 有错误吗？

引用 1 楼 自信男孩的回复:#include <stdio.h> #include <stdlib.h>  struct student {     long num;     char name[10];     float score[3]; }ml[10];  void mr(float aver[],int rank[]) {     int i,j,a;     for(i=0;i<10;i++)     {         a=1;         for(j=0;j<10;j++)         {             if(aver[i]<aver[j])                 a=a+1;         }         rank[i]=a;     } } int main() {     FILE *fp1,*fp2;     int i,rank[10];     float aver[10];     if((fp1=fopen("E:\\student1.txt","r"))==NULL)     {         printf("无法打开文件\n");         exit(0);     }     fp2 = fopen("E:\\student2.txt","w");     if (!fp2) {         printf("无法打开文件\n");         exit(0);     }  #if 0     for(i=0;i<10;i++)         //fscanf(fp1,"%ld %s %f %f %f",ml[i].num,ml[i].name,ml[i].score[0],ml[i].score[1],ml[i].score[2]);         fscanf(fp1,"%ld %s %f %f %f", &ml[i].num,ml[i].name, &ml[i].score[0], &ml[i].score[1], &ml[i].score[2]);     for(i=0;i<10;i++)     {         aver[i]=(ml[i].score[0]+ml[i].score[1]+ml[i].score[2])/3.0;     } #else     for(i=0;i<10;i++) {         //fscanf(fp1,"%ld %s %f %f %f",ml[i].num,ml[i].name,ml[i].score[0],ml[i].score[1],ml[i].score[2]);         fscanf(fp1,"%ld %s %f %f %f", &ml[i].num,ml[i].name, &ml[i].score[0], &ml[i].score[1], &ml[i].score[2]);         aver[i] = (ml[i].score[0]+ml[i].score[1]+ml[i].score[2])/3.0;     } #endif     mr(aver,rank);     for(i=0;i<10;i++)         fprintf(fp2,"%-9ld%-10s%-5.1f%-5.1f%-8.1f%-10.1f%-d\n",ml[i].num,ml[i].name,ml[i].score[0],ml[i].score[1],ml[i].score[2],aver[i],rank[i]);     fclose(fp1);     fclose(fp2);     return 0; } 供参考～ 谢谢你，感觉自己是真的蠢总犯这种小错误


Question: 求助

作业也放这上来伸手了！

这是您的作业？


Question: 为什么这个里边的SIGQUIT会一直显示没有定义呢

缺少依赖：#include <csignal>


Question: 求助C语言数组实训题

//#include<iostream> 可改为  #include<stdio.h>  可将 system("pause"); 删除 #include<iostream> #include<time.h>  int main() { 	int		a[10][10] = { 0 };  //数组初始化为0 	int		i = 0; 	int		j = 0; 	int		count = 0;          //大于90的元素个数 	int		sum1 = 0;           //对角线的元素个数之和 	int		sum2[10] = { 0 };   //每行元素的和 	int		sum3[10] = { 0 };   //每列元素的和 	int		max = 0;		    //最大值 	int		min = 100;			//最小值  	srand(time(0));				//初始化元素种子 	for (i = 0; i < 10; i++) 	{ 		for (j = 0; j < 10; j++) 		{  			a[i][j] = rand() % 100 + 1;  //随机生成100以内的元素 		} 	} 	printf("二维数组的元素为：\n"); 	for (i = 0; i < 10; i++) 	{ 		for (j = 0; j < 10; j++) 		{ 			printf("%d  ", a[i][j]); 		} 		printf("\n"); 	}   	//01大于90的元素的个数 	for (i = 0; i < 10; i++) 	{ 		for (j = 0; j < 10; j++) 		{ 			if (a[i][j] > 90) 			{ 				count = count + 1; 			}  		} 	} 	printf("大于90的元素的个数: %d\n", count);   	//02对角线的元素个数之和 	for (i = 0; i < 10; i++) 	{ 		j = i; 		sum1 += a[i][j]; 	} 	printf("对角线的元素个数之和:%d \n", sum1);   	//03 每行和每列的和 	for (i = 0; i < 10; i++) 	{ 		for (j = 0; j < 10; j++) 		{ 			sum2[i] += a[i][j]; 			sum3[i] += a[j][i];  		} 	} 	printf("每行的和为:"); 	for (i = 0; i < 10; i++) 	{ 		printf("%d  ", sum2[i]); 	} 	printf("\n"); 	printf("每列的和为:"); 	for (i = 0; i < 10; i++) 	{ 		printf("%d  ", sum3[i]); 	} 	printf("\n");   	//最大元素和最小元素 	for (i = 0; i < 10; i++) 	{ 		for (j = 0; j < 10; j++) 		{ 			//最大 			if (max < a[i][j]) 			{ 				max = a[i][j]; 				 			}  			//最小 			if (min > a[i][j]) 			{ 				min = a[i][j]; 			} 		} 	} 	printf("最大元素为：%d\n", max); 	printf("最小元素为：%d\n", min);  	system("pause"); }

引用 3 楼 ?Victor.?? 的回复:你得学着自己做了  不然期末考试危险了  我打算下个星期回学校开始重学一遍。。。不过挂科应该不至于

你得学着自己做了  不然期末考试危险了

引用 1 楼 chxchxkkk 的回复:给个思路，具体代码自己写吧 int a[10][10] ={0};  int i,j; 先输入二维数组的值 1. int count = 0;  //大于90的元素个数 for (i=0; i<10; i++) {     for (j=0; j<10; j++)     {         if (a[i][j] > 90)             count++;     } } 2.求对角线元素的和 int sum = 0; for (i=0; i<10; i++) {     for (j=0; j<10; j++)     {         if (i == j)             sum += a[i][j];     } } 3.每行每列的和 int hsum[10] = {0}; int lsum[10] ={0};  for (i=0; i<10; i++) {     for (j=0; j<10; j++)     {         hsum[i] += a[i][j]; //每行之和         lsum[i] += a[j][i];  //每列之和           } } 4. int max = a[0][0];      int min = a[0][0]; for (i=0; i<10; i++) {     for (j=0; j<10; j++)     {         if (a[i][j] > max)             max = a[i][j];    //最大值         if (a[i][j] < min)             min = a[i][j];   //最小值      } }我是属于一点不会的那种。。。。


Question: 求大佬

引用 4 楼 自信男孩 的回复:[quote=引用 1 楼 ?Victor.?? 的回复:]  #include<stdio.h>  int main() {     int i, s = 1;     for(i = 1; i < 21; i++)           s*= i;     printf("%d", s);     return 0; }  有没有考虑到s溢出的问题？[/quote]  确实 感谢提醒 考虑不周~

s考虑用unsigned long long或这 double  引用 4 楼 自信男孩 的回复:[quote=引用 1 楼 ?Victor.?? 的回复:]  #include<stdio.h>  int main() {     int i, s = 1;     for(i = 1; i < 21; i++)           s*= i;     printf("%d", s);     return 0; }  有没有考虑到s溢出的问题？[/quote]

引用 1 楼 ?Victor.?? 的回复: #include<stdio.h>  int main() {     int i, s = 1;     for(i = 1; i < 21; i++)           s*= i;     printf("%d", s);     return 0; }  有没有考虑到s溢出的问题？

LS的两种方法都可以，只是结果超出int范围，所以最好把int改成double类型

递归 #include <stdio.h> #include <stdlib.h>   int fac(int n) {     if (n <= 1)     {         return 1;     }     else     {         return n*fac(n - 1);     }      } int main() {     int n = 0;     printf("请输入一个数：");     scanf_s("%d", &n);   //这块输入你求的乘积数 比如你上面的20     int fac(n);     printf("%d\n", fac(n));     system("pause");     return 0; }


Question: 查找字符串子串用strcmp函数

学习。。。。。。。

int instring(char *s1, char *s2) {   if (!strlen(s1) > strlen(s2)) return 0;   char *cur_s1 = s1;   char *cur_s2 = s2;   if (*cur_s1 == '\0') return 1;   else return 0;   if (*cur_s1 == *cur_s2) return instring(cur_s1++, cur_s2++); }

引用 23 楼 qybao的回复:[quote=引用 22 楼 其实一开始我是拒绝的 的回复:]  不用动态分配，直接char*s【20】=NULL可以？ 就你的代码而言，s1肯定不会超过20（name[20]），所以不用动态分配，用char s[20] = {0}; 也可以，这样连s[len1]='\0'也可以省了[/quote] 好，，，，，，，

引用 22 楼 其实一开始我是拒绝的 的回复:不用动态分配，直接char*s【20】=NULL可以？ 就你的代码而言，s1肯定不会超过20（name[20]），所以不用动态分配，用char s[20] = {0}; 也可以，这样连s[len1]='\0'也可以省了

引用 21 楼 qybao的回复:[quote=引用 20 楼 其实一开始我是拒绝的 的回复:]  为什么s【len1】要等于字符串结束符 因为s的最后一个字符是字符串结尾符，s申请内存的长度是len1+1就是为了让s的最后一个字符保存字符串结尾符，从s2循环赋值给s只用到len1个字符（从s[0]到s[len1-1]），所以最后一个字符就是s[len1][/quote] 不用动态分配，直接char*s【20】=NULL可以？

引用 20 楼 其实一开始我是拒绝的 的回复:为什么s【len1】要等于字符串结束符 因为s的最后一个字符是字符串结尾符，s申请内存的长度是len1+1就是为了让s的最后一个字符保存字符串结尾符，从s2循环赋值给s只用到len1个字符（从s[0]到s[len1-1]），所以最后一个字符就是s[len1]

引用 11 楼 qybao的回复:用strcmp的（不用memcpy的版本） int instring(char *s1,char *s2) {     int len1,i;     if(s1==NULL || s2==NULL) return 0;     len1 = (int)strlen(s1);     char *s = (char*)malloc(sizeof(char)*(len1+1)); //用个临时变量保存子串     s[len1] = '\0';     for(;*s2!='\0'&&strlen(s2)>=len1;s2++) //循环改变s2的开始位置     {         for (i=0;i<len1;i++) //用for循环从s2开始位置截取子串             s[i] = s2[i];         if (strcmp(s, s1) == 0) //如果截取的子串和s1相同             return 1;     }     free(s); //释放临时变量     return 0; } 为什么s【len1】要等于字符串结束符

引用 11 楼 qybao的回复:用strcmp的（不用memcpy的版本） int instring(char *s1,char *s2) {     int len1,i;     if(s1==NULL || s2==NULL) return 0;     len1 = (int)strlen(s1);     char *s = (char*)malloc(sizeof(char)*(len1+1)); //用个临时变量保存子串     s[len1] = '\0';     for(;*s2!='\0'&&strlen(s2)>=len1;s2++) //循环改变s2的开始位置     {         for (i=0;i<len1;i++) //用for循环从s2开始位置截取子串             s[i] = s2[i];         if (strcmp(s, s1) == 0) //如果截取的子串和s1相同             return 1;     }     free(s); //释放临时变量     return 0; } 我知道了，谢谢

引用 17 楼 轻箬笠的回复:int instring(char *s1,char *s2) {     if (strlen(s1) == 0)return 1;          char buf[100];     do{         if (strlen(s1) > strlen(s2))return 0;         int i = 0;         for (; i < strlen(s1); i++)             buf[i] = s2[i];         buf[i] = '\0';         if (strcmp(s1, buf) == 0)return 1;         s2++;     }while(1);     return 0; } 汗，写错了。if (strcmp(s1, s2) == 0)return 1;改成if (strcmp(s1, buf) == 0)return 1; 我知道了，谢谢

int instring(char *s1,char *s2) {     if (strlen(s1) == 0)return 1;          char buf[100];     do{         if (strlen(s1) > strlen(s2))return 0;         int i = 0;         for (; i < strlen(s1); i++)             buf[i] = s2[i];         buf[i] = '\0';         if (strcmp(s1, s2) == 0)return 1;         s2++;     }while(1);     return 0; } 那改成这样，原来memset和memcpy都不能用啊

引用 14 楼 其实一开始我是拒绝的 的回复:mencpy怎么改成for循环？ memcpy改成for的版本在11L

引用 9 楼 qybao的回复:一定要用strcmp吗？不能用strncmp吗？ 用strcmp的版本  int instring(char *s1,char *s2) {     int len1;     if(s1==NULL || s2==NULL) return 0;     len1 = (int)strlen(s1);     char *s = (char*)malloc(sizeof(char)*(len1+1)); //用个临时字符串     memset(s, '\0', len1+1);     for(;*s2!='\0'&&strlen(s2)>=len1;s2++)  //循环改变s2的开始位置     {         memcpy(s, s2, len1); //从s2开始位置截取leng1长度的子串（这里用了memcpy，可以自己循环一个一个字符赋值）         if (strcmp(s, s1) == 0) //比较截取的子串是否和s1相同             return 1;     }     free(s);     return 0; }   用strncmp的版本 int instring(char *s1,char *s2) {     int len1;     if(s1==NULL || s2==NULL) return 0;     len1 = (int)strlen(s1);     for(;*s2!='\0'&&strlen(s2)>=len1;s2++) //循环改变s2的开始位置     {         if (strncmp(s2, s1, len1) == 0) //从s2的开始位置比较len1个字符是否和s1相同             return 1;     }     return 0; } mencpy怎么改成for循环？

引用 10 楼 轻箬笠的回复:[quote=引用 8 楼 其实一开始我是拒绝的 的回复:] 能不能改成for循环 ，menset（）还没学 for (int i = 0; i < strlen(buf); i++)buf[i] = '\0';[/quote] b【i】是写在for循环里面的？

引用 8 楼 其实一开始我是拒绝的 的回复:能不能改成for循环 ，menset（）还没学 for (int i = 0; i < strlen(buf); i++)buf[i] = '\0';

引用 5 楼 轻箬笠的回复:int instring(char *s1,char *s2) {     if (strlen(s1) == 0)return 1;          char buf[100];     do{         if (strlen(s1) > strlen(s2))return 0;         memset(buf, 0, sizeof(buf));         memcpy(buf, s2, strlen(s1));         if (strcmp(s1, buf) == 0)return 1;         s2++;     }while(1);     return 0; } 这样试试，楼主测试看看。 能不能改成for循环 ，menset（）还没学

引用 6 楼 chxchxkkk的回复:用strcmp的话可以参考  int instring(char *s1, char *s2)  {       if (strcmp(s1, s2) == 0)            return 1;      else           return 0;   }  这样好像不行啊


Question: 麻烦帮下忙

引用 1 楼 user-1 的回复：7/2=3.5 取整（int类型）是多少？那就是去掉小数部分，所以答案是3（也就是选c）好的谢谢


Question: 1234对应的二进制数

4d2是16进制表示。根据16进制是一个数字表示4位，比如 4==0100 d==1101 2==0010 所以二进制是010011010010

引用 8 楼 其实一开始我是拒绝的 的回复:[quote=引用 7 楼 Tryagain2006的回复:][quote=引用 楼主 其实一开始我是拒绝的 的回复:] 为什么1234对应点二进制数是这样？  您说的是文件上存储的数据吧？[/quote] 对的。。。。。[/quote]  C语言的文件分为文本文件和二进制文件，如果要将一个整数保存到二进制文件中，则系统会将内存中的用 二进制 表示的整数 转换为用 ASCII 表示的字符串，所以内存中整型的 1234 数，在存入文本文件的时候就会被自动自动转换为四个ASCII字符，也是书上说的4个数字 ‘1’，‘2’，‘3’，‘4’。

引用 7 楼 Tryagain2006的回复:[quote=引用 楼主 其实一开始我是拒绝的 的回复:] 为什么1234对应点二进制数是这样？  您说的是文件上存储的数据吧？[/quote] 对的。。。。。

引用 楼主 其实一开始我是拒绝的 的回复:为什么1234对应点二进制数是这样？  您说的是文件上存储的数据吧？

引用 4 楼 真相重于对错的回复:[quote=引用 2 楼 其实一开始我是拒绝的 的回复:] [quote=引用 1 楼 真相重于对错的回复:]1234 转为16进制就是4d2 可是里面说1234对应的是二进制的[/quote] 你截书截了一半，我看不到上下文，哪里知道你的书里写的啥？[/quote] 是我看错了，三楼说了，谢谢

引用 2 楼 其实一开始我是拒绝的 的回复:[quote=引用 1 楼 真相重于对错的回复:]1234 转为16进制就是4d2 可是里面说1234对应的是二进制的[/quote] 你截书截了一半，我看不到上下文，哪里知道你的书里写的啥？

引用 2 楼 其实一开始我是拒绝的 的回复:[quote=引用 1 楼 真相重于对错的回复:]1234 转为16进制就是4d2 可是里面说1234对应的是二进制的[/quote] 看书这么不认真的，人家说的是放到文件文件1234表现的二过制对应的ASCii码值， 放到二进制文件中，则是0x4d2(虽然你没截到图，估计是这样子的)

引用 1 楼 真相重于对错的回复:1234 转为16进制就是4d2 可是里面说1234对应的是二进制的

1234 转为16进制就是4d2


Question: 求出每行最大元素及其所在的行号和列号,哪里出问题了呀，大神帮帮忙

//#include "stdio.h" #include <stdio.h>  //void main() int main() {     int i,j,max,m,n;     int a[3][4];      for(i=0;i<3;i++)         for(j=0;j<4;j++)             scanf("%d",&a[i][j]);      for(i=0;i<3;i++)     {         for(j=0;j<4;j++)             printf("%4d",a[i][j]);         printf("\n");     }      for(i=0;i<3;i++)     {         max=a[i][0];          {             //for(j=0;j<4;j++) {             for(j=1;j<4;j++) {                 if(max<a[i][j]) {                     max=a[i][j];                     m=i;                     n=j;                 }                 //m=i;                 //n=j;             }              printf("第%d行最大的元素行列号为别%d,%d\n",i+1,m+1,n+1);         }     }  } 供参考～

引用 1 楼 user-2 的回复:代码缩进是个好习惯。  for(i=0;i<3;i++) {	       max=a[i][0];       for(j=0;j<4;j++)  //上面多了个{     {         if(max<a[i][j])         {                                         max=a[i][j];             m=i;             n=j;         }     }         printf("第%d行最大的元素行列号为别%d,%d\n",i+1,m+1,n+1);  }  这样层次更清晰些，把m=i; n=j也包含在判断语句里试试看 多了个{

代码缩进是个好习惯。  for(i=0;i<3;i++) {	       max=a[i][0];       {for(j=0;j<4;j++)     {         if(max<a[i][j])         {                                         max=a[i][j];             m=i;             n=j;         }     }         printf("第%d行最大的元素行列号为别%d,%d\n",i+1,m+1,n+1);  }  这样层次更清晰些，把m=i; n=j也包含在判断语句里试试看


Question: 在Linux下设计一个游戏快捷键应用程序


Question: 求大佬帮我解释这段单链表代码，求求孩子吧，卡了三天了

岔路口 学习.

不错的资源，很好

太过精偏！！！！！！！！

二级指针的目的是为了可以修改这个一级指针的指向，否则只能修改这个指针指向那块结构的内容，任何对于指针本身的修改都是不生效的，类似于 int max(const int a,const int b,int max) //不能修改max值 int max(const int a,const int b,int * max) //可以修改max值

引用 11 楼 weixin_45906870 的回复:没看懂...我的意思是addBook这个函数的参数为什么不能是一级指针？  作为基本概念，您是否注意到，C语言在函数之间进行参数传递遵守的是规则是单向的“值传递”，所以要用 swap 函数交换main 函数中两个 int 类型变量值的时候，在swap 函数的参数中要使用 int * 作为参数。这是所有讲C语言的教材中都会说到的例子。这样，在 swap 函数中才能改变 main 函数中变量的值。  同理，在 main 函数中 library 为指针，现在希望在子函数中 修改 指针 library，所以子函数的参数就要使用二级指针。

没看懂...我的意思是addBook这个函数的参数为什么不能是一级指针？

addBook(&library);  这里传进去的是library的地址，是这个指针本身的地址，如果子函数里只用 一个*，那么得到的是这个指针的地址，而不是它指向结构体的地址，所以要用 **

引用 6 楼 自信男孩 的回复：#include <stdio.h> #include <stdlib.h>  struct Book {     char title[128];     char author[40];     struct Book *next; };  void getInput(struct Book *book) {     printf("请输入书名：");     scanf("%s", book->title);     printf("请输入作者：");     scanf("%s", book->author); }  void addBook(struct Book **library)     //这里的参数是个二级指针，目的是为了修改指针的地址，但是这个函数里面只用到了一级指针，那为什么还要弄个二级指针作参数？ {     struct Book *book, *temp;      book = (struct Book *)malloc(sizeof(struct Book));      //这里为什么用了malloc申请空间，目的是什么？不用有什么影响？     if (!book)  //不加这句是做啥，不想让程序运行了吗？     {         printf("内存分配失败了！\n");         exit(1);     }      getInput(book);      if (*library != NULL)     {         temp = *library;         *library = book;         book->next = temp;     }     else     {         *library = book;         book->next = NULL;     } }  void printLibrary(struct Book *library) {     struct Book *book;     int count = 1;      book = library;     while (book != NULL)     {         printf("Book%d: ", count);         printf("书名：%s", book->title);         printf("作者：%s", book->author);         putchar(10);         book = book->next;         count++;     } }  //void releaseLibrary(struct Book *library) void releaseLibrary(struct Book **library) {     struct Book *pcur = *library, *ptmp; #if 0     while (library != NULL)     {         free(library);         library = library->next;     } #else     while (pcur) {         ptmp = pcur->next;         free(pcur);         pcur = ptmp;     }     *library = NULL;  #endif } int main() {     struct Book *library = NULL;     int ch;      while (1)     {         printf("请问是否需要录入书籍信息（Y/N）：");         do         {             ch = getchar();             getchar();    //for '\n'         } while (ch != 'Y' && ch != 'N');          if (ch == 'Y')         {             addBook(&library);             getchar();    //for '\n'         }         else         {             break;         }     }      printf("请问是否需要打印图书信息（Y/N）:");     do     {         ch = getchar();         getchar();    //for '\n'     } while (ch != 'Y' && ch != 'N');      if (ch == 'Y')     {         printLibrary(library);     }      releaseLibrary(&library);      return 0; }  供参考～  注意getchar()和scanf("%c", xxx);比较特殊需要处理'\n' 建议对比代码找出自己的问题～感谢，不过那个二级指针的问题我还是不懂

引用 7 楼 Tryagain2006 的回复：[quote=引用 5 楼 weixin_45906870 的回复:] [quote=引用 3 楼 Tryagain2006 的回复：]void addBook(struct Book **library) //这里的参数是个二级指针，目的是为了修改指针的地址，但函数里面只用到了一级指针，那为什么还要弄个二级指针作参数？  这个问题是这样的。在 main 函数中 library 为指针，现在希望在子函数中 修改指针 library，所以子函数的参数就要使用二级指针。可是子函数中没有用到二级指针啊，全是一级指针[/quote]  呵呵，你的基本概念有问题。[/quote]？？？

引用 5 楼 weixin_45906870 的回复:[quote=引用 3 楼 Tryagain2006 的回复：]void addBook(struct Book **library) //这里的参数是个二级指针，目的是为了修改指针的地址，但函数里面只用到了一级指针，那为什么还要弄个二级指针作参数？  这个问题是这样的。在 main 函数中 library 为指针，现在希望在子函数中 修改指针 library，所以子函数的参数就要使用二级指针。可是子函数中没有用到二级指针啊，全是一级指针[/quote]  呵呵，你的基本概念有问题。

引用 3 楼 Tryagain2006 的回复：void addBook(struct Book **library) //这里的参数是个二级指针，目的是为了修改指针的地址，但函数里面只用到了一级指针，那为什么还要弄个二级指针作参数？  这个问题是这样的。在 main 函数中 library 为指针，现在希望在子函数中 修改指针 library，所以子函数的参数就要使用二级指针。可是子函数中没有用到二级指针啊，全是一级指针

book = (struct Book *) malloc(sizeof(struct Book)); //这里为什么用了malloc申请空间，目的是什么？不用有什么影响？  book 是一个指向结构的指针，book要必须指向一个“实体”之后才能进行后续的操作，所以要为 book 分配一个空间，用来存储实际的数据。

引用 1 楼 Tryagain2006 的回复：题目是什么？有什么问题？我都用红色字体标注了

题目是什么？有什么问题？


Question: 怎么才能在C语言里实现cd、dir、mkdir之类的操作呢，类似于自己写一个操作系统这样？救救孩子

windows头文件 使用system() 调用

封装好命令，调用system也是一种方法。 也可以看一下系统调用函数，比如mkdir，access等等函数

system()


Question: 求字符串中的查找子串

引用 5 楼 其实一开始我是拒绝的的回复:[quote=引用 4 楼 自信男孩的回复:]#include <stdio.h> #include <string.h> //#include "stdio.h" //#include "string.h" //#if 0 #define N 10  struct Book {   char name[100];     float price; };  int instring(const char *s1, const char *s2); //s1若属于s2的字串，则返回1，否则返回0 int main() {   struct Book books[N]={{"Fling in sky",23.0},{"I love my mother",15.5},{"My love",25.6},{"Color is red",34.9},{"Black and red",20.5},{"Let me love you",16.0}, {"Sun is red",45.0},{"Flower sunshine",23.8},{"Say love not easy",45.9},{"Friday black",34.0}};     int i;     char name[20];     gets(name);     for(i=0;i<N;i++)         if(instring(name,books[i].name))             printf("%30s,%6.2f\n",books[i].name,books[i].price);     return 0; }  int instring(const char *s1, const char *s2) {     if (strstr(s2, s1))         return 1;     return 0;  } //#else  int instring2(const char *s1, const char *s2) {     int i = 0;     int len1, len2;      len1 = strlen(s1);     len2 = strlen(s2);      while (i < len2) {         if (len2 - i < len1)             break;         if (strncmp(s1, s2+i, len1) == 0)             return 1;         i++;     }      return 0; } /* int main(void) {     const char *s1 = "helloworld";     const char *s2 = "orl";      printf("%d\n", instring2(s2, s1));      return 0; } */ #endif 供参考～  两种方法都可以考虑测试一下。 能解释一下第二种方法？[/quote] 我搞懂了，谢谢。

引用 4 楼 自信男孩的回复:#include <stdio.h> #include <string.h> //#include "stdio.h" //#include "string.h" //#if 0 #define N 10  struct Book {   char name[100];     float price; };  int instring(const char *s1, const char *s2); //s1若属于s2的字串，则返回1，否则返回0 int main() {   struct Book books[N]={{"Fling in sky",23.0},{"I love my mother",15.5},{"My love",25.6},{"Color is red",34.9},{"Black and red",20.5},{"Let me love you",16.0}, {"Sun is red",45.0},{"Flower sunshine",23.8},{"Say love not easy",45.9},{"Friday black",34.0}};     int i;     char name[20];     gets(name);     for(i=0;i<N;i++)         if(instring(name,books[i].name))             printf("%30s,%6.2f\n",books[i].name,books[i].price);     return 0; }  int instring(const char *s1, const char *s2) {     if (strstr(s2, s1))         return 1;     return 0;  } //#else  int instring2(const char *s1, const char *s2) {     int i = 0;     int len1, len2;      len1 = strlen(s1);     len2 = strlen(s2);      while (i < len2) {         if (len2 - i < len1)             break;         if (strncmp(s1, s2+i, len1) == 0)             return 1;         i++;     }      return 0; } /* int main(void) {     const char *s1 = "helloworld";     const char *s2 = "orl";      printf("%d\n", instring2(s2, s1));      return 0; } */ #endif 供参考～  两种方法都可以考虑测试一下。 能解释一下第二种方法？

引用 2 楼 其实一开始我是拒绝的的回复:[quote=引用 1 楼 自信男孩的回复:]直接贴代码吧，贴图片不好给你调试代码～ #include "stdio.h" #include "string.h" #define N 10 struct Book {   char name[100];     float price; }; int instring(char *s1,char *s2); //s1若属于s2的字串，则返回1，否则返回0 int main() {   struct Book books[N]={{"Fling in sky",23.0},{"I love my mother",15.5},{"My love",25.6},{"Color is red",34.9},{"Black and red",20.5},{"Let me love you",16.0}, {"Sun is red",45.0},{"Flower sunshine",23.8},{"Say love not easy",45.9},{"Friday black",34.0}};     int i;     char name[20];     gets(name);     for(i=0;i<N;i++)         if(instring(name,books[i].name))            printf("%30s,%6.2f\n",books[i].name,books[i].price);     return 0; }  int instring(char *s1,char *s2) {     [textArea=11,60] } [/quote] 怎样在函数定义那里实现？

引用 1 楼 自信男孩的回复:直接贴代码吧，贴图片不好给你调试代码～ #include "stdio.h" #include "string.h" #define N 10 struct Book {   char name[100];     float price; }; int instring(char *s1,char *s2); //s1若属于s2的字串，则返回1，否则返回0 int main() {   struct Book books[N]={{"Fling in sky",23.0},{"I love my mother",15.5},{"My love",25.6},{"Color is red",34.9},{"Black and red",20.5},{"Let me love you",16.0}, {"Sun is red",45.0},{"Flower sunshine",23.8},{"Say love not easy",45.9},{"Friday black",34.0}};     int i;     char name[20];     gets(name);     for(i=0;i<N;i++)         if(instring(name,books[i].name))            printf("%30s,%6.2f\n",books[i].name,books[i].price);     return 0; }  int instring(char *s1,char *s2) {     [textArea=11,60] }

直接贴代码吧，贴图片不好给你调试代码～

引用 10 楼 其实一开始我是拒绝的 的回复:for的后面为什么有分号 因为for不需要做什么处理，只需要找到不符合循环条件的 j 位置，如果找不到 j 位置（也就是一直满足 for 循环条件），j 就会一直走到s1的最后位置（也就是 j 一直走到 s1 的最后字符都是和 s2 的字符相等的），所以此时就说明s2里包含s1，所以后面的接着的 if 就直接返回 1

引用 8 楼 其实一开始我是拒绝的的回复:[quote=引用 7 楼 user-2的回复:][quote=引用 5 楼 其实一开始我是拒绝的 的回复:]  能解释一下第二种方法？ 方法二的另一种形式，可能更好理解一些（其实就挨个比较字符，只不过LS用了内存比较） int instring2(char *s1, char *s2) {     int i=0,j=0;     for(;s2[i]!='\0'; i++)      {         if (s2[i]==s1[0]) //找到第一个相等的字符后         {              for (j=1;s2[i+j]!='\0'&&s1[j]!='\0'&&s2[i+j]==s1[j];j++); //依次比较后续的字符             if (s1[j]=='\0') return 1; //如果后续字符都相同就返回1         }     }     return 0; }[/quote] 为什么for后面会有（）[/quote] for的后面为什么有分号

引用 8 楼 其实一开始我是拒绝的的回复:[quote=引用 7 楼 user-2的回复:][quote=引用 5 楼 其实一开始我是拒绝的 的回复:]  能解释一下第二种方法？ 方法二的另一种形式，可能更好理解一些（其实就挨个比较字符，只不过LS用了内存比较） int instring2(char *s1, char *s2) {     int i=0,j=0;     for(;s2[i]!='\0'; i++)      {         if (s2[i]==s1[0]) //找到第一个相等的字符后         {              for (j=1;s2[i+j]!='\0'&&s1[j]!='\0'&&s2[i+j]==s1[j];j++); //依次比较后续的字符             if (s1[j]=='\0') return 1; //如果后续字符都相同就返回1         }     }     return 0; }[/quote] 为什么for后面会有（）[/quote] for的后面为什么有；

引用 7 楼 user-2的回复:[quote=引用 5 楼 其实一开始我是拒绝的 的回复:]  能解释一下第二种方法？ 方法二的另一种形式，可能更好理解一些（其实就挨个比较字符，只不过LS用了内存比较） int instring2(char *s1, char *s2) {     int i=0,j=0;     for(;s2[i]!='\0'; i++)      {         if (s2[i]==s1[0]) //找到第一个相等的字符后         {              for (j=1;s2[i+j]!='\0'&&s1[j]!='\0'&&s2[i+j]==s1[j];j++); //依次比较后续的字符             if (s1[j]=='\0') return 1; //如果后续字符都相同就返回1         }     }     return 0; }[/quote] 为什么for后面会有（）

引用 5 楼 其实一开始我是拒绝的 的回复:能解释一下第二种方法？ 方法二的另一种形式，可能更好理解一些（其实就挨个比较字符，只不过LS用了内存比较） int instring2(char *s1, char *s2) {     int i=0,j=0;     for(;s2[i]!='\0'; i++)      {         if (s2[i]==s1[0]) //找到第一个相等的字符后         {              for (j=1;s2[i+j]!='\0'&&s1[j]!='\0'&&s2[i+j]==s1[j];j++); //依次比较后续的字符             if (s1[j]=='\0') return 1; //如果后续字符都相同就返回1         }     }     return 0; }


Question: 数组

楼上正解  借花献佛，另外一种答案：  #include<stdio.h>   int main() {      int a[6] = {0};      int i;      for(i = 0; i < 6; i++)           scanf("%d", a+i);     //a是整型指针。加1，代表向后移动4个字节，到下一个整型数组元素      for(i = 0; i < 6; i++)           printf("%d", a[i]);      return 0; }

#include<stdio.h>  int main() {      int a[6] = {0};      int i;      for(i = 0; i < 6; i++)           scanf("%d", &a[i]);      for(i = 0; i < 6; i++)           printf("%d", a[i]);      return 0; }   是这个意思吧？


Question: 【求助】同一个结构体在一个文件中输入后，在其他多个文件调用运算并输出

另存一下，因为代码页应该不对


Question: 求助C语言数组实训题

#include<stdio.h>  int main() {     int a[100] = {0}, b[100] = {0};     int i;     for(i = 0; i < 100; i++)           a[i] = i;     for(i = 0; i < 100; i++)           printf("%4d", a[i]);     for(i = 0; i < 100; i++)           b[i] = a[100-i];     for(i = 0; i < 100; i++)           printf("%4d", b[i]);     return 0;   题目要求不是很严格


Question: 求助C语言数组实训题

#include <stdio.h>  /** 可以直接按照实际函数构造C语言函数*/ int f(int n) { 	if (n == 1) 	{ 		return 1; 	} 	else if (n==2) 	{ 		return 3; 	} 	else 	{ 		return f(n-1) + 2*n; 	} } 	   int main () { 	int array[20]; 	 	int i; 	for(i=0; i<20; i++) 	{ 		array[i] = f(i+1); 		printf("%d\n", array[i]); /**< 输出前20项*/ 	} }


Question: 求助大佬

咱最好给出源程序，让我再输入一遍程序？这个真不愿意。

就是他的运行结果是这样，不继续运行了

运行不下去，指的是什么？出错还是结果不对，还是其他的

我调用了这个函数，但是他运行不正确  他只打印换行符，不打印其他东西 我有换成p = head->next，结果判断p为空

引用 4 楼 盛夏·绽放 的回复:我是现在又修改了以下，应该是链表创建没什么问题，但是打印还有问题  文件格式的话是.c文件，内容有点多 不知道你的head是头指针不，一般有头指针head的数据域是空的 遍历时一般： p = head->next 或 p->next != NULL 试试看 另外 菜单1 下调用 showall函数了没

楼主的不是有序链表，建议提供更多的代码，另外，文件的内容和格式也提供一下


Question: c语言图形化数据统计 求大神帮帮忙?

用MFC的作图函数


Question: C语言指针

请参考《C++数组地址偏移》 希望能够帮到你！

p += 6;就是向后偏移6 * sizeof(int)个字节，如果p是char *，那么选择6是没问题的。因为sizeof(char)是1.

int main() {     int *p = NULL；    //这里把0换成NULL会更好理解     printf("%d\n", p);     p += 6;          printf("%d\n", p); } ---------------------- 定义了一个整型指针变量 p, 指针p开始指向“0”（空），可以理解为NULL 指针p = 0； 由于指针是int整型的，加1，要向后移动4个字节。 所以，加6，就像后移动了24个字节 故再次打印p的值，是24

因为一个int是四个字节


Question: 求求大佬，救救孩子吧，研究三小时了

初学吧~~字符串'/0'结尾 也就是NULL 也就是0，然后按个数到'/0'，+1+1+1，最后返回这个计数的就行了

写个易懂的  int i = 0 while (str[i] != '\0') {     i++; } return i;

引用 5 楼 user-3的回复:[quote=引用 3 楼 zege666 的回复:] [quote=引用 1 楼 user-3的回复:]你一定假装在想，哎…… ---------------------- int i; for(i=0;str[i];i++); return i; 这这这.....[/quote]  一句一小时~~~ VC的strlen是这样写的： const char *eos = str; while( *eos++ ) ; return( eos - str - 1 );[/quote] 触及到我知识盲区了，我们还没学到指针

引用 3 楼 zege666 的回复:[quote=引用 1 楼 user-3的回复:]你一定假装在想，哎…… ---------------------- int i; for(i=0;str[i];i++); return i; 这这这.....[/quote]  一句一小时~~~ VC的strlen是这样写的： const char *eos = str; while( *eos++ ) ; return( eos - str - 1 );

引用 1 楼 user-3的回复:你一定假装在想，哎…… ---------------------- int i; for(i=0;str[i];i++); return i; 都不需要scanf的吗......

引用 1 楼 user-3的回复:你一定假装在想，哎…… ---------------------- int i; for(i=0;str[i];i++); return i; 这这这.....


Question: 函数返回二维数组和一维数组

感谢各位，本人疑惑已解开

既然一维可以，为啥二维不可以？ 比如 int main () {     int i,j;     //方法1     printf("方法1\n");     int *arr1[3] = {(int*)malloc(sizeof(int)*3), (int*)malloc(sizeof(int)*4), (int*)malloc(sizeof(int)*5)};     for (i=0; i<5; i++) {         if (i<3) arr1[0][i] = i+1;         if (i<4) arr1[1][i] = i+1;         arr1[2][i] = i+1;     }     for(i=0; i<3; i++) {         printf("%p:", arr1[i]); //打印地址（动态申请堆内存）         for (j=0; j<3+i; j++) {             printf("%d ", arr1[i][j]);         }         printf("\n");         free(arr1[i]); //释放内存     }     //方法2     printf("方法2\n");     int a1[]={1,2,3};     int a2[]={1,2,3,4};     int a3[]={1,2,3,4,5};     int *arr2[3] = {a1, a2, a3};     for (i=0; i<3; i++) {         printf("%p:", arr2[i]); //打印地址（栈内存）         for (j=0; j<3+i; j++) {             printf("%d ", arr2[i][j]);         }         printf("\n");     }     return 0; }  另，如LS所说，如果要做为函数返回值返回就用动态分配内存，不要返回局部变量内存空间，因为离开函数，局部变量就消亡了（也就是函数栈内存被系统回收了，返回值就变成野指针）

建议楼主写个程序，这样描述和验证更好一些。  另外，返回局部变量（数组）是未定义行为，注意一下数组的作用域，不要定义了局部数组，又返回局部数组。

如果你是定义的arr[3][3]，那么*arr[n]中n的取值范围就是0~2 感觉你搞混了定义中的空间大小与下标的取值范围。


Question: 求大佬帮忙

哦哦谢谢大佬了

scanf("%d",&G.E[i][j]); G.E[i][j]=G.E[j][i];  输入到 G.E[i][j] ;又用 G.E[j][i] 重置了


Question: 求助   Tom and Jerry (大概是这么叫的)

引用 5 楼 user-3 的回复：建立数学模型：    5s后Tom与Jerry的距离 = 5*v1-(n+5*v2)，若>=0，则追上Jerry GG!    否则，看第6s时，Tom与Jerry的距离 = (n+6*v2)-5*v1，若>n则无法追上为啥是>n？老鼠-猫不是应该大于0吗

引用 3 楼 user-3 的回复:[quote=引用 2 楼 5250 的回复:] [quote=引用 1 楼 user-3 的回复:] 试试这个程序能通过测试吗？ #include <stdio.h>  int main() { 	int n, v1, v2; 	while ( scanf("%d%d%d", &n, &v1, &v2)==3 ) 	{ 		if ( 5*v1-(n+5*v2)>=0 ) 			printf("Jerry GG!\n"); 		else if ( (n+6*v2)-5*v1 >n ) 			printf("Jerry win!\n"); 	} 	return 0; }  虽然我没有运行 但是一看就感觉你的代码不行   从头到尾就没有出现时间，一秒定胜负还是5秒定胜负？[/quote] 关键在于数学模型，只要建立好了数学模型，你会发现，这个与时间没有什么直接关系。[/quote]   引用 4 楼 5250 的回复:#include <stdio.h> int main() {     int n, v1, v2;     while (scanf("%d %d %d", &n, &v1, &v2))     {         int t = 0; //时间         while (1)         {             if(v1 <= v2){                  //如果tom速度比jerry慢，那么tom永远无法追上jerry                 printf("jerry win\n");                 break;             }              if ( (v1 * (t - t / 5)) >= (v2 * (t+t/5) + n) )     //反之，如果tom速度快，那么tom总会追上jerry,即使可能会过很久很久             {                 printf("after %d second jerry GG\n",t);                 break;             }             else                 t++;         }     }     return 0; }  改一下  if ( (v1 * (t - t / 5)) >= (v2 * t + n) )

引用 2 楼 5250 的回复:[quote=引用 1 楼 user-3 的回复:] 试试这个程序能通过测试吗？ #include <stdio.h>  int main() { 	int n, v1, v2; 	while ( scanf("%d%d%d", &n, &v1, &v2)==3 ) 	{ 		if ( 5*v1-(n+5*v2)>=0 ) 			printf("Jerry GG!\n"); 		else if ( (n+6*v2)-5*v1 >n ) 			printf("Jerry win!\n"); 	} 	return 0; }  虽然我没有运行 但是一看就感觉你的代码不行   从头到尾就没有出现时间，一秒定胜负还是5秒定胜负？[/quote] 关键在于数学模型，只要建立好了数学模型，你会发现，这个与时间没有什么直接关系。

引用 1 楼 user-3 的回复:试试这个程序能通过测试吗？ #include <stdio.h>  int main() { 	int n, v1, v2; 	while ( scanf("%d%d%d", &n, &v1, &v2)==3 ) 	{ 		if ( 5*v1-(n+5*v2)>=0 ) 			printf("Jerry GG!\n"); 		else if ( (n+6*v2)-5*v1 >n ) 			printf("Jerry win!\n"); 	} 	return 0; }  虽然我没有运行 但是一看就感觉你的代码不行   从头到尾就没有出现时间，一秒定胜负还是5秒定胜负？


Question: 求助 简单字符串加密

明文，每个字符+3得到密文。

位移。左移，右移。

你的代码: --------------------- void secret(char s1[],char s2[] ) { 	while(*s1){ 		*s2=*s1+3; 		s1++,s2++; 	} }

遍历字符串s1,每个字符+1（或别的）赋值给s2 比如：       while (s1[i] != '\0')       {             s2[i] = s1[i] + 1;             i++;       }       s2[i] = '\0'; 类似这样


Question: 【小白求教】F8单步运行问题

引用 1 楼 user-1的回复:先加断点，再按F5 好的，谢谢大佬！

先加断点，再按F5


Question: n=strlen(s);出现错误，求助

#include<stdio.h> #include <string.h>  void input(char s[],int len) {     fgets(s, len, stdin); }  void show(char s[]) {     puts(s); }  void FanXuCunFang(char s[]) {     int i,n;     char s_temp[100];      n=strlen(s);     for(i=0;i<n;i++)     {         s_temp[i]=s[n-i-1];     }      for(i=0;i<n;i++)     {         s[i]=s_temp[i];     } }  int main() {     char s[100];     printf("请输入非中文字符串：\n");     input(s, 100);     printf("您输入的是：\n");     show(s);     printf("反序存放……………………\n");     FanXuCunFang(s);     printf("反序存放后输出：\n");     show(s);     return 0; } 供参考～  出现编译错误是因为缺少头文件<string.h>

出啥错？是不是头文件没导进来？ #include <string.h>


Question: 为什么课本上可以运行，实践却不可以(小白刚学c语言)

那就将 void 全改为 int。

引用 6 楼 Tryagain2006的回复:修改为下面这样就应该没有问题了。 #include"stdio.h" void printstar() { 	printf("********\n"); } void print_message() { 	printf("how do you do\n"); } int main() { 	printstar(); 	print_message(); 	printstar(); 	return 0; } 谢谢，老师说我们用的在线编程环境不可以用void main（）

void main()这种写法不是标准的写法，建议还是按标准 int main()这种写法

引用 3 楼 自信男孩的回复:代码没什么问题，楼主的问题是编译不过?（因为main的返回值类型是void，试试改成int） 还是编译好了不能运行？（是因为缺少system("pause");？） 我问过老师了，老师说网络编程环境不支持void，谢谢

引用 1 楼 魂灵L的回复:  你在说啥？ 课本上的代码，完全抄下来却不可以运行

你在说啥？


Question: 用【递归法】将一个整数n换成字符串。例如，输入483，应输出字符串  4  8  3（%4c输出）。注意，n的位数不确定，可以是任意位数的整数、

// 算法 void trans(int num) {  trans(num%10);  printf("%d,num/10); }  大概就是这样了。

引用 2 楼 Tryagain2006的回复://用【递归法】将一个整数n换成字符串。例如，输入483，应输出字符串 4 8 3（%4c输出）。 //注意，n的位数不确定，可以是任意位数的整数、 #include <stdio.h> int zhuanhuan(int); int zhuanhuan(int n) { 	if (n<0) 	{	printf("-"); 		n = -n; 	} 	if ( n>=0 && n<=9 )  	{	printf("%4d", n);		//咱用 %4d不好吗？  	} 	else 	{	zhuanhuan( n/10 ); 		printf("%4d", n%10); 	} 	return 0; } int main() { 	int n; 	scanf("%d", &n); 	zhuanhuan(n); 	return 0; } 谢谢，已了解。

483/10=48 余3,3就出来了 48/10=4 余8,8就出来了 4/10=0余4,4就出来了 一次类推