c++类的成员函数返回结构体的问题

我写了一个类,在类的头文件中定义了一个结构体,在类的实现中对结构体进行了操作,然后我留了一个接口,用于获取类中定义的结构体的值,但是这个接口函数在返回结构体时报错了,我是个小白,看了半天不知道哪儿出错了,想请教一下各位大佬,麻烦给我答疑,谢谢!(之前发过一次,一张图片没传上来)
这是头文件图片说明
这是头文件的实现
图片说明
主要就是返回结构体那个函数有问题,Qt提示是:
analyze.cpp:109:24: error: incomplete result type 'struct Header' in function definition
analyze.h:15:12: note: forward declaration of 'Header'

analyze.cpp:110:13: error: no viable conversion from 'Analyze::Header' to incomplete type 'struct Header'
analyze.h:15:12: note: forward declaration of 'Header'

我查了半天也没有查出所以然来

1个回答

class Analyze
{
public:
    struct Header;      //在使用之前声明结构体
    Header getHeader();

private:
    struct Header {     //定义
    };
    Header header;

};
Analyze::Header Analyze::getHeader()        //访问内部结构体
{
    return header;
}
WangYun_me
WangYun_me 谢谢,确实需要在用之前声明结构体。
6 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
c++类的成员函数返回结构体的问题
我写了一个类,在类的头文件中定义了一个结构体,在类的实现中对结构体进行了操作,然后我留了一个接口,用于获取类中定义的结构体的值,但是这个接口函数在返回结构体时报错了,我是个小白,看了半天不知道哪儿出错了,想请教一下各位大佬,麻烦给我答疑,谢谢!(之前发过一次,一张图片没传上来) 这是头文件![图片说明](https://img-ask.csdn.net/upload/201907/21/1563697696_467931.png) 这是头文件的实现 ![图片说明](https://img-ask.csdn.net/upload/201907/21/1563697714_537410.png) 主要就是返回结构体那个函数有问题,Qt提示是: analyze.cpp:109:24: error: incomplete result type 'struct Header' in function definition analyze.h:15:12: note: forward declaration of 'Header' analyze.cpp:110:13: error: no viable conversion from 'Analyze::Header' to incomplete type 'struct Header' analyze.h:15:12: note: forward declaration of 'Header' 我查了半天也没有查出所以然来
c++类的成员函数返回在类中定义的结构体的问题
我写了一个类,在类的头文件中定义了一个结构体,在类的实现中对结构体进行了操作,然后我留了一个接口,用于获取类中定义的结构体的值,但是这个接口函数在返回结构体时报错了,我是个小白,看了半天不知道哪儿出错了,想请教一下各位大佬,麻烦给我答疑,谢谢! 这是头文件 ![图片说明](https://img-ask.csdn.net/upload/201907/21/1563697402_605751.png) 这是头文件的实现
c++通过成员函数指针 跨DLL回调的问题
最近写了个项目,里面遇到了一个函数跨模块回调的问题,由于项目本身比较复杂,所以简化了一下,但是还是能反映问题的。 问题大致是这样: 我从主程序(exe)中调用一个DLL(称为D)中的类,这个类又调用另一个DLL(称为B)中的类,在每一级的调用之前都已经传入了一个函数指针, 在B执行完之后通过回调返回到上一个DLL(D),然后再通过回调最后返回到主程序。但是在从B返回到D之后,D的数据好像变了,导致D最终无法返回主程序。 更具体一点: D是依赖于B的,而主程序对B和D都依赖。 回调我是通过类的成员函数指针: ``` typedef void(Object::*CallBack)(...); ``` 通过一个结构体来保存函数指针和该函数所属的对象。 ``` typedef struct { Object* object; CallBack method; } EventHandler; ``` 代码片段在这里: https://code.csdn.net/snippets/693435 项目地址: https://code.csdn.net/jomoonrain2/c-lab 我觉得最有问题是我定义的这个函数指针。 但是问题是如果我没有跨DLL的话,貌似这样是没问题的。我知道跨模块调用应该挺复杂,虽然可以想其他的办法,但是这个问题如果搞不明白,吃饭都不香。。。 希望各路高手不嫌弃我这仅有的60币,不吝赐教。
C++编程新手求解:结构体与数组问题?
``` #include <iostream> using namespace std; struct bits1 //位域结构体 { unsigned char a : 1; //整数范围0~1 unsigned char b : 3; //整数范围0~7 unsigned char c : 4; //整数范围0~15 }; struct bits2 { unsigned short a : 1; //整数范围0~1 unsigned short b : 3; //整数范围0~7 unsigned short c : 4; //整数范围0~15 }; void main( ) { cout << "bits1: " << sizeof (bits1)*8 << endl; cout << "bits2: " << sizeof (bits2)*8 << endl; bits2 bit, *pbit = &bit; //定义结构体指针 bit.a = 1; bit.b = 7; bit.c = 15; cout << bit.a << " " << bit.b << " " << bit.c << endl; pbit->a = 0; pbit->b = 0; pbit->c = 0; //指针访问成员 cout << pbit->a << " " << pbit->b << " " << pbit->c << endl; system("pause"); } ``` 请对上面的程序作出以下修改: (1)写一个输出函数,输出各个data,使其不在main 中输出。函数原型为: void showNodeData( NODE *head ) ; (2)写一个逆序输出函数,以逆序输出各个NODE 的data 值。函数原型为: void reverseShowNodeData( NODE *head ) ;如果需要额外空间,请在本函数中动态分配及释放。 (3)写一个均值函数,计算各个data 的均值并返回。函数原型为:double averageNodeData( NODE *head ) ; (4)写一个查找函数,在各个data 中查找某个值KEY。函数原型为:NODE * searchNodeData( NODE *head, int KEY ) ;如果找到了,返回该NODE 地址并输出data;如果没找到,返回NULL 指针。 (5)写一个插入函数,在第K 个位置插入一个newNODE。函数原型为: bool InsertNode( NODE *head, int K, NODE *newNODE ) ;在main 函数中为newNODE 分配空间并赋值data(data 值自定)。如果插入成功返回true,并输出各个data 以证明插入成功。失败返回false。插入成功、失败的条件是什么? (6)写一个删除函数,删除第K 个位置上的NODE。函数原型为:bool DelNode( NODE *head, int K ) ; 如果删除成功,释放该NODE 内存并返回true,输出各个data 以证明删除成功。如果删除失败,给出提示信息并返回false。 (7)原题new 分配的所有NODE 内存都没有释放,编一个释放函数,原型如下:void DelList( NODE *head ) ; C++新手求各路大神解答,定感恩不尽!
C++课程设计 求大神帮忙写下构造函数和析构函数
1.网格世界类 网格中每个元素存放各种生物对象的指针或者为空。模拟过程中,我们需要移动生物,还有繁殖和饥饿(死亡),所以在网格类中,我们可以将一只生物放到网格中;可以读取网格中的某个指定位置的生物,获取它的指针,以便在每一个time step中对它进行处理(移动、繁殖和饥饿死亡)。在一个time step中,网格中每只生物都要处理一遍,先狮蚁,后蚂蚁。另外,应该有一个显示网格的成员函数。 2.有机生物类 生物要能够放到网格中,所以每一只生物都有相关的函数。可以是构造函数,即构造生物的时候,同时指明放到网格的哪一个位置上。 有Move函数,Breed函数,Starve函数(是否饿死)。这些函数在派生类中有派生类自己的实现。所以,在有机生物类中,这些函数应该是纯虚函数,有机生物类是一个抽象类。 网格世界类中,从某个网格位置读取生物并处理时,需要知道是哪一种类型的生物(是狮蚁还是蚂蚁),所以,有机生物类里应该考虑如何返回生物的类型。简单的办法是,用不同的常量来表示狮蚁和蚂蚁。例如,用整数1表示狮蚁,2表示蚂蚁。在有机生物类中定义纯虚函数GetType,返回生物的具体类型。 3.蚂蚁类 实现Move函数,Breed函数,Starve函数和GetType函数。 4.狮蚁类 实现Move函数,Breed函数,Starve函数和GetType函数。 (二)细化: 1.网格世界类: (1)属性。数据结构:网格世界中如何存放蚂蚁或狮蚁对象? 20*20的网格,用一个20*20的二维数组来表示,数组元素是什么类型? (2)方法。网格世界类应该有哪些成员函数? 构造函数:初始化网格。 析构函数:释放掉所有生物。 Set函数:指定x,y位置(二维数组的下标),以及一只生物的地址(指针),将这只生物存入网格中。 Get函数:获取网格中x,y坐标上的生物的地址(指针)。 OneStep函数:在一个time step中,网格中每只生物都要处理一遍,包括移动、繁殖和饥饿。首先,把网格中的每一只生物在本轮是否移动过的标记moved先都标记为假(为什么?);其次,移动,先狮蚁,后蚂蚁,同时把该生物的moved标记为真;再次,把饥饿的狮蚁消灭掉;最后,繁殖。 Display函数:显示函数,显示网格中的具体情况。每个网格,如果是空,显示”.”;如果是蚂蚁,显示”o”;如果是狮蚁,显示”x”。 2.有机生物类 (1)属性 要记录每只生物的一些基本属性:属于哪个网格对象,具体在哪个位置上(x,y坐标),本轮是否移动过。另外,为了记录是否到了繁殖时间,要有一个跟踪器,即记录上次繁殖之后,又经历了多少次time step。 (2)方法 构造函数: 带参数的构造函数:指定网格对象和x、y位置,把构造的生物放到网格中。 析构函数: Move函数,Breed函数,Starve函数和GetType函数为纯虚函数。 3.蚂蚁类 (1)属性 不需要再添加属性。 (2)方法 构造函数: 带参数的构造函数:指定网格对象和x、y位置,把构造的蚂蚁放到网格中。 析构函数: Move函数:随机选择一个方向,看是否能移动,否则保持在原位置。 Breed函数:繁殖跟踪器+1.如果是3的倍数,就需要繁殖,同时跟踪器清零。 Starve函数:本模拟中蚂蚁不会饿死,所以仅返回false值即可。 GetType函数:返回蚂蚁的类型标记。 4.狮蚁类 (1)属性 狮蚁会饿死,需要添加一个属性,跟踪记录狮蚁饥饿了多少次time step。 (2)方法 构造函数: 带参数的构造函数:指定网格对象和x、y位置,把构造的狮蚁放到网格中。 析构函数: Move函数:若有相邻蚂蚁,移动到单元网格,吃掉蚂蚁;否则,随机选择一个方向,看是否能移动,不能移动则保持在原位置。 Breed函数:繁殖跟踪器+1,如果是8的倍数,就需要繁殖,同时跟踪器清零。 Starve函数:饥饿跟踪器+1,如果是3的倍数,则饥饿并死亡,从网格中拿掉该狮蚁,同时跟踪器清零。 GetType函数:返回狮蚁的类型标记。 四、其它 (一)所有涉及的常量定义为类型常量。如: const int ANTBREED = 3; //蚂蚁的繁殖周期为3个time steps const int DOODLEBREED = 8; //狮蚁的繁殖周期为8个time steps 初始化网格世界时,用的狮蚁只数和蚂蚁只数,分别为5只和100只,也定义为类型常量。如: const int INITIALANTS = 100; const int INITIALBUGS = 5;
Delphi 调用C++ dll 回调函数
用Delphi 调用容联云通信的动态库CCPAppClient.DLL,其中有一个函数 Function CCPinit( CallbackInterface: CCPCALLBACKINTERFACE ):Integer;stdcall; 参数CCPCALLBACKINTERFACE 是一个结构体指针,包含 onConnected , onConnectError 等回调函数。 在调用函数CCPinit调用成功后(返回值0),会触发CCPCALLBACKINTERFACE 结构体中的回调函数onConnected 这部分代码用Delphi如何写?麻烦高手给看一下 下面是C#的demo CCPCall.instance.loginInterface = this; string ret = CCPCall.instance.LoginCCP(); if (ret != null) { MessageBox.Show(ret, "登录失败", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); } else { login_btn.Enabled = false; login_btn.BackgroundImage = Resources.bluebutton_disable; login_btn.ForeColor = Color.White; login_btn.Text = "登录中...请稍后"; } public delegate void LoginDelegate(); #region ILoginInterface 成员 public void onConnected() { LoginDelegate connected = delegate() { IMDBAccess.CreateIMMessageTable(); IMDBAccess.CreateGroupNoticeTabel(); this.Hide(); new MainForm().Show(); }; this.BeginInvoke(connected); } public void onConnectError(CloopenReason reason) { LoginDelegate error = delegate() { login_btn.Enabled = true; login_btn.BackgroundImage = Resources.bluebutton_normal; login_btn.Text = "登录"; }; login_btn.BeginInvoke(error); } #endregion ```
窗口类应用程序已经编译成功,为什么显示一直在连接,就是没有界面出来,是什么问题
``` #include<windows.h> #include<stdio.h> //声明窗口过程函数 LRESULT CALLBACK WinSunProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); //编写WinMain函数 int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )//注意没有冒号 { //设计窗口类,给所有成员赋值 WNDCLASS wndcls;//WNDCLASS 为窗口类名,wndcls为窗口类对象,接下来为WNDCLASS里的每一个成员赋值 wndcls.cbWndExtra =0; wndcls.cbClsExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//用GetStockObject这个函数从库里选择一个黑色的现成的黑色画刷 wndcls.hCursor =LoadCursor(NULL,IDI_ERROR);//用这个函数从库里获取一个图标,前参数为句柄,后者是句柄类型 wndcls.hInstance =hInstance;//WinMain函数里有个当前应用程序句柄,当调用WinMain函数是,它就会传过来一个应用程序句柄 wndcls.lpfnWndProc =WinSunProc;//将窗口过程函数的名字赋给他,因为函数的名字就是一个指针(地址),注意不是窗口类的名字 wndcls.lpszClassName ="liquanfu2009"; wndcls.lpszMenuName =NULL; wndcls.style =CS_HREDRAW|CS_VREDRAW; //注册窗口类 RegisterClass(&wndcls);//用RegisterClass这个函数注册,将设计的窗口类的对象Wndcls的地址传给这个函数 //创建窗口 HWND hwnd; hwnd=CreateWindow("liquanfu2009","我的窗口",WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//WS_OVERLAPPWDWINDOW是要显示的窗口的样式 //显示窗口 ShowWindow(hwnd,SW_SHOWNORMAL);//SW_SHOWNORMAL是显示的方式 //更新窗口 UpdateWindow(hwnd); //消息循环 MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } /////////////// //窗口过程函数的定义 LRESULT CALLBACK WinSunProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case WM_CHAR: char szChar[20]; sprintf(szChar,"char code is %d",wParam);//第一个szChar 是指对这个数组进行格式化,然后把WPARAM这个东西格式化它 MessageBox(hwnd,szChar,"char",0);//弹出消息框,有四个参数,这个消息框函数用于输出字符数组的内容输出,由平台SDK提供函数,第一个参数是要显示的窗口句柄,第二个是输出内容,三是消息的标题,四是输出的样式 break; case WM_LBUTTONDOWN://鼠标左键的按下的消息 MessageBox(hwnd,"mouse clicked","message",0); HDC hdc;//用HDC结构体定义一个对象 hdc=GetDC(hwnd);//返回一个HDC对象 TextOut(hdc,0,50,"My window",strlen("My window"));//调用这个函数在窗口输出内容,参数一是HDC对象,二和三是显示的位置,四是内容,五是内容的长度 //获取DC后要释放DC ReleaseDC(hwnd,hdc); break; case WM_PAINT:// HDC hDC;//定义对象 PAINTSTRUCT ps;//定义对象 hDC=BeginPaint(hwnd,&ps);//返回值是hDC,这个函数只能在相应WH_PAINT类消息中使用,和下面的EndPaint配套使用 TextOut(hDC,0,0,"My program",strlen("My program")); EndPaint(hwnd,&ps); case WM_CLOSE://关闭窗口的消息 if(IDYES==MessageBox(hwnd,"do you quit?","message",MB_YESNO))//MB_VESNO提供两个按钮,是和否,返回YES或NO DestroyWindow(hwnd);//当选择确定时消除窗口 break; case WM_DESTROY://退出消息 PostQuitMessage(0);//向应用程序发出退出的消息 break; default://都不是以上的消息类型 return DefWindowProc(hwnd,uMsg,wParam,lParam);//调用默认的窗口过程函数 } return 0;//结束整个函数 } ``` ![图片说明](https://img-ask.csdn.net/upload/201602/21/1456024121_285707.png)
C语言编译执行返回255(0xFF)且时间为2秒多是怎么回事?
线性表顺序存储结构实现,内含int数组成员的结构体声明为指针类型,调用初始化函数x给其中的数组成员赋值时,编译执行非常慢,且printf无法输出内容。 返回结果: Process returned 255 (0xFF) execution time 2.144s 代码片段如下: ``` #include <stdio.h> #define OK 1 #define ERROR 0 #define ERROR_EXIT -1 #define MAXSIZE 30 typedef int Status; typedef int ElemType; typedef struct { ElemType data[MAXSIZE]; int len; }*SQLIST; Status listInit(SQLIST L) { int len = 10; int i = 0; for(;i<len;i++) { L->data[i] = i; // 这行导致程序问题,请指教 } L->len = 10; return OK; } Status listShow(SQLIST L) { return OK; } int main() { SQLIST L; listInit(L); printf("%d\n",L->len); return OK; } ```
WM_WINDOWPOSCHANGING消息中的WINDOWPOS->flags成员怎么清除相应位SWP_DRAWFRAME???
**WM_WINDOWPOSCHANGING消息备注:** 对于具有WS_OVERLAPPED或WS_THICKFRAME样式的窗口,DefWindowProc函数将WM_GETMINMAXINFO消息发送到窗口。 这样做是为了验证窗口的新大小和位置,并强制执行CS_BYTEALIGNCLIENT和CS_BYTEALIGNWINDOW客户端样式。 通过不将WM_WINDOWPOSCHANGING消息传递给DefWindowProc函数,应用程序可以覆盖这些默认值。 在处理此消息时,修改WINDOWPOS中的任何值会影响窗口在Z顺序中的新大小,位置或位置。应用程序可以通过设置或清除WINDOWPOS的flags成员中的相应位来阻止对窗口的更改。 **WINDOWPOS结构成员flags描述** flags 类型:UINT 该成员可以是以下一个或多个值。 值 含义 SWP_DRAWFRAME 0×0020 在窗口周围绘制一个框架(在窗口的类描述中定义)。与SWP_FRAMECHANGED标志相同。 SWP_FRAMECHANGED 0×0020 即使窗口的大小未更改,也会向窗口 发送WM_NCCALCSIZE消息。如果未指定此标志,则仅在更改窗口大小时发送WM_NCCALCSIZE。 ``` case WM_NCCALCSIZE:return 0; case WM_WINDOWPOSCHANGING: { WINDOWPOS *pos = (LPWINDOWPOS)lParam; pos->flags;//怎么清除相应位SWP_DRAWFRAME??? return 0; } ``` WM_NCCALCSIZE消息返回0后可以无边框,但是最大化时会发生位移 不正常(-8, -8)-(1374, 776), 1382x784 (最大化) 正常(0,0)-(1366,768)(最大化) 清除相应位SWP_DRAWFRAME后应该就可以实现正常,但怎么实现???
返回自定义对象时的异常
#include <iostream> #include <string> #include <vector> using namespace std; class listOperateion{ private: string * a; string * b; string pattern; public: listOperateion(){} void setList1(string * a){ this->a = a; } void setList2(string * b){ this->b = b; } string* getList1(){ return this->a; } string* getList2(){ return this->b; } static vector<string> split(string str,string pattern) { string::size_type pos; vector<string> result; str+=pattern; int size=str.size(); for(int i=0; i<size; i++) { pos=str.find(pattern,i); if(pos<size) { string s=str.substr(i,pos-i); result.push_back(s); i=pos+pattern.size()-1; } } return result; } static OutputData elementSplit( string str ) { OutputData od; vector<string> result = split(str,","); //cout<<"the result:"<<endl; int vsize = result.size(); string *str1 = new string[vsize](); for(int i=0; i<result.size(); i++) { str1[i] = result[i]; //cout<<str1[i]<<endl; } od.setA(str1); od.setB(vsize); return od; } string* dataInput() { string a; char ch1[100]; scanf("%[^\n]", ch1); a = ch1; OutputData od ; od = elementSplit(a); string *str2 = od.getA(); int vsize = od.getB(); setList1(str2); /*for (int i=0;i<vsize;i++) { cout<<str2[i]; }*/ return str2; } }; class OutputData{ private: string * a ; int b; public: OutputData(){} void setA(string * a){ this->a = a; } string* getA(){ return this->a; } void setB(int b){ this->b = b; } int getB(){ return this->b; } ~OutputData(){} }; void main(){ listOperateion lo; lo.dataInput(); string * a = lo.getList1(); /*for (int i=0;i<a->length();i++) { cout<<a[i]; }*/ } 异常: 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(51): error C2146: 语法错误: 缺少“;”(在标识符“elementSplit”的前面) 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(51): error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(51): error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(52): error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(66): warning C4183: “elementSplit”: 缺少返回类型;假定为返回“int”的成员函数 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(41): warning C4018: “<”: 有符号/无符号不匹配 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(53): error C2146: 语法错误: 缺少“;”(在标识符“od”的前面) 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(53): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(58): warning C4018: “<”: 有符号/无符号不匹配 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(63): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(63): error C2228: “.setA”的左边必须有类/结构/联合 1> 类型是“'unknown-type'” 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(64): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(64): error C2228: “.setB”的左边必须有类/结构/联合 1> 类型是“'unknown-type'” 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(65): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(76): error C2146: 语法错误: 缺少“;”(在标识符“od”的前面) 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(76): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(77): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(78): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(78): error C2228: “.getA”的左边必须有类/结构/联合 1> 类型是“'unknown-type'” 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(79): error C2065: “od”: 未声明的标识符 1>e:\vs2010\newproject\crapt01\crapt01\t01.cpp(79): error C2228: “.getB”的左边必须有类/结构/联合 1> 类型是“'unknown-type'” c++新手**
c++程序设计,求完整程序参考
有3个学生stu[3],每个学生的数据包括学号、姓名、3门课的成绩(声明struct student结构体类型),从键盘输入3个学生的数据,要求调用子函数average求出3门课的总平均成绩(函数首部:int average(struct student *ps),函数返回值为3个学生3门课的总平均成绩,即9个成绩的平均值),调用子函数getMax找出所有成绩中最高分的学生序号,在主函数中输出三门课的总平均成绩,以及最高分学生的数据(包括学号、姓名、3门课成绩)。运行结果如图1所示,程序结构如下,请完善程序。 #include <stdio.h> struct student {//成员列表 int num; //学号 char name[20]; //姓名 float score[3]; //存放3门课成绩 }; float average(struct student *ps) // 返回3个学生的3门课的总平均成绩 { } int getMax(struct student *ps)// 返回3个学生3门课成绩中最高分的学生序号 { } void main() { struct student stu[3]; //定义其他变量 //从键盘输入3个学生的学号、姓名、3门课的成绩 //调用子函数average求出3个学生3门课的总平均成绩 //输出总平均成绩 //调用子函数getMax找出最高分的学生序号 //输出最高分学生的数据(包括学号、姓名、3门课成绩) } ![图片说明](https://img-ask.csdn.net/upload/201804/15/1523802279_242315.png)
用ctypes向dll传入的数组,返回python后,其中的数据有时正确有时错误,怎么办?
运行环境: win10 + anaconda5.3 + jupyter python文件 ``` import numpy as np import pandas as pd mylib = ctypes.cdll.LoadLibrary('mydll.dll') C_fun = mylib.func_name C_fun.restypes = None C_fun.argtypes = pass_args_Struct, c_double*10 # pass_args_Struct 是继承ctypes.Structure定义的结构体,代码略 def generate_Struct(data, 其他参数略): # 生成 pass_args_Struct,代码略 # data是个DataFrame,用于接收下面myClass的data属性 class myClass(): # myclass有个data属性,data是一个DataFrame # 其他代码略 def func1(self, x): # 删除self.data的一列,再根据x参数重新添加这一列,代码略 struct_x = generate_Struct(self.data, 其他参数略) myArr = (c_double*10)() C_fun(struct_x, myArr) npArr = np.ctypeslib.as_array(myArr,(10,)) return pd.Series(npArr, _column_names) # _column_names 定义略 def func2(self): # 生成df,df是个只有一列值的DataFrame,代码略 return df.apply(lamba x: self.func1(x[0]), axis=1, result_type='expand')) # 其他代码略 ``` mydll.dll中的代码 ``` #define API extern "C" __declspec(dllexport) typedef pass_args_Struct { // 对应于python中pass_args_Struct,代码略 } API void func_name(pass_args_Struct* x, double arr[]) { // 对arr进行一些操作,代码略 } ``` 在jupyter中: 导入前述Python文件并生成 myObject=myClass() 之后, 执行ret1 = myObject.func1()没什么问题, 但是ret2 = myObject.func2()的结果则有时正确有时错误,错误的时候,ret2中会出现一些NaN值和错误的值。 之前把generate_Struct()定义成myclass的一个方法,连ret1也会出错; 之前的func1(self, x)中采用: ``` func1(self, x): # 其他代码略 myArr = np.ctypeslib.as_array(myArr,(10,)) # 左边不用新名而直接用myArr return pd.Series(myArr, _column_names) ``` 则ret1会频繁出错,基本上是对一次就错一次。 程序一直能运行,只是结果有时不正确。 请教各位大牛,正确的写法是什么样子的? ==================================================== =====2018年11月30日更新==================================== 我可能发现问题了: Python文件TestX.py(放在PYTHONPATH下): ``` import numpy as np from ctypes import Structure, c_double, c_int, POINTER class struct_args(Structure): _fields_ = [('data',POINTER(c_double*2)), ('rows',c_int)] class test(): def __init__(self): self.data = None def get_args_2C(self): arr = np.ascontiguousarray(self.data[['foo','bar']].values, dtype=np.float) rows = c_int(arr.shape[0]) return struct_args(arr.ctypes.data_as(POINTER(c_double*2)), rows) ``` 在jupyter中: ``` import TestX import pandas as pd import numpy as np mydata = pd.DataFrame(np.arange(1600).reshape(800,2),columns=['foo','bar']) # 行数不要太小 mytest = TestX.test() mytest.data = mydata args = mytest.get_args_2C() np.ctypeslib.as_array(args.data,(800,)) ``` 输出的值经常是错误的。 ==================================================== =====2018年12月3日更新==================================== 不知道为什么,但总算是不出错了: python文件: ``` from ctypes import Structure,POINTER,c_double def Struct_A(ctypes.Structure): _fields_ = [(), # 其他成员略 ('my_arr',POINTER(c_double)] # 这个地方用c_double*10后面也会出错 class myClass(): def makeStructA(self, 其他参数): arr = (c_double*10)() SA = Struct_A(……,arr) # 其他成员略 return SA def myMethod(self, 其他参数): SA = self.makeStructA(其他参数) # myCfun是dll中的函数,功能是利用SA中数据进行一些计算,然后把结果写入SA.my_arr,具体代码略 myCfun(SA) ret = pd.Series(np.ctypeslib.as_array(SA.my_arr,(10,)), _columns_name) ret['odd'] = 1 # 这里随便新加点什么就不会出错了 return ret ``` 以上代码如果没有ret['odd']=1那一行,则myObject.myMethod()返回的Series中都是错误的值(看着像是内存未初始化,比如-2.24934335e308之类),而随便给ret添加点什么内容,返回值就是正确的了。 但是在以下计算中仍然会出错,只是出错的频率变小了,而且多运行几次就会正确: ``` class myClass(): # 接上文 def myOptimize(self, arg_name, arg_range): ret = pd.DataFrame({arg_name:arg_range}) _optimize = lambda arg: self.myMethod(**{arg_name:arg[arg_name]}) return ret.join(ret.apply(_optimize, axis=1, result_type='expand')) ``` ===================================== =====2018年12月7日更新==================================== 又出错了!!!12月3日写的: ``` ret['odd'] = 1 # 这里随便新加点什么就不会出错了 ``` 那个函数确实不出错了,但是别的函数用同样的写法(先生成c_double*shape再传入dll在C中写入值)得到的ret无论添加行还是添加列,多运行几次总会出错(内存被清理)。 换一种写法: ``` 略 arr=np.zeros(shape) 略 # 然后传入arr.ctypes.data_as(POINTER(c_double*10)) ``` 目前暂时不出错了。 =====2018年12月13日更新==================================== 前面的写法有问题:用函数生成结构体(比如makeStructA)再传递给dll就会出错,直接将makeStuctA的代码放到myMethod中就不会出错。 另外,传递结构体时用byref就不会出错了,在dll中用malloc给结构体的成员赋值都不会出错。
运行到广度优先遍历函数调用队列时就出问题
#include<iostream> using namespace std; /*********************各类定义******************************/ class Node//基本抽象数据类型 { public: char ch; //记录名称,如果将这里改成数组,结点名称可以是多个字符 int flag;//记录结点是否被访问 }; class Graph //图类,此类中,封装了图的一些成员和一些必须的成员函数 { private: int getSub(char); //获取某名称的下标 Node* arrNode; //记录名称和是否访问的数组 int numVertex,numEdge;//记录图的顶点数和边数 int **matrix; //用一个二维数组记录两点间是否相连,1相连,0断开 public: void setCh(char,int); //将数组的arrNode的每一个单元设置一个结点名称 Graph(int); ~Graph(); int getNumVertex();//获得图的顶点数 char first(char ch);//获得相邻结点 char next(char ch1,char ch2);//获得隔着ch2,但与ch2相邻的结点 void setEdge(char,char,int w=1);//设置两顶点的边和权重(权重默认为1) void eraserEdge(char,char); void outPut(); int getMark(char);//获取是否被访问的记录,已访问返回1,未访问返回0 void setMark(char);//把已访问的结点,设置标记 }; template<class T> class myQueue { private: int theFront; // 1 counterclockwise from theFront element int theBack; // position of theBack element int arrayLength; // queue capacity T *queue; // element array public: myQueue(int initialCapacity = 10); ~myQueue() {delete [] queue;} bool empty() const {return theFront == theBack;} int size() const {return (theBack - theFront + arrayLength) % arrayLength;} T& front() {// return front element /*if (theFront == theBack) throw queueEmpty();*/ return queue[(theFront + 1) % arrayLength]; } T& back() {// return theBack element /*if (theFront == theBack) throw queueEmpty();*/ return queue[theBack]; } void pop() {// remove theFront element /*if (theFront == theBack) throw queueEmpty();*/ theFront = (theFront + 1) % arrayLength; queue[theFront].~T(); // destructor for T } void push(const T& theElement); }; /*************各函数的函数体*****************************/ Graph::Graph(int n) { int i,j; arrNode=new Node[n]; numVertex=n; numEdge=0; for(i=0;i<numVertex;i++) arrNode[i].flag=0; matrix=new int*[numVertex]; for(i=0;i<numVertex;i++) matrix[i]=new int[numVertex]; for(i=0;i<numVertex;i++) for(j=0;j<numVertex;j++) matrix[i][j]=matrix[j][i]=0; } Graph::~Graph() { delete [] arrNode; for(int i=0;i<numVertex;i++) delete [] matrix[i]; delete [] matrix; } int Graph::getSub(char ch) //获取下标 { for(int i=0;i<numVertex;i++) if(ch==arrNode[i].ch) return i; } int Graph::getNumVertex() //获取顶点数 { return numVertex; } char Graph::first(char ch) //获取相邻结点 { for(int i=0;i<numVertex;i++) if(matrix[getSub(ch)][i]!=0) return arrNode[i].ch; return ch; } char Graph::next(char ch1,char ch2) //获取与ch2相邻的结点 { for(int i=getSub(ch2)+1;i<numVertex;i++) if(matrix[getSub(ch1)][i]!=0) return arrNode[i].ch; return ch1; } void Graph::setEdge(char ch1,char ch2,int w) //设置边 { if(matrix[getSub(ch1)][getSub(ch2)]==0) { numEdge++; matrix[getSub(ch1)][getSub(ch2)]=matrix[getSub(ch2)][getSub(ch1)]=1; } } void Graph::eraserEdge(char ch1,char ch2) { if(matrix[getSub(ch1)][getSub(ch2)]==1) { numEdge--; matrix[getSub(ch1)][getSub(ch2)]=matrix[getSub(ch2)][getSub(ch1)]=0; } } void Graph::outPut() { for(int i=0;i<numVertex;i++) { for(int j=0;j<numVertex;j++) { cout<<matrix[i][j]<<" "; } cout<<endl<<endl;; } } int Graph::getMark(char ch)//获取访问信息 { for(int i=0;i<numVertex;i++) if(ch==arrNode[i].ch) return arrNode[i].flag; return -1; } void Graph::setMark(char ch) //设置标记 { for(int i=0;i<numVertex;i++) if(ch==arrNode[i].ch) arrNode[i].flag=1; } void Graph::setCh(char ch,int n)//将结点名称设置在字符中 { arrNode[n].ch=ch; } template<class T> myQueue<T>::myQueue(int initialCapacity) {// Constructor. /*if (initialCapacity < 1) {ostringstream s; s << "Initial capacity = " << initialCapacity << " Must be > 0"; throw illegalParameterValue(s.str()); }*/ arrayLength = initialCapacity; queue = new T[arrayLength]; theFront = 0; theBack = 0; } template<class T> void myQueue<T>::push(const T& theElement) {// Add theElement to queue. // increase array length if necessary if ((theBack + 1) % arrayLength == theFront) {// double array length // allocate a new array T* newQueue = new T[2 * arrayLength]; // copy elements into new array int start = (theFront + 1) % arrayLength; if (start < 2) // no wrap around copy(queue + start, queue + start + arrayLength - 1, newQueue); else { // queue wraps around copy(queue + start, queue + arrayLength, newQueue); copy(queue, queue + theBack + 1, newQueue + arrayLength - start); } // switch to newQueue and set theFront and theBack theFront = 2 * arrayLength - 1; theBack = arrayLength - 2; // queue size arrayLength - 1 arrayLength *= 2; queue = newQueue; } // put theElement at the theBack of the queue theBack = (theBack + 1) % arrayLength; queue[theBack] = theElement; } /***************主函数*********************/ void DFS(Graph*,char); //深度优先遍历函数声明 void BFS(Graph*,char,myQueue*); //广度优先遍历函数声明 int main() { char option; int numVer,numE,i; char temp1,temp2; //temp1,temp2作临时变量,记录输入的值 // myQueue* q=new myQueue; cout << "输入定点数和弧数:"; cin >> numVer >> numE; Graph myGraph1(numVer); Graph myGraph2(numVer); cout << "请输入" << numVer << "个顶点:\n"; for(i=0;i<numVer;i++) //将结点名称设置在数组中 { cout << "输入顶点" << i << ":"; cin >> temp1; myGraph1.setCh(temp1,i); myGraph2.setCh(temp1,i); } cout << "请输入" << numE << "条弧:\n"; for(i=0;i<numE;i++) //设置边 { cout << "输入弧" << i << ":"; cin >> temp1 >> temp2; myGraph1.setEdge(temp1,temp2); myGraph2.setEdge(temp1,temp2); } myGraph1.outPut(); while(1) { cout<<"2:删除边 "<<endl; cout<<"3: 深度遍历"<<endl; cout<<"4: 广度遍历"<<endl; cout<<"0: 退出"<<endl; cout<<"\n请输入你的选择:"; cin>>option; switch(option) { case'0': exit(0); break; case'2': { cout << "输入弧的顶点:" << endl; cin >> temp1 >> temp2; myGraph1.eraserEdge(temp1,temp2); myGraph2.eraserEdge(temp1,temp2); myGraph1.outPut(); break; } case'3': { cout << "深度优先结果:"; DFS(&myGraph1,'a'); cout<<endl; break; } case'4': { cout << "\n广度优先结果:"; //BFS(&myGraph2,'a',q); cout<<endl; break; } cout<<endl; } }cout<<endl; } void DFS(Graph* G,char ch) //深度优先遍历函数体 { int i=0; cout << ch << " "; G->setMark(ch); for(char w=G->first(ch);i<G->getNumVertex();w=G->next(ch,w),i++) if(G->getMark(w)==0) DFS(G,w); } void BFS(Graph* G,char ch,myQueue* q) //广度优先遍历函数体 { char v,w; q->push(ch); G->setMark(ch); while(q->size()!=0) { q->pop(v); cout << v << " "; int i=0; for(w=G->first(v);i<G->getNumVertex();w=G->next(v,w),i++) if(G->getMark(w)==0) { G->setMark(w); q->push(w); } } } /*输入顶点数和弧数:8 9 输入8个顶点. 输入顶点0:a 输入顶点1:b 输入顶点2:c 输入顶点3:d 输入顶点4:e 输入顶点5:f 输入顶点6:g 输入顶点7:h 输入9条弧. 输入弧0:a b 1 输入弧1:b d 1 输入弧2:b e 1 输入弧3:d h 1 输入弧4:e h 1 输入弧5:a c 1 输入弧6:c f 1 输入弧7:c g 1 输入弧8:f g 1 */
C++重载类型转换的问题
这是c++哈夫曼树的代码template<class T> class HfmTree : public BinaryTree<T> //哈夫曼树类 { public: operator T() const{ return weight; } //重载类型转换符,T a;HfmTree<T> b;a=b;//b是HfmTree类型直接转换成T类型,赋值给a T getW(){ return weight; } //返回weight void putW(const T&x){ weight = x; } //确定weight的值 void SetNull(){ root = NULL; } //置空二叉树private: T weight; }; template<class T> HfmTree<T> CreateHfmTree(T w[],char q[],int n) //构造哈夫曼树 { PrioQueue<HfmTree<T> > pq(n); //声明优先队列 HfmTree<T> x, y, z, zero; for(int i = 0; i < n; i++) { z.MakeTree(w[i], q[i], x ,y); //继承,使用父类的函数,这里每个新建的二叉树都只有空的子树和一个根节点 z.putW(w[i]); pq.Append(z);//进堆操作 z.SetNull(); }//for循环结束后,已经按照最小堆构建好了 for(i = 1; i < n; i++) { pq.Serve(x); pq.Serve(y); z.MakeTree(x.getW() + y.getW(), 'e', x, y); z.putW(x.getW() + y.getW()); pq.Append(z); z.SetNull(); }//构造哈夫曼树 pq.Serve(z); return z; } 这是优先权队列的代码template<class T> class PrioQueue //优先权队列类 { public: PrioQueue(int mSize = 20); ~PrioQueue(){ delete []q; } bool IsEmpty() const{ return n == 0; } //判断队列是否为空 bool IsFull() const{ return n == maxSize; } //判断队列是否满了 void Append(const T&x); //进队列 void Serve(T&x); //出队列private: void AdjustDown(int r, int j); void AdjustUp(int j); T *q; int n, maxSize; }; template<class T> PrioQueue<T>::PrioQueue(int mSize) { maxSize = mSize; n = 0; q = new T[maxSize]; } template<class T> void PrioQueue<T>::AdjustUp(int j) //向上调整,j是队列中最后元素的下标 { int i = j; T temp = q[i]; while (i > 0 && temp < q[(i - 1) / 2]) { q[i] = q[(i - 1) / 2]; i = (i - 1) / 2; } q[i] = temp; } template<class T> void PrioQueue<T>::Append(const T&x) //插入新元素 { if(IsFull()) { cout << "Overflow" << endl; return; } q[n++] = x; AdjustUp(n-1); } template<class T> void PrioQueue<T>::Serve(T&x) //删除堆顶元素 { if(IsEmpty()) { cout << "Underflow" << endl; return; } x = q[0]; q[0] = q[--n];//将堆底元素放到堆顶 AdjustDown(0, n-1); } template<class T> void PrioQueue<T>::AdjustDown(int r,int j) //向上调整,r是堆顶元素,j是堆底元素 { int child = 2 * r + 1; T temp = q[r]; while(child <= j) { if((child < j) && (q[child] > q[child+1]))//找到左右子树中较小的 child++; if(temp <= q[child]) break; q[(child - 1) / 2] = q[child]; child = 2 * child + 1; } q[(child - 1) / 2] = temp; } 关键就在构造哈夫曼树时,传进队列中去的是HfmTree<T>类型的数据,但是队列处理的是T类型的数据,如果operate T()这个成员函数是按照我注释那样写的,那存进去的应该是weight的值,怎么取出来还能当HfmTree<T>的数据使用?求解答,这个问题困扰我很久了。
c程序求查错 自己真找不出哪里错了
test3.cpp ``` #include<stdio.h> #include<string.h> #include<stdlib.h> #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 #define OVERFLOW 0 typedef int Elemtype; /*通讯录的结构*/ typedef struct MailList{ int num; char name[20]; char tel1[12]; char tel2[12]; char email[50]; }MailList; /*用于恢复删除信息的结构*/ typedef struct DeleteList{ MailList data; DeleteList *next; }DeleteList,*LinkList; /*顺序表的定义结构*/ typedef struct{ MailList *elem; //存储空间基址 int length; //当前长度 int Listsize; //当前分配的存储容量 }SqList; int InitList_Sq(SqList &L);//初始化通讯录 bool InitList_Delete(MailList &L);//初始化回收站 int ListIsert_Sq(SqList &L,int i,Elemtype e);//插入数据 void ShowAll(SqList &L);//显示全部通讯录内容 int deleteList(SqList &L1,int i,MailList &e);//删除某一条并以e返回 void ListInsert(LinkList &L,MailList x);//添加到回收站 void WatchList(LinkList &L);//查看回收站 bool find_int(SqList &L,int x);//按照编号查找数据 void find_char(SqList &L,char x[]);//按照姓名查找数据 bool recoverList(LinkList &L2,int n,MailList &e);//从回收站中删除并以e返回 bool ChangeList(SqList &L1,int n);//修改信息 #include"test3_Seq.h" #include"test3_Link.h" int main(void) { SqList L1; InitList_Sq(L1); LinkList L2; InitList_Delete(L2); MailList M; int i = 1; printf("请创建新的通讯录,格式为:姓名 电话1 电话2 电子邮箱。(输入数字“0”结束)\n"); while(1) { M.num = i; scanf("%s",M.name); if(M.name[0] == '0') break; scanf("%s %s %s",M.tel1,M.tel2,M.email); ListIsert_Sq(L1,M); i ++; } printf("输入成功!^_^\n"); int number; while(1){ printf("请输入数字进行相关操作\n1.查看通讯录\n2.查找通讯录\n3.添加通讯录\n4.修改通讯录\n5.删除通讯录\n6.查看已删除的通讯录\n7.恢复通讯录\n0.退出菜单\n"); scanf("%d",&number); switch(number) { case 1: ShowAll(L1); break; case 2: int n,m; char find_name[20]; printf("选择查找方式\n1.按编号查找\n2.按姓名查找\n"); scanf("%d",&n); if(n == 1) { printf("请输入编号: "); scanf("%d",&m); find_int(L1,m); } else if(n == 2) { printf("请输入姓名: "); scanf("%s",find_name); find_char(L1,find_name); } break; case 3: printf("请输入你要添加的内容: "); M.num = i; scanf("%s %s %s %s",M.name,M.tel1,M.tel2,M.email); ListIsert_Sq(L1,M); i ++; break; case 4: int c; printf("请输入你要修改的条目编号: "); scanf("%d",&c); ChangeList(L1,c); break; case 5: int a; printf("请输入你要删除的成员序号: "); scanf("%d",&a); MailList N; deleteList(L1,a,N); ListInsert(L2,N); break; case 6: WatchList(L2); break; case 7: int b; printf("请输入要还原的成员在回收站中的编号: "); scanf("%d",&b); recoverList(L2,b,M); ListIsert_Sq(L1,M); break; case 0: free(L1.elem); return 0; default: printf("请输入正确的数字!\n"); break; } } } ``` test_Link.h ``` #include<stdio.h> #include<stdlib.h> //此函数用于创建链表 int InitList_Delete(LinkList &L) { L = NULL; L = (LinkList)malloc(sizeof(DeleteList)); if(L == NULL) return 0; LinkList P = L -> next; P = NULL; return 1; } //此函数用于在链表中(回收站)插入元素 void ListInsert(LinkList &L,MailList x) { LinkList p,q; p = L; while(p->next) p = p->next; q = (LinkList)malloc(sizeof(DeleteList)); q->data = x; q->next = p->next; p->next = q; printf("删除成功!可在回收站中查看。\n"); } //此函数用于查看回收站 void WatchList(LinkList &L) { LinkList p; p = L->next; while(p) { printf("%d %s %s %s %s\n",p->data.num,p->data.name,p->data.tel1,p->data.tel2,p->data.email); p = p->next; } } //此函数用于从回收站中删除数据并以e返回 int recoverList(LinkList &L2,int n,MailList &e) { LinkList p,q; int i,k = 0; q = L2->next; while(q){ q = q->next; k ++; } if(n < 1 || n > k){ printf("输入错误\n"); return 0; } p = L2; for(i = 0;i < n - 1;i ++) p = p->next; e = p->next->data; p->next = p->next->next; printf("恢复成功!\n"); return 1; } ``` test_Seq.h ``` #include<stdio.h> #include<stdlib.h> /*此函数用于初始化顺序表*/ int InitList_Sq(SqList &L) { L.elem = (MailList *)malloc(LIST_INIT_SIZE*sizeof(MailList)); //为线性表分配100个空间 if(! L.elem) exit(OVERFLOW); //如果分配失败则返回0 L.length = 0; L.Listsize = LIST_INIT_SIZE; return 1; } //此函数用于删除第i条内容 int deleteList(SqList &L1,int i,MailList &e) { if((i<1)||(i>L1.length)) { printf("请输入正确的数字!\n"); return 0; } int j; e = L1.elem[i - 1]; for(j = i;j <= L1.length -1;j ++) { L1.elem[j].num --; L1.elem[j - 1] = L1.elem[j]; } L1.length --; return 1; } /*此函数用于在顺序表末尾插入数据元素*/ int ListIsert_Sq(SqList &L,MailList e) { MailList *newbase ; if(L.length >=L.Listsize) { newbase = (MailList *)realloc(L.elem,(L.Listsize + LISTINCREMENT) * sizeof(MailList)); if(! newbase) exit(OVERFLOW); L.elem = newbase; L.Listsize +=LISTINCREMENT; } MailList *p; p = &(L.elem[L.length]); *p = e; ++ L.length; return 1; } //此函数用于显示整个通讯录内容 void ShowAll(SqList &L) { MailList* p; p = &(L.elem[0]); for (p = &(L.elem[0]);p < &(L.elem[L.length]);p ++) printf("%d %s %s %s %s\n",p->num,p->name,p->tel1,p->tel2,p->email); } //此函数用于通过编号查找成员信息 int find_int(SqList &L,int x) { if(x < 1 || x > L.length) { printf("编号不存在!\n"); return 0; } MailList *p; int i; p = &(L.elem[0]); for(i = 1;i < x;i ++) p += 1; printf("%d %s %s %s %s\n",p->num,p->name,p->tel1,p->tel2,p->email); } //此函数用于通过姓名查找成员信息 void find_char(SqList &L,char x[]) { MailList* p; int h = 0,i; p = &(L.elem[0]); for(i = 0;i < L.length;i ++) { if(strcmp(p->name,x) == 0) { printf("%d %s %s %s %s\n",p->num,p->name,p->tel1,p->tel2,p->email); h = 1; } p ++; } if(h == 0) printf("编号不存在!\n"); } //此函数用于修改成员信息 int ChangeList(SqList &L1,int n) { if(n < 1 || n > L1.length) { printf("编号不存在!\n"); return 0; } MailList *p; int i; p = &(L1.elem[0]); for(i = 1;i < n;i ++) p += 1; int s = 1; while(s != 0){ printf("请选择你要修改的信息:\n1.姓名\n2.电话1\n3.电话2\n4.电子邮箱\n0.退出\n"); scanf("%d",&s); printf("修改为:"); switch(s) { case 1: char nm[20]; scanf("%s",nm); strcpy(p->name , nm); printf("修改成功!\n"); break; case 2: char t1[12]; scanf("%s",t1); strcpy(p->tel1 , t1); printf("修改成功!\n"); break; case 3: char t2[12]; scanf("%s",t2); strcpy(p->tel2 , t2); printf("修改成功!\n"); break; case 4: char em[50]; scanf("%s",em); strcpy(p->email , em); printf("修改成功!\n"); break; case 0: return 1; default: printf("请输入正确的数字!\n"); } } } ```
如何卸载assembly?或者class
.net的动态编译功能很好,但是有个问题,动态编译的代码,每次执行后,都会产生一个新的assembly,而且无法卸载。这个动态方法执行多次之后,就会慢慢的内存泄漏。因为每个assembly都会占用内存。 google了一下,没有发现满意的答案。唯一的答案就是,把assembly放到一个appdomain里,然后所在的appdomain卸载掉。但如果这样的话,所有的东西都得通过rpc调用了,效率非常低。 从原理上来说,已经加载的class,应该是可以卸载的。不知道是否有办法调用原生的api去卸载一个已经加载的assembly。 [b]问题补充:[/b] 我的问题是,需要实现一个脚本操作的功能,对已有的数据进行处理,并且用到linq查询,然后返回查询的结果。 查询的逻辑是未知的,由客户输入脚本来实现。查询的结果是一个二维表。但是希望查询结果返回的数据结构是自描述的。为了简化问题,就用了linq的匿名对象。 现在的做法,是用动态编译的方法,用CSharpCodeProvider动态编译客户输入的那段代码,产生一个CompilerResult,这个地方的问题的实质,是需要一个编译器。现在为了省事,就调用了c#的编译器,但是后果就是每次执行一个脚本,就会生成一个Assembly。长期执行下去,内存会慢慢变少。因此希望能将这个Assembley卸载。 Expresstion Tree比较麻烦,因为问题就是要做语法分析,如果已经成了Tree就不需要做了。 感谢RednaxelaFX兄的解答,我想xie卸载程序集还是有可能的。理由是:第一,有些.net代码保护工具,就可以让clr把已经加载的类卸载,防止别人dump整个程序集。第二,Dlr的类是动态生成的。如果无法卸载动态生成的类,等着它的必定是内存泄漏。 从编程语言的发展趋势看,总的趋势是越来越灵活。开始阶段,是针对硬件的汇编,然后是对硬件的具体实现有一定抽象作用的c语言,再到有oo特性的c++,然后是继承了GC和更过oo特性的java和c#。现在的趋势是,对编程语言本身进行编程,表现就是Aop和动态语言。 动态语言,它需要的除了动态编译以为,就是对把gc的特性扩展到类的类型本身。当一个类的代码不再被需要,它也可以被GC。我以为,动态的创建和销毁代码,也是非常必要的。它实际上是未来编程语言的一个方向。 [b]问题补充:[/b] 再次感谢RednaxelaFX兄的热情解答。使我明白DLR是怎么实现的。 ironpython是个好主意。可惜我要的不仅仅是脚本,还需要linq的查询结果。如果用ironPython的话,它返回给我的是个动态类型,虽然可以动态增加删除成员,奈何我还要对返回的数据进行处理。如果不是.net的数据控件支持的类型,我还得开发一堆数据控件或者adapter去支持它的类型,比较麻烦,我还没做好成为ironpython的开发人员的心理准备。最理想的办法,就是能卸载assembly。这样工作量就是最小的。其实,不卸载也是无所谓的,因为我可以把写好的脚本缓存起来,不必每次都生成新的assembly。客户也不会无聊到写很多脚本故意把它搞崩溃。 之所以研究这个问题,纯属心理上的洁癖,想让它有个更好的解决方案。 关于.net保护工具如何让已经加载的类重新被卸载的问题,我也不知道答案,作者也没有公布。因为这可能就是他保护技术的核心。我想,如果有办法能让程序回到一个程序集加载之前的状态,就算是完成了卸载操作。如果确信程序集不再被引用,那么应该有办法完成这个操作。不过,这一定需要非常了解clr的底层结构。 .net没有提供加载的类卸载的方法,只是出于安全性的理由,这个类可能被别的代码引用,卸载了它,就可能会出现野指针。 此外,如果类可以卸载,那么有些静态构造函数的语义,可能会被改变。因为重新加载类的时候,静态构造函数可能会再次执行。 如果类也增加引用计数之类的机制,那么,类本身也应该是可以被gc的。 既然代码可以动态的创建,那为什么不可以动态的删除?既然对对象的GC可以做到,那么对类型的GC,一样可以做到。这不过是编程语言设计者观念上的问题,不是不可逾越的障碍。 静态编译,不过是为了提高运行效率而已。如果效率可以接受,那静态编译对于编程思想的表达,并不是必须的。 也就是说,动态的产生类,动态的销毁类,完全是可行的。类也不过是数据而已。
顺序表的 问题 求指教!
#include<stdio.h> #include<stdlib.h> #include<string.h> //#include"eg2_3.h" #define MAXSIZE 100 //顺序表的最大长度 typedef struct{ char* stuNo; char* stuName; char* stuSex; int mathScore; int chinScoee; }DataType; //顺序表中数据元素的类型DataType,这里假设为int //顺序表的类型 typedef struct{ DataType *data; //一维数组data用于存放表节点 int length; //线性表当前的长度 }SeqList; //初始化 void InitList(SeqList *L) { L->data=(DataType*)malloc(sizeof(DataType)*MAXSIZE); L->length=0; //元素的个数为零 } //求表长 int ListLength(SeqList *L) { return L->length; } //取值 DataType GetNode(SeqList *L,int i) { if(i<1||i>L->length) printf("位置错误\n"); return L->data[i]; } //定位 int LocateNode(SeqList *L,DataType e) { int i=1; while(i<=L->length &&!strcmp( L->data[i].stuNo,e.stuNo)) i++; if(i>L->length) return -1; else return i; } //插入 void InsertList(SeqList *L,DataType e,int i) { int j; if(i<1 || i>L->length+1) printf("位置错误\n"); if(L->length>=MAXSIZE) printf("错误,表空间溢出\n"); for(j=L->length;j>=i;j--) { L->data[j+1]=L->data[j]; L->data[i]=e; L->length++; } } void Output(SeqList *L) { int i; for(i=1;i<=L->length;i++) printf("%s\t%s\t%s\t%5d\t%5d\t\n",L->data[i].stuNo,L->data[i].stuName,L->data[i].stuSex,L->data[i].mathScore,L->data[i].chinScoee); printf("\n"); } void main() { SeqList La;//定义这种结构的顺序表La InitList(&La);//初始化这个顺序表 DataType re1,re2,re3; //定义结构类型变量 //对成员进行赋值 re1.stuNo="20121101"; re1.stuName="陈曦";re1.stuSex="男";re1.mathScore=95;re1.chinScoee=92; re2.stuNo="20121102"; re2.stuName="李晓红";re2.stuSex="女";re2.mathScore=86;re2.chinScoee=98; re3.stuNo="20121103"; re3.stuName="魏海燕";re3.stuSex="女";re3.mathScore=99;re3.chinScoee=88; //对表元素进行赋值 InsertList(&La,re1,1); InsertList(&La,re2,2); InsertList(&La,re3,3); Output(&La);//输出这个表 } 求表长和取值函数没有其他函数调用它,他们的 返回值给我谁?
int add_child(node *head) 这个语句里有错误,让整个程序正确运行
``` ```//////////////////////////////// //家谱管理系统 /////////////////////////////// #include<stdio.h> #include<stdlib.h> #include<string.h> #include<malloc.h> //创建一个结构体 struct node//结构体变量 { char family[20];//家庭成员 int generation;//辈分 node *lchild, *rchild;//左孩子是孩子,右孩子是兄弟 }; //各个功能函数声明 void Display();//显示主界面并调用功能函数 int add_child(node *head);//添加家庭成员 int add_brother(node *head);//添加兄弟成员 int beifen(node *p, char *name);//确定成员辈分 void output(node *head, char *name);//输出指定家庭成员 void preOrder(node *head);//先序遍历 输出家庭成员 void chengyuan(node *head, int name);//输出相应辈分成员 node *create();//建立祖先 void Delete(node *head, char *name);//删除成员 //////////////////////////////////////////////// //函数名: Display() //函数功能:1.显示主界面 // 2.清屏函数 // 3.调用各个功能函数 //////////////////////////////////////////////// void Display()//显示主界面 { while(1) { system("cls");//清屏 printf(" ******************************************\n"); printf(" * *\n"); printf(" * 欢迎进入家谱管理系统 *\n"); printf(" * *\n"); printf(" ******************************************\n\n"); printf(" * 1.设立家谱祖先 *\n"); printf(" * 2.添加家庭成员(孩子) *\n"); printf(" * 3.添加家庭成员(兄弟) *\n"); printf(" * 4.输出指定家庭成员 *\n"); printf(" * 5.确定成员辈分 *\n"); printf(" * 6.输出指定辈的所有成员 *\n"); printf(" * 7.删除家庭成员 *\n"); printf(" * 8.先序遍历输出家庭成员 *\n"); printf(" * 0.退出 *\n"); printf(" 提示:按相应数字进行相应操作,请先输入操作数再进行运算 \n\n"); int num;// 定义输入的序号 node *head;//定义头节点 int generation;//辈分 char name[20];//存放名字 scanf("%d", &num); if(num >= 1 && num <= 8) { system("cls");//清屏 } if(num == 0) { printf("Thank you for using!\n"); return ; } switch(num) { case 1://创建家谱 (姓名 性别 ) head = create();//调用函数 break; case 2://添加家庭成员 add_child(head);//调用函数 break; case 3://添加兄弟成员 add_brother(head);//调用函数 break; case 4://输出指定家庭成员 printf("请输入父亲节点:"); scanf("%s", &name); printf("\n成员为: "); output(head, name);//调用函数 printf("\n"); break; case 5://确定成员辈分 printf("请输入姓名:"); scanf("%s", &name); printf("辈分为:"); beifen(head, name);//调用函数 printf("\n"); break; case 6://退出 printf("请输入辈分:"); scanf("%d", &generation); printf("\n成员为: "); chengyuan(head, generation);//调用函数 printf("\n"); break; case 7: printf("请输入要删除的成员:"); scanf("%s", &name); Delete(head, name);//调用函数 break; case 8: printf("所有成员先序遍历输出:\n"); preOrder(head); break; case 0: printf("Thank you for using!\n"); break; default: printf("Input error !\n"); system("pause"); system("cls"); continue; } } } ///////////////////////////////////////////// //功能: 创建祖先 //函数名:*create ///////////////////////////////////////////// node *create()//建立祖先 { node *head;//头结点 head = (node *)malloc(sizeof(node));//分配存储空间 char name[20]; printf("输入祖先名字:"); scanf("%s", &name); strcpy(head->family, name);// 赋值 head->generation = 1;//分配辈分 printf("祖先载入成功!\n"); system("pause"); return head;//返回祖先节点(根节点) } ////////////////////////////////////////////////////// // 功能: 添加家庭成员 // 函数名: add_child // 说明: 非递归法 ////////////////////////////////////////////////////// int add_child(node *head) { char child[20], father[20];//用来储存孩子信息和父亲信息 node *pchild, *q;//定义新变量pchild为孩子,q为父亲节点 q = head; printf("输入加入父节点姓名:"); scanf("%s", &father);//输入父节点 pchild = (node *)malloc(sizeof(node));//动态分配存储空间 printf("输入要添加的孩子:"); scanf("%s", &child);//输入孩子信息 strcpy(pchild->family, child);//赋值到节点 pchild->lchild = NULL;//新节点左孩子为空 pchild->rchild = NULL;//新节点右孩子为空 while(q != NULL)//循环左孩子查找 { if(strcmp(father, q->family) == 0)//比较 { if(q->lchild == NULL)//如果此结点没有孩子则添加到左孩子 { pchild->generation = q->generation + 1;//孩子为父节点的辈分加1 q->lchild = pchild;//新节点为父节点的左孩子节点 return 1; } else//如果左结点有孩子,则找到孩子,再找到最后一个兄弟,并添加到后面 { q = q->lchild; while(q->rchild != NULL)//循环到最后一个//系统在此处有错误?会自动停止 { q = q->rchild;//兄弟指向右孩子 } pchild->generation = q->generation;//兄弟辈分相同 q->rchild = pchild;//新节点为父节点的右孩子节点 return 1; } } q = q->lchild;//指向左孩子 } q = head; while(q != NULL)//循环右孩子查找 { if(strcmp(father, q->family) == 0)//比较 { if(q->lchild == NULL)//如果此结点没有孩子则添加到左孩子 { pchild->generation = q->generation+1;//孩子为父节点的辈分加1 q->lchild = pchild;//新节点为父节点的左孩子节点 return 1; } else//如果此结点有孩子,则找到孩子,再找到最后一个兄弟,并添加到后面 { q = q->lchild; while(q->rchild != NULL)//循环到最后一个 { q = q->rchild;//兄弟指向右孩子 } pchild->generation = q->generation;//兄弟辈分相同 q->rchild = pchild;//新节点为父节点的左孩子节点 return 1; } } q = q->rchild;//指向右孩子 } //system("pchildause"); } ////////////////////////////////////////////////////// // 功能: 添加兄弟成员 // 函数名: add_brother // 说明: 非递归法 ////////////////////////////////////////////////////// int add_brother(node *head) { node *p, *s; //定义新变量 char bro[20], bro1[20];//用来储存兄弟节点和要添加的兄弟信息 p = head; s=(node *)malloc(sizeof(node));//动态分配存储空间 printf("输入加入兄弟节点姓名"); scanf("%s", &bro1);//输入兄弟节点姓名 printf("请输入要添加的兄弟:"); scanf("%s", &bro);//输入添加信息 strcpy(s->family, bro);//赋值 s->lchild = NULL;//新节点左孩子为空 s->rchild = NULL;//新节点右孩子为空 //system("pause"); while(1)//循环左孩子查找 { if(strcmp(p->family,bro1) == 0)//比较 { if(p->rchild == NULL)//如果兄弟节点为空,赋给兄弟节点 { s->generation = p->generation;//兄弟辈分相同 p->rchild = s;//兄弟为右孩子 return 1; } else//否则找到最后一个兄弟,在其后添加结点 { while(p->rchild != NULL)//循环到最后节点 { p = p->rchild;//指向下一个右孩子 } s->generation = p->generation;//兄弟辈分相同 p->rchild = s;//兄弟为右孩子 return 1; } } p = p->lchild;//指向左孩子 } p = head; while(1)//循环右孩子查找 { if(strcmp(p->family,bro1) == 0)//比较 { if(p->rchild == NULL)//如果兄弟节点为空,赋给兄弟节点 { s->generation = p->generation;//兄弟辈分相同 p->rchild = s;//兄弟为右孩子 return 1; } else//否则找到最后一个兄弟,在其后添加结点 { while(p->rchild != NULL)//循环到最后节点 { p = p->rchild;//指向下一个右孩子 } s->generation = p->generation;//兄弟辈分相同 p->rchild = s;//兄弟为右孩子 return 1; } } p = p->rchild;//指向右孩子 } //system("pause"); } ////////////////////////////////////////////////////// // 功能: 输出指定家庭成员 // 函数名: output // 说明: 递归法 ////////////////////////////////////////////////////// void output(node *head, char *name) { if(head != NULL) { if(strcmp(head->family,name) == 0)//若输入的名字name与head->family相等 { if(strcmp(head->family, "0") != 0)//head->family不等于0 printf("%s-", head->family);//找到后先输出该成员,再调用函数输出其子孙 if(head->lchild != NULL) { head = head->lchild; preOrder(head);//调用函数,输出孩子节点 } } output(head->lchild, name);//递归 output(head->rchild, name);//递归 } } ////////////////////////////////////////////////////// // 功能: 确定成员辈分 // 函数名: beifen // 说明: 递归法 ////////////////////////////////////////////////////// int beifen(node *p, char *name) { if(p!=NULL) { if(strcmp(p->family, name) == 0 && strcmp(p->family, "0") != 0)//如果找到且不为字符 0 则输出 { printf("%d", p->generation);//输出 return 1; } beifen(p->lchild, name);//递归 beifen(p->rchild, name);//递归 } } ////////////////////////////////////////////////////// // 功能: 先序遍历输出家庭成员 // 函数名: preOrder // 说明: 递归法 ////////////////////////////////////////////////////// void preOrder(node *head) { if(head != NULL) { if(strcmp(head->family,"0") != 0)//判断是否为空 printf("-%s-", head->family);//输出 preOrder(head->lchild);//递归 preOrder(head->rchild);//递归 } } ////////////////////////////////////////////////////// // 功能: 输出相应辈分成员 // 函数名: chengyuan // 说明:输出相应辈分成员 递归法 ////////////////////////////////////////////////////// void chengyuan(node *head, int name) { if(head != NULL) { if(head->generation == name)//找到后且该成员未被删除 则输出 { if(strcmp(head->family, "0") != 0)//查找 printf("-%s-", head->family);//输出 } chengyuan(head->lchild, name);//递归 chengyuan(head->rchild, name);//递归 } } ////////////////////////////////////////////////////// // 功能: 删除成员 // 函数名: Delete // 说明:其实未删除,只是将其姓名设为字符 0 递归法 ////////////////////////////////////////////////////// void Delete(node* head,char *name) { if(head != NULL) { if(strcmp(head->family, name) == 0)//比较找到 strcpy(head->family, "0");//值归0 Delete(head->lchild, name);//递归 Delete(head->rchild, name);//递归 } } ////////////////////////////////////////////// // 主函数 main() // 调用主界面函数 Display() ////////////////////////////////////////////// int main() { Display();//显示主界面 return 0; }
关于迷宫随机产生方向的问题,求教大神???
#include<iostream> using namespace std; template <class T> //声明一个类模板 class SqStack { public: //顺序栈类的各成员函数 SqStack(int m = 1000); ~SqStack(); void Clear(); bool Empty()const; int Length()const; T &Top()const; void Push(const T &e); void Pop(); private: //顺序栈类的数据成员 T *m_base; //基地址指针 int m_top; //栈顶指针 int m_size; //向量空间大小 }; //构造函数,分配m个结点的顺序空间,构造一个空的顺序栈。 template<class T> SqStack<T>::SqStack(int m) { m_top = 0; m_base = new T[m]; m_size = m; } //析构函数,将栈结构销毁。 template<class T> SqStack<T>::~SqStack() { if (m_base != NULL) delete[] m_base; } //清空栈。 template <class T> void SqStack<T>::Clear() { m_top = 0; } //判栈是否为空,若为空,则返回true,否则返回false。 template <class T> bool SqStack<T>::Empty()const { return m_top == 0; } //求栈的长度。 template <class T> int SqStack<T>::Length()const { return m_top; } //取栈顶元素的值。先决条件是栈不空。 template<class T> T &SqStack<T>::Top()const { return m_base[m_top - 1]; } //入栈,若栈满,则先扩展空间。插入e到栈顶。 template <class T> void SqStack<T>::Push(const T &e) { if (m_top >= m_size) { T* newbase; newbase = new T[m_size + 10]; for (int j = 0; j<m_top; j++) newbase[j] = m_base[j]; delete[] m_base; m_base = newbase; m_size += 10; } m_base[m_top++] = e; } //入栈,若栈满,则先扩展空间。插入e到栈顶。 template<class T> void SqStack<T>::Pop() { m_top--; }#include"windows.h" #include"stdlib.h" #include"time.h" #include"SqStack.h" #include "iostream" using namespace std; #define MAXSIZE 30 #define N 25 const static int _MAX = 65535; struct PosType { int x; int y; }; struct DataType { PosType seat; int di; }; //输出坐标 void gotoxy(int x, int y) { COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); //定义一个结构体pos,x,y就是构成的成员 } void color(int b) { HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)); SetConsoleTextAttribute(hConsole, b); //调用API设置字体和背景的颜色函数 } class Maze { protected: // static int MAX = 1111; public: Maze(int, int,bool ); ~Maze(); bool MazePath(PosType, PosType,bool); void Input(); void Print(); void init(); void Manual(); private: PosType NextPos(PosType, int); int **m_maze; int m_row; int m_col; bool w; }; Maze::Maze(int m, int n,bool k) { if (k) { m_row = m + 2; m_col = n + 2; w = k; m_maze = new int *[m_row]; for (int i = 0; i < m_row; i++) m_maze[i] = new int[m_col]; this->Input(); } else { int i = 0, j = 0; m_row = m + 2; m_col = n + 2; w = k; m_maze = new int *[m_row]; for ( i = 0; i < m_row; i++) m_maze[i] = new int[m_col]; int p[20][20] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, }; for (i = 1; i <= m_row - 2; i++) for (j = 1; j <= m_col - 2; j++) m_maze[i][j]=p[i-1][j-1]; // m_maze[i][j] = rand() % 2; for (i = 0; i < m_row; i++) { m_maze[i][0] = 65535; m_maze[i][m_col - 1] = 65535 ; } for (j = 1; j < m_col - 1; j++) { m_maze[0][j] = 65535; m_maze[m_row - 1][j] = 65535; } } } Maze::~Maze() { for (int i = 0; i < m_row; i++) if (m_maze[i] != NULL) delete[] m_maze[i]; if (m_maze != NULL) delete[] m_maze; } bool Maze::MazePath(PosType start, PosType end,bool m) { SqStack<DataType> path(MAXSIZE); PosType curpos; DataType e; curpos = start; int curstep = 2; e.di = 0; do { if (m_maze[curpos.x][curpos.y] == 0) { m_maze[curpos.x][curpos.y] = curstep; e.seat.x = curpos.x; e.seat.y = curpos.y; path.Push(e); curstep++; if (m) { Sleep(50); gotoxy(0,0); this->init(); } if (curpos.x == end.x && curpos.y == end.y) { m_maze[curpos.x][curpos.y] = 2; return true; } curpos = NextPos(curpos, e.di); } else { if (!path.Empty()) { e = path.Top(); path.Pop(); curstep--; while (e.di == 3&&!path.Empty()) { m_maze[e.seat.x][e.seat.y] = -1; e = path.Top(); path.Pop(); curstep--; } if (e.di < 3) { if(m_maze[e.seat.x+1][e.seat.y]==0&&m_maze[e.seat.x-1][e.seat.y]!=0&&m_maze[e.seat.x][e.seat.y+1]!=0&&m_maze[e.seat.x][e.seat.y-1]!=0) e.di=0; if(m_maze[e.seat.x+1][e.seat.y]!=0&&m_maze[e.seat.x-1][e.seat.y]==0&&m_maze[e.seat.x][e.seat.y+1]!=0&&m_maze[e.seat.x][e.seat.y-1]!=0) e.di=1; if(m_maze[e.seat.x+1][e.seat.y]!=0&&m_maze[e.seat.x-1][e.seat.y]!=0&&m_maze[e.seat.x][e.seat.y+1]==0&&m_maze[e.seat.x][e.seat.y-1]!=0) e.di=2; if(m_maze[e.seat.x+1][e.seat.y]!=0&&m_maze[e.seat.x-1][e.seat.y]!=0&&m_maze[e.seat.x][e.seat.y+1]!=0&&m_maze[e.seat.x][e.seat.y-1]==0) e.di=3; else { e.di =rand()%3; } curstep++; path.Push(e); curpos = NextPos(e.seat, e.di); } } } } while (!path.Empty()); return false; } void Maze::Input() { int i, j; cout << "请输入" << m_row-2 << "*" << m_col - 2 << "的迷宫:" << endl; for (i = 1; i <= m_row - 2; i++) for (j = 1; j <= m_col - 2; j++) cin >> m_maze[i][j]; for (i = 0; i < m_row; i++) { m_maze[i][0] = 65535; m_maze[i][m_col - 1] = 65535; } for (j = 1; j < m_col - 1; j++) { m_maze[0][j] = 65535; m_maze[m_row - 1][j] = 65535; } } void Maze::Print() { //FILE *fp; //errno_t err; // err = fopen_s(&fp, "output", "w"); // fprintf(fp, "----------迷宫路径----------\n"); int i, j; for (i = 0; i < m_row; i++) { for (j = 0; j < m_col; j++) { cout << " " << m_maze[i][j]; // fprintf(fp, "\t%d", m_maze[i][j]); } cout << endl; // fprintf(fp, "\n"); } // fprintf(fp, "\n"); // fclose(fp); } PosType Maze::NextPos(PosType c, int d) { PosType direct[4] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; c.x += direct[d].x; c.y += direct[d].y; return c; } //界面初始化 void Maze::init() //初始化一个迷宫 { for (int i = 0; i < m_row; i++) { for (int j = 0; j < m_col; j++) { if (m_maze[i][j]==1) { color(11); cout << "■"; //围墙或者此路不通 } else if (m_maze[i][j] ==65535) { color(10); cout << "◇"; } else if (m_maze[i][j]==0) { color(12); cout << "□"; //通路 } else if (m_maze[i][j] == 2) { color(15); cout << "★"; } else { color(14); cout << "★"; } } cout << endl; } } void Maze::Manual() { gotoxy(N + 25, 1); color(11); cout<<"现在呈现一个"<<m_row-2<<"*"<<m_col-2<<"迷宫"; } void main() { srand((unsigned)time(NULL)); while (1) { PosType begin, end; bool k; cout << "请选择模式:" << endl; cout << "如果要自己输入迷宫,输入非0数,如果要想用现成的输入0:" << endl; cout << "请选择!!!"; cin >> k; int m, n; cout << "请输入迷宫的行数,列数:"; cin >> m >> n; Maze maze(m, n, k); system("cls"); maze.init(); maze.Manual(); gotoxy(N + 25, 7); cout << "出口和入口行数和列数需加1 \n"; gotoxy(N + 25, 8); cout << "请输入入口位置(行数,列数):"; cin.sync(); gotoxy(N + 25, 9); cin >> begin.x >> begin.y; gotoxy(N + 25, 13); cout << "请输入出口位置(行数,列数):"; gotoxy(N + 25, 14); cin >> end.x >> end.y; bool l; gotoxy(N + 25, 16); cout << "是否想看走迷宫过程?0否1是!"; gotoxy(N + 25, 17); cin >> l ; if (maze.MazePath(begin, end, l)) { if (!l) gotoxy(0, N + 25); cout << "此迷宫从入口到出口的一条路径如下:" << endl; maze.init(); } else { if (!l) gotoxy(0, N + 25); cout << "此迷宫没有从入口到出口的路径" << endl; } cin.sync(); system("pause"); } }
为什么在MFC中使用线程会出现程序崩溃?是我实用的方法不敌还是怎么回事?
在使用MFC中使用的线程是 API函数,调用CreateThread(); 可是使用的时候调试一步一步走都是正常的,但是一起运行就发现程序崩溃。我是一个初学的菜鸟,可能是代码有点乱,麻烦看一下!!! 谢谢各位大佬: ``` // UDPserver.cpp : 实现文件 // #include "stdafx.h" #include "ServerUDP.h" #include "UDPserver.h" #include <Winsock2.h>//加裁头文件 #include <stdio.h>//加载标准输入输出头文件 #define IDP_SOCKETS_INIT_FAILED 103 SOCKET m_revSocket; // CUDPserver CUDPserver::CUDPserver() { } CUDPserver::~CUDPserver() { } // CUDPserver 成员函数 // Server 成员函数 bool CUDPserver::Socket()//初始化 { //初始化Winscok if (!AfxSocketInit()) { AfxMessageBox(IDP_SOCKETS_INIT_FAILED); return 1; } // SetSockOpt(); WORD wVersionRequested;//版本号 WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 );//1.1版本的套接字 err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return false; }//加载套接字库,加裁失败则返回 if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return false; }//如果不是1.1的则退出 return true; } #include"Set_up.h" CSet_up up; bool CUDPserver::GetLocalAddress(){ CString strAddress; int nCardNo = 1; //PIP_ADAPTER_INFO结构体指针存储本机网卡信息 PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO(); //得到结构体大小,用于GetAdaptersInfo参数 unsigned long stSize = sizeof(IP_ADAPTER_INFO); //调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量 int nRel = GetAdaptersInfo(pIpAdapterInfo,&stSize); //记录网卡数量 int netCardNum = 0; //记录每张网卡上的IP地址数量 int IPnumPerNetCard = 0; if (ERROR_BUFFER_OVERFLOW == nRel) { //如果函数返回的是ERROR_BUFFER_OVERFLOW //则说明GetAdaptersInfo参数传递的内存空间不够,同时其传出stSize,表示需要的空间大小 //这也是说明为什么stSize既是一个输入量也是一个输出量 //释放原来的内存空间 delete pIpAdapterInfo; //重新申请内存空间用来存储所有网卡信息 pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize]; //再次调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量 nRel=GetAdaptersInfo(pIpAdapterInfo,&stSize); } if (ERROR_SUCCESS == nRel) { //输出网卡信息 //可能有多网卡,因此通过循环去判断 while (pIpAdapterInfo) { //可能网卡有多IP,因此通过循环去判断 IP_ADDR_STRING *pIpAddrString =&(pIpAdapterInfo->IpAddressList); switch(pIpAdapterInfo->Type) { case MIB_IF_TYPE_OTHER: case MIB_IF_TYPE_ETHERNET: case MIB_IF_TYPE_TOKENRING: case MIB_IF_TYPE_FDDI: case MIB_IF_TYPE_PPP: case MIB_IF_TYPE_LOOPBACK: case MIB_IF_TYPE_SLIP: { strAddress = pIpAddrString->IpAddress.String; // 需要注意的是有时可能获取的IP地址是0.0.0.0,这时需要过滤掉 if(CString("0.0.0.0")==strAddress) break; // std::cout<<_T("第")<< nCardNo<<_T("张网卡的IP地址是")<< strAddress<<std::endl; // long PID = _ttol(strAddress); //CString 转成 char*,该语句缺一不 // mxcj.m_strIP = (DWORD)PID; // 再强制转换成DWORD m_DIP= strAddress; nCardNo++; break; } default: // 未知类型网卡就跳出 break; } pIpAdapterInfo = pIpAdapterInfo->Next; } } //释放内存空间 if (pIpAdapterInfo) { delete pIpAdapterInfo; } //initsocket();//创建套接字 return true; } bool CUDPserver::initsocket() { /*创建套接字*/ //AF_INET表示IPv4,SOCK_STREAM数据传输方式,IPPROTO_TCP传输协议; m_listenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if (m_listenSocket == INVALID_SOCKET) { //printf("套接字创建失败"); WSACleanup(); return 0; } Bind(); return true; } bool CUDPserver::Bind()// 绑定地址端口 { sockaddr_in addrListen; addrListen.sin_family = AF_INET; //指定IP格式 addrListen.sin_port = htons(m_iDKH); //绑定端口号 addrListen.sin_addr.S_un.S_addr = INADDR_ANY; //表示任何IP service.sin_addr.s_addr = inet_addr("127.0.0.1"); if (bind(m_listenSocket, (SOCKADDR*)&addrListen, sizeof(addrListen)) == SOCKET_ERROR) //(SOCKADDR*) { //printf("绑定失败"); closesocket(m_listenSocket); return 0; } Connect(); //连接开始监听 return true; } unsigned int WINAPI ThreadProFunc(void *pParam); bool CUDPserver::Connect() //连接 { /*开始监听*/ if (listen(m_listenSocket, 5) == SOCKET_ERROR) { //printf("监听出错"); closesocket(m_listenSocket); return 0; } /*等待连接,连接后建立一个新的套接字*/ //SOCKET revSocket; //对应此时所建立连接的套接字的句柄 //HANDLE hThread; // DWORD dwThreadId; //sockaddr_in remoteAddr; //接收连接到服务器上的地址信息 //int remoteAddrLen = sizeof(remoteAddr); //printf("等待连接...\n"); /*等待客户端请求,服务器接收请求*/ //m_revSocket = accept(m_listenSocket, (SOCKADDR*)&remoteAddr, &remoteAddrLen); //等待客户端接入,直到有客户端连接上来为止 /*if (m_revSocket == INVALID_SOCKET) { closesocket(m_listenSocket); WSACleanup(); return 0; } else { /* 启动等待连接线程 */ HANDLE acceptThread = CreateThread(NULL, 0, WaitAcceptThread, (LPVOID)m_listenSocket, 0, NULL); WaitForSingleObject(acceptThread, INFINITE); // 等待线程结束 // return 0; //} return true; } unsigned int WINAPI ThreadProFunc(void *pParam) { CUDPserver server; server.Receive(); char revData[255] = ""; while(1){ /*通过建立的连接进行通信*/ int res = recv(server.m_revSocket, revData, 255, 0); if (res > 0) { //printf("Bytes received: %d\n", res); // server.m_wndOutputBuild.AddString(_T("调试输出正显示在此处。")); //printf("客户端发送的数据: %s\n", revData); return 0; } //sleep(1000); return 0; } } UINT __cdecl CUDPserver::hellothread(LPVOID lparam){ CUDPserver server; server.Receive(); char revData[255] = ""; while(1){ /*通过建立的连接进行通信*/ int res = recv(server.m_revSocket, revData, 255, 0); if (res > 0) { //printf("Bytes received: %d\n", res); // server.m_wndOutputBuild.AddString(_T("调试输出正显示在此处。")); //printf("客户端发送的数据: %s\n", revData); return 0; } //sleep(1000); return 0; } } HANDLE bufferMutex; DWORD WINAPI WaitAcceptThread(LPVOID IpParameter) { SOCKET m_socket = (SOCKET)IpParameter; // int rval; sockaddr_in remoteAddr; //接收连接到服务器上的地址信息 int remoteAddrLen = sizeof(remoteAddr); while(true){ /*等待客户端请求,服务器接收请求*/ m_revSocket = accept(m_socket, (SOCKADDR*)&remoteAddr, &remoteAddrLen); //等待客户端接入,直到有客户端连接上来为止 if (m_revSocket == INVALID_SOCKET) { //printf("客户端发出请求,服务器接收请求失败:\n",WSAGetLastError()); closesocket(m_revSocket); WSACleanup(); return 0; } HANDLE receiveThread = CreateThread(NULL, 0, RecMsgThread, (LPVOID)m_revSocket, 0, NULL); WaitForSingleObject(bufferMutex, INFINITE); if(NULL == receiveThread) { //printf("\nCreatThread AnswerThread() failed.\n"); return 0; } ReleaseSemaphore(bufferMutex, 1, NULL); } } DWORD WINAPI RecMsgThread(LPVOID IpParameter) { SOCKET ClientSocket=(SOCKET)(LPVOID)IpParameter; int rval; while(1) { char recvBuf[1024]; rval = recv(ClientSocket, recvBuf, 1024, 0); WaitForSingleObject(bufferMutex, INFINITE); if (rval == SOCKET_ERROR) { // printf("ONE Client Exit\n"); // vector<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket); // clientSocketGroup.erase(result); // for (map<SOCKET, string>::iterator i=m_ipSocket.begin(); i!=m_ipSocket.end(); i++) // { // if (i->first == ClientSocket) // { // printf("%s下线\n",m_ipSocket[ClientSocket].c_str()); // m_ipSocket.erase(i); // break; // } // } closesocket(ClientSocket); ReleaseSemaphore(bufferMutex, 1, NULL); break; } recvBuf; if(recvBuf[0] == -113){ if(recvBuf[0]== -1){ return 0; } } // printf("%s Says: %s\n", m_ipSocket[ClientSocket].c_str(), recvBuf); // 接收信息 Sleep(1000); ReleaseSemaphore(bufferMutex, 1, NULL); } return 0; } ```
相见恨晚的超实用网站
相见恨晚的超实用网站 持续更新中。。。
爬虫福利二 之 妹子图网MM批量下载
爬虫福利一:27报网MM批量下载 点击 看了本文,相信大家对爬虫一定会产生强烈的兴趣,激励自己去学习爬虫,在这里提前祝:大家学有所成! 目标网站:妹子图网 环境:Python3.x 相关第三方模块:requests、beautifulsoup4 Re:各位在测试时只需要将代码里的变量path 指定为你当前系统要保存的路径,使用 python xxx.py 或IDE运行即可。 ...
字节跳动视频编解码面经
三四月份投了字节跳动的实习(图形图像岗位),然后hr打电话过来问了一下会不会opengl,c++,shador,当时只会一点c++,其他两个都不会,也就直接被拒了。 七月初内推了字节跳动的提前批,因为内推没有具体的岗位,hr又打电话问要不要考虑一下图形图像岗,我说实习投过这个岗位不合适,不会opengl和shador,然后hr就说秋招更看重基础。我当时想着能进去就不错了,管他哪个岗呢,就同意了面试...
开源一个功能完整的SpringBoot项目框架
福利来了,给大家带来一个福利。 最近想了解一下有关Spring Boot的开源项目,看了很多开源的框架,大多是一些demo或者是一个未成形的项目,基本功能都不完整,尤其是用户权限和菜单方面几乎没有完整的。 想到我之前做的框架,里面通用模块有:用户模块,权限模块,菜单模块,功能模块也齐全了,每一个功能都是完整的。 打算把这个框架分享出来,供大家使用和学习。 为什么用框架? 框架可以学习整体...
源码阅读(19):Java中主要的Map结构——HashMap容器(下1)
HashMap容器从字面的理解就是,基于Hash算法构造的Map容器。从数据结构的知识体系来说,HashMap容器是散列表在Java中的具体表达(并非线性表结构)。具体来说就是,利用K-V键值对中键对象的某个属性(默认使用该对象的“内存起始位置”这一属性)作为计算依据进行哈希计算(调用hashCode方法),然后再以计算后的返回值为依据,将当前K-V键值对在符合HashMap容器构造原则的基础上,放置到HashMap容器的某个位置上,且这个位置和之前添加的K-V键值对的存储位置完全独立,不一定构成连续的存储
c++制作的植物大战僵尸,开源,一代二代结合游戏
此游戏全部由本人自己制作完成。游戏大部分的素材来源于原版游戏素材,少部分搜集于网络,以及自己制作。 此游戏为同人游戏而且仅供学习交流使用,任何人未经授权,不得对本游戏进行更改、盗用等,否则后果自负。目前有六种僵尸和六种植物,植物和僵尸的动画都是本人做的。qq:2117610943 开源代码下载 提取码:3vzm 点击下载--&gt; 11月28日 新增四种植物 统一植物画风,全部修...
Java学习的正确打开方式
在博主认为,对于入门级学习java的最佳学习方法莫过于视频+博客+书籍+总结,前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人,实际上越到后面你会发现学习的最好方式就是阅读参考官方文档其次就是国内的书籍,博客次之,这又是一个层次了,这里暂时不提后面再谈。博主将为各位入门java保驾护航,各位只管冲鸭!!!上天是公平的,只要不辜负时间,时间自然不会辜负你。 何谓学习?博主所理解的学习,它是一个过程,是一个不断累积、不断沉淀、不断总结、善于传达自己的个人见解以及乐于分享的过程。
程序员必须掌握的核心算法有哪些?
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过...
Python——画一棵漂亮的樱花树(不同种樱花+玫瑰+圣诞树喔)
最近翻到一篇知乎,上面有不少用Python(大多是turtle库)绘制的树图,感觉很漂亮,我整理了一下,挑了一些我觉得不错的代码分享给大家(这些我都测试过,确实可以生成) one 樱花树 动态生成樱花 效果图(这个是动态的): 实现代码 import turtle as T import random import time # 画樱花的躯干(60,t) def Tree(branch, ...
linux系列之常用运维命令整理笔录
本博客记录工作中需要的linux运维命令,大学时候开始接触linux,会一些基本操作,可是都没有整理起来,加上是做开发,不做运维,有些命令忘记了,所以现在整理成博客,当然vi,文件操作等就不介绍了,慢慢积累一些其它拓展的命令,博客不定时更新 free -m 其中:m表示兆,也可以用g,注意都要小写 Men:表示物理内存统计 total:表示物理内存总数(total=used+free) use...
Python 基础(一):入门必备知识
Python 入门必备知识,你都掌握了吗?
深度学习图像算法在内容安全领域的应用
互联网给人们生活带来便利的同时也隐含了大量不良信息,防范互联网平台有害内容传播引起了多方面的高度关注。本次演讲从技术层面分享网易易盾在内容安全领域的算法实践经验,包括深度...
程序员接私活怎样防止做完了不给钱?
首先跟大家说明一点,我们做 IT 类的外包开发,是非标品开发,所以很有可能在开发过程中会有这样那样的需求修改,而这种需求修改很容易造成扯皮,进而影响到费用支付,甚至出现做完了项目收不到钱的情况。 那么,怎么保证自己的薪酬安全呢? 我们在开工前,一定要做好一些证据方面的准备(也就是“讨薪”的理论依据),这其中最重要的就是需求文档和验收标准。一定要让需求方提供这两个文档资料作为开发的基础。之后开发...
网页实现一个简单的音乐播放器(大佬别看。(⊙﹏⊙))
今天闲着无事,就想写点东西。然后听了下歌,就打算写个播放器。 于是乎用h5 audio的加上js简单的播放器完工了。 演示地点演示 html代码如下` music 这个年纪 七月的风 音乐 ` 然后就是css`*{ margin: 0; padding: 0; text-decoration: none; list-...
Python十大装B语法
Python 是一种代表简单思想的语言,其语法相对简单,很容易上手。不过,如果就此小视 Python 语法的精妙和深邃,那就大错特错了。本文精心筛选了最能展现 Python 语法之精妙的十个知识点,并附上详细的实例代码。如能在实战中融会贯通、灵活使用,必将使代码更为精炼、高效,同时也会极大提升代码B格,使之看上去更老练,读起来更优雅。
数据库优化 - SQL优化
以实际SQL入手,带你一步一步走上SQL优化之路!
2019年11月中国大陆编程语言排行榜
2019年11月2日,我统计了某招聘网站,获得有效程序员招聘数据9万条。针对招聘信息,提取编程语言关键字,并统计如下: 编程语言比例 rank pl_ percentage 1 java 33.62% 2 cpp 16.42% 3 c_sharp 12.82% 4 javascript 12.31% 5 python 7.93% 6 go 7.25% 7 p...
通俗易懂地给女朋友讲:线程池的内部原理
餐盘在灯光的照耀下格外晶莹洁白,女朋友拿起红酒杯轻轻地抿了一小口,对我说:“经常听你说线程池,到底线程池到底是个什么原理?”
经典算法(5)杨辉三角
写在前面: 我是 扬帆向海,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的。 这博客是对自己学习的一点点总结及记录,如果您对 Java、算法 感兴趣,可以关注我的动态,我们一起学习。 用知识改变命运,让我们的家人过上更好的生活。 目录一、杨辉三角的介绍二、杨辉三角的算法思想三、代码实现1.第一种写法2.第二种写法 一、杨辉三角的介绍 百度
腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹?
昨天,有网友私信我,说去阿里面试,彻底的被打击到了。问了为什么网上大量使用ThreadLocal的源码都会加上private static?他被难住了,因为他从来都没有考虑过这个问题。无独有偶,今天笔者又发现有网友吐槽了一道腾讯的面试题,我们一起来看看。 腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹? 在互联网职场论坛,一名程序员发帖求助到。二面腾讯,其中一个算法题:64匹...
面试官:你连RESTful都不知道我怎么敢要你?
干货,2019 RESTful最贱实践
为啥国人偏爱Mybatis,而老外喜欢Hibernate/JPA呢?
关于SQL和ORM的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行了一番讨论,感触还是有一些,于是就有了今天这篇文。 声明:本文不会下关于Mybatis和JPA两个持久层框架哪个更好这样的结论。只是摆事实,讲道理,所以,请各位看官勿喷。 一、事件起因 关于Mybatis和JPA孰优孰劣的问题,争论已经很多年了。一直也没有结论,毕竟每个人的喜好和习惯是大不相同的。我也看...
项目中的if else太多了,该怎么重构?
介绍 最近跟着公司的大佬开发了一款IM系统,类似QQ和微信哈,就是聊天软件。我们有一部分业务逻辑是这样的 if (msgType = "文本") { // dosomething } else if(msgType = "图片") { // doshomething } else if(msgType = "视频") { // doshomething } else { // doshom...
致 Python 初学者
欢迎来到“Python进阶”专栏!来到这里的每一位同学,应该大致上学习了很多 Python 的基础知识,正在努力成长的过程中。在此期间,一定遇到了很多的困惑,对未来的学习方向感到迷茫。我非常理解你们所面临的处境。我从2007年开始接触 python 这门编程语言,从2009年开始单一使用 python 应对所有的开发工作,直至今天。回顾自己的学习过程,也曾经遇到过无数的困难,也曾经迷茫过、困惑过。开办这个专栏,正是为了帮助像我当年一样困惑的 Python 初学者走出困境、快速成长。希望我的经验能真正帮到你
Python 编程实用技巧
Python是一门很灵活的语言,也有很多实用的方法,有时候实现一个功能可以用多种方法实现,我这里总结了一些常用的方法,并会持续更新。
“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作
一、垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高。 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介绍,他是偶尔需要一些中文文字用于GUI开发时测试文本渲染,因此开发了这个废话生成器。但由于生成的废话实在是太过富于哲理,所以最近已经被小伙伴们给玩坏了。 他的文风可能是这样的: 你发现,
程序员:我终于知道post和get的区别
IT界知名的程序员曾说:对于那些月薪三万以下,自称IT工程师的码农们,其实我们从来没有把他们归为我们IT工程师的队伍。他们虽然总是以IT工程师自居,但只是他们一厢情愿罢了。 此话一出,不知激起了多少(码农)程序员的愤怒,却又无可奈何,于是码农问程序员。 码农:你知道get和post请求到底有什么区别? 程序员:你看这篇就知道了。 码农:你月薪三万了? 程序员:嗯。 码农:你是怎么做到的? 程序员:
"狗屁不通文章生成器"登顶GitHub热榜,分分钟写出万字形式主义大作
前言 GitHub 被誉为全球最大的同性交友网站,……,陪伴我们已经走过 10+ 年时间,它托管了大量的软件代码,同时也承载了程序员无尽的欢乐。 上周给大家分享了一篇10个让你笑的合不拢嘴的Github项目,而且还拿了7万+个Star哦,有兴趣的朋友,可以看看, 印象最深刻的是 “ 呼吸不止,码字不停 ”: 老实交代,你是不是经常准备写个技术博客,打开word后瞬间灵感便秘,码不出字? 有什么
推荐几款比较实用的工具,网站
1.盘百度PanDownload 这个云盘工具是免费的,可以进行资源搜索,提速(偶尔会抽风????) 不要去某站买付费的???? PanDownload下载地址 2.BeJSON 这是一款拥有各种在线工具的网站,推荐它的主要原因是网站简洁,功能齐全,广告相比其他广告好太多了 bejson网站 3.二维码美化 这个网站的二维码美化很好看,网站界面也很...
《程序人生》系列-这个程序员只用了20行代码就拿了冠军
你知道的越多,你不知道的越多 点赞再看,养成习惯GitHub上已经开源https://github.com/JavaFamily,有一线大厂面试点脑图,欢迎Star和完善 前言 这一期不算《吊打面试官》系列的,所有没前言我直接开始。 絮叨 本来应该是没有这期的,看过我上期的小伙伴应该是知道的嘛,双十一比较忙嘛,要值班又要去帮忙拍摄年会的视频素材,还得搞个程序员一天的Vlog,还要写BU
相关热词 c# plc s1200 c#里氏转换原则 c# 主界面 c# do loop c#存为组套 模板 c# 停掉协程 c# rgb 读取图片 c# 图片颜色调整 最快 c#多张图片上传 c#密封类与密封方法
立即提问