65,208
社区成员
发帖
与我相关
我的任务
分享//#pragma comment(lib, "netapi32.lib")
#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <lm.h>
int main()
{
LPUSER_INFO_0 pBuf = NULL;
LPUSER_INFO_0 pTmpBuf;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
NET_API_STATUS nStatus;
do
{ nStatus = NetUserEnum((LPCWSTR) NULL, 0, FILTER_NORMAL_ACCOUNT, (LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) // If the call succeeds,
{
if ((pTmpBuf = pBuf) != NULL) //疑问1:此处为什么判断!= NULL 外层if已经判断了If the call succeeds, 这个值就肯定不会是空啊?为啥要多此一举?
{
for (DWORD i = 0; (i < dwEntriesRead); i++) // Loop through the entries.
{
assert(pTmpBuf != NULL); //疑问2:这句话是什么意思 我觉得好像不起作用
if (pTmpBuf == NULL) //疑问3: 我觉的应该此处没有为空的可能性啊
{
fprintf(stderr, "An access violation has occurred\n");
break;
}
wprintf(L"%s\n", pTmpBuf->usri0_name); // Print the name of the user account.
pTmpBuf++;
}
}
}
// Free the allocated buffer.
if (pBuf != NULL)
{
NetApiBufferFree(pBuf);
pBuf = NULL; //疑问4:这里如果不设pBuf = NULL,有严重后果吗?
}
}
// Continue to call NetUserEnum while there are more entries.
while (nStatus == ERROR_MORE_DATA); // end do
// Check again for allocated memory. 疑问5:循环体里面不是每次都释放了吗 最后在释放有必要吗?
if (pBuf != NULL) NetApiBufferFree(pBuf);
return 0;
}
#include <stdio.h>
#include <windows.h>
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
int main()
{
LPUSER_INFO_0 pBuf = NULL;
LPUSER_INFO_0 pTmpBuf;
NET_API_STATUS nStatus;
DWORD dwEntriesRead = 0, dwTotalEntries = 0, dwResumeHandle = 0;
do
{ nStatus = NetUserEnum((LPCWSTR) NULL, 0, FILTER_NORMAL_ACCOUNT, (LPBYTE*)&pBuf, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) // If the call succeeds,
{
pTmpBuf = pBuf;
for (DWORD i = 0; (i < dwEntriesRead); i++) // Loop through the entries.
{
wprintf(L"%s\n", pTmpBuf->usri0_name); // Print the name of the user account.
pTmpBuf++;
}
}
if (pBuf != NULL){NetApiBufferFree(pBuf); pBuf = NULL;} // Free the allocated buffer. 保留这句好
}while (nStatus == ERROR_MORE_DATA);
//if (pBuf != NULL) NetApiBufferFree(pBuf); // Check again for allocated memory. 还是保留这句好呢 不是说重复了吗
return 0;
}
理解和讨论之前请先学会如何观察!
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……
对学习编程者的忠告:
多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
代码功能归根结底不是别人帮自己看或讲解或注释出来的;而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。
提醒:再牛×的老师也无法代替学生自己领悟和上厕所!
单步调试和设断点调试(VS IDE中编译连接通过以后,按F10或F11键单步执行,按Shift+F11退出当前函数;在某行按F9设断点后按F5执行停在该断点处。)是程序员必须掌握的技能之一。
引发如此大的误会