C语言学习笔记(九)——IDE

为了完成教学中的项目,需要了解一些C++的知识,也需要知道它和C的一些区别。
现在开始看一些它们的区别吧

1、首先在C++中,malloc是返回值是void
所以char *p=malloc(100);在C++中无法使用,需要强转:char *p=(char *)malloc(100)
其实在C++很多时候经常用 new,是C++的一个关键字,不需要包含任何头文件

char *p=new char[100];//在堆中分配100个char
delete []p;//释放一个数组,如果只有p那么只释放第一个char
char *p1=new char;//在堆中分配一个char
delete p1;//释放一个char
//c++语言可以兼容c语言的内存管理机制,但如果用malloc分配的内存就必须要free
如果用new分配的就必须用delete,不能混合使用

2、在c语言中,可用下面的方法绕过const

const int a=10;
int *p2=(int *)&a;
*p2=100;
printf("%d\n",a);

但在C++中不会修改a的值

3、在c语言中

void test (int a=10);//c语言中是非法的,C++是合法的,此时调用的时候还是根据输入的实参调用这个函数,但是如果缺省函数的实参,就会使用a=10.这个叫形参的缺省值
{
}
void test (int a,int b);
{
}
//在C语言中,这种全局的函数名字不允许相同,所以这是非法的,但在C++中是合法的,这叫重载,根据调用的时候参数的不同,自动调用相应的函数

4、当然最主要的区别还是C++是面向对象的= =

#include <stdio.h>
#include <string.h>
struct man
{
    char name[20];
    int age;
    void set_name(const char *p)//在结构体中可以使用函数
    {
        strcpy(name, p);
    }
    void set_age(int a)
    {
        age = a;
    }
    const char *get_name()
    {
        return name;//在结构体中,它就不在内存中,具体在堆在栈中应该看定义它的语法
    }
    int get_age()
    {
        return age;
    }
    man()//没有返回值,名字和结构名字相同,这叫构造函数
    {
        printf("hello world\n");
    }
    man(const char *p, int a = 0)//构造函数的重载
    {
        age = a;
        strcpy(name, p);
    }
    ~man()//析构函数
    {
        printf("~man\n");
    }
};

int main01()
{
   //man m;//前面不用加struct
   //m.set_name("Tom");//C++一般这样设置,而不是在这里调用strcpy
   // m.set_age(20);
   // printf("%s, %d\n", m.get_name(), m.get_age());//虽然m在栈中,但此时m并未消失,m.get_name()地址是有效的
  //如果想把m放到堆中 
    man *m = new man;//这里结构成了堆里面一个变量
    m->set_name("tom");//因为m是指针,所以需要改成->
    m->set_age(20);
     printf("%s, %d\n", m->get_name(), m->get_age());
    delete m;
    man m1;//结构成了栈里面一个变量了,这里调用的是没有参数的构造函数
    man m2("abc", 100);// 明确的调用有const char *参数的构造函数
    printf("%s, %d\n", m2.get_name(), m2.get_age());
    man *m3 = new man("张三", 30);
    printf("%s, %d\n", m3->get_name(), m3->get_age());
    delete m3;
    return 0;

}


struct A//这里分析构造和析构的行为
{
    int age;
    A(int a)
    {
        age = a;
        printf("A, %d\n", age);
    }
    ~A()
    {
        printf("~A, %d\n", age);
    }
};
 A a;//通过这样达到在main前执行代码
int main()
{
    printf("hell world\n");//如何在调用main函数之前就执行一段代码?
    A a(10);
    A *p = new A(20);
    delete p;

    return 0;
}

构造函数是一个结构在内存中变成一个变量的时候,自动被调用的

在内存中出现的时候,自动调用构造函数,如果在内存中销毁的时候自动调用析构函数

构造函数可以有多个,但析构函数只能有一个,而且没有参数

5、this指针

#include <stdio.h>


struct A
{
    A()
    {
        //int a;
        //scanf("%d", &a);
        //int b;
        //scanf("%d", &b);
        //printf("%d\n", a + b);
    }
    int age;
    void set_age(int age)
    {
        this->age = age;//this是c++的关键字,代表对象的地址
    }
    struct A *get_addr()
    {
        return this;
    }
};



int main()
{
    A a;//a是一个对象,
    printf("%p, %p\n", &a, a.get_addr());
    A *p = new A;
    printf("%p, %p\n", p, p->get_addr());
    delete p;
    return 0;
}

类与结构体的区别

C++里面,结构所有的成员都是公有的,就是外部可以访问的
class里面所有的成员都是私有的,外部不能访问
public:公有成员
private:私有成员

#include <stdio.h>
#include <string.h>

class man
{
public:
    char *name;

    man()//给下面的if(name)用
    {
        name = NULL;
    }

    void set_name(const char *name)
    {
        if (name)//如果不加这句会隐含内存泄露,但是刚开始没有name可以删除,所以小技巧是在上面加一个构造函数
            delete []this->name;
        this->name = new char[strlen(name) + 1];//在外面使用时就不用关心内存了,且注意此处的this
        strcpy(this->name, name);
    }

    const char *get_name()
    {
        if (name)
            return name;
        else
            return "nothing";
    }
    int get_age()
    {
        return age;//可以通过这种方法,访问到age
    }

    ~man()
    {
        if (name)//不加这句的话,如果后面没有对name初始化,这里也会有问题,所以加if(name)
            delete []name;
    }

private:
    int age;    //此时在main函数里面访问它,是不能访问的

};

int main()
{
    man *m = new man;
    m->set_name("sdfsdfsdfsdfdsfsdfsdfdsfsdfsfdsf");
    m->set_name("a");//如果不在select中加delete会产生内存泄露
    printf("%s\n", m->get_name());
    printf("%d\n", m->get_age());
    delete m;
    return 0;
}

#include <stdio.h>
#include <string.h>
class man
{
private:
    char *name;
    int age;
public:
    man()
    {
        name = NULL;
        age = 0;
    }
    ~man()
    {
        if (name)
            delete []name;
    }
    const char *get_name()
    {
        return name;
    }
    int get_age()
    {
        return age;
    }
    void set_name(const char *name)
    {
        if (strcmp(name, "凤姐") == 0)//之所以用private,就像这样,可以对成员进行限制
            return;
        if (this->name)
            delete []this->name;
        this->name = new char[strlen(name) + 1];
        strcpy(this->name ,name);
    }
    void set_age(int age)
    {
        if (age >= 0 && age <= 200)//之所以用private,就像这样,可以对成员进行限制
            this->age = age;
    }
};

int main()
{
    man m;
   // m.set_name("Tom");
   // m.set_age("30");
    char name[100];
    scanf("%s", name);
    int age= 0;
    scanf("%d", &age);
    m.set_name(name);//通过用户输入指定名字
    m.set_age(age);
    printf("%s, %d\n", m.get_name(), m.get_age());
    return 0;
}

类的继承
父类和子类间有关联

例子(不是类的例子,是个破解按键的有趣的例子)

在VS中新建一个MFC项目
可以设置按键等,也可以设置某些键位不能使用,此时可以对其破解。
windows的窗口都有句柄,窗口里的控件也一样有句柄
先得到句柄

在VS工具栏下选择spy++(64)
在弹出的窗口选择这里写图片描述会再弹出一个窗口,此时将这里写图片描述拖到窗口的按键上,handle窗口就会显示出它的句柄。此时得到0x000607B2
新建一个控制台项目,用c语言写,包含

#include <Windows.h>

int main()
{
    Sleep(3000);//等待3S
    SendMessage((HWND)0x000607B2, WM_LBUTTONDOWN, 0, 0);//给指定的句柄发送消息,发送一个鼠标左键按下消息 HWND是把数字强转为句柄

    SendMessage((HWND)0x000607B2, WM_LBUTTONUP, 0, 0);//给指定的句柄发送消息,发送一个鼠标左键抬起的消息
    return 0;

}

此时可以发现打开的程序中,原来不能按的按钮(虽然还是不能按),但其按下去产生的结果出现了

IDE实例

在VS中创建一个MFC工程,
这里写图片描述
选择基于对话框
后面框架样式选择最大化框,最小化框,然后一直next到完成,此时可以得到一个可编辑的图形的界面。
把上面所有的按钮删除,并从左边
这里写图片描述
的Toolbox中选择Edit Control放到界面中,可以调整它的大小,然后在右下角调整它的属性:
这里写图片描述
将Want Return 和Multiline调整为true,分别代表回车换行和允许多行输入。此时可以F5试着运行一下。
这里写图片描述
可以在空白的编辑框中输入文字,并且可以输入多行,但是可以发现,当拖动它的边框,调整外面边框的大小后,内部的小编辑框大小不会改变,且没有拖动条。需要进一步改进
首先是滚动条
这里写图片描述
将Horizontal/Vertical Scroll调成True可以发现编辑界面多了滚动条如图
这里写图片描述
第二呢就是把这个空白的编辑窗口弄得和窗口一样大。
右键这个窗口,添加变量,类型control ,起个名字edit1,那么完成之后,可以发现ideDlg.h文件中多了一行

public:
    afx_msg void OnBnClickedOk();
    afx_msg void OnEnChangeEdit1();
    CEdit edit1;//多出来的代码

然后去它的cpp代码中,去添加代码,实现编辑窗口和实际的窗口一样大

void CIDEDlg::OnPaint()//窗口大小发生改变的时候会调用它
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CRect rect;//MFC提供类,实现了一个矩形结构
        GetClientRect(&rect);//得到窗口客户区大小
        edit1.SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), 0);//设置edit1的位置和大小(0,0)指的是相对窗口的坐标  这三行代码实现了编辑窗和实际窗口大小相同
        CDialogEx::OnPaint();
    }
}

当窗口变化时,就会调用上面这个函数,通过添加三行函数就可以实现了

下面给它添加一个菜单,右键资源管理文件夹,这里写图片描述选择添加,添加新的资源,再选menu就可以打开一个菜单编辑器
这里写图片描述
现在来编辑里面的内容
这里写图片描述
此时这些菜单选项是没有用的。返回到对话框那里,发现对话框属性里的menu,把它改成刚刚编辑的菜单名字
再F5运行一下
得到如下结果:
这里写图片描述
下一步,给菜单栏添加一些功能,首先回到菜单项,右键菜单中的退出,选择添加事件
这里写图片描述

这里写图片描述
注意修改类和消息类型
点Add and Edit后,发现进入代码编辑界面,也就是点击退出会执行的代码

void CIDEDlg::OnBnClickedOk()
{
    // TODO: Add your control notification handler code here
    //CDialogEx::OnOK();
}


void CIDEDlg::OnEnChangeEdit1()
{
    // TODO:  If this is a RICHEDIT control, the control will not
    // send this notification unless you override the CDialogEx::OnInitDialog()
    // function and call CRichEditCtrl().SetEventMask()
    // with the ENM_CHANGE flag ORed into the mask.

    // TODO:  Add your control notification handler code here
}


void CIDEDlg::On32775()//退出菜单对应的执行函数
{
    // TODO: Add your command handler code here
    CDialogEx::OnCancel();//把上面点击OK的执行代码修改一下放到这里
}

然后就实现了退出的功能

下面是帮助中的关于,其实系统已经准备好了关于的文件,在资源文件IDE.rc中
这里写图片描述
是这个样子的
这里写图片描述
然后就可以对其进行编辑= =
在IDEDlg.cpp文件中这两行代码就是弹出窗口的代码,我们把它复制到关于菜单下(步骤和退出按钮相同)

CAboutDlg dlgAbout;
dlgAbout.DoModal();

下面我们来看看文件菜单下的打开
为其添加事件
在执行代码中,添加

CFileDialog cf(TRUE);//这是一个MFC提供的类,功能是弹出一个文件对话框,TRUE代表打开对话框,FALSE代表保存
if(cf.DoModal()==IDOK);//实现打开,且用户按得是确定
{
CString cs;//MFC提供的字符串类,CString在宽码配置下是一个UCS2编码格式的字符串
//需要把宽码格式的字符串转化为GBK格式的字符串
cs=cf.GetPathName();//返回文件路径+文件名
//MessageBox(cs);//弹出一个对话框,对话框里显示这个字符串
CStringA file_name(cs);//调用CStringA的构造函数,将宽码字符串转化为ASCII字符串,GBK基于ACSII
FILE *p=fopen(file_name.Getbuffer(),"rb");//并不能直接用file_name应为CStringA并不是const char*
CStringA content;//存放文件的内容
if(p)
{
    while(ifeof(p))
    {
        char buf[1024]={0};
        fgets(buf,sizeof(buf),p);//读一行
        content+=buf;//字符串追加

    }
    fclose(p);
    CString con;
    con=content;//吧ASCII字符转化为宽码

    edit1.SetWindowText(con);//设置edit1内容
}
}
//如果按的取消,程序什么都不做

保存和打开很像

CFileDialog cf(False);//这是一个MFC提供的类,功能是弹出一个文件对话框,TRUE代表打开对话框,FALSE代表保存
if(cf.DoModal()==IDOK);//实现打开,且用户按得是确定
{
CString cs;//MFC提供的字符串类,CString在款吗配置下是一个UCS2编码格式的字符串
//需要把宽码格式的字符串转化为GBK格式的字符串
cs=cf.GetPathName();//返回文件路径+文件名
CString con;
edit1.GetWindowText(con);//将用户在edit中输入的内容放入变量con
CStringA content(con);//把宽码转化为ASCII字符串
CStringA file_name(cs);
FILE *p=fopen(file_name.Getbuffer(),"w");
fputs(content.GetBuffer(),p);
fclose(p);
}
//如果按的取消,程序什么都不做

下面设置新建,只要加这两句就行了

CString cs;
edit1.SetWindowText(cs);

下面来看复制

edit1.Copy();

同理,粘贴

edit1.Paste();

剪切

edit1.Cut();

以上大概是实现了一个记事本的功能,下面来实现编译的功能
在按钮中添加编译,并添加事件
之前写的file_name 是局部的,我们把它放到.h里面去,它的功能就是得到用户保存的文件名

private:
    CStringA filename;

加了这句之后,之前的file_name 就要进行一次赋值操作

filename=file_name;//目的是在其他函数中得到用户保存的文件名

我们使用gcc来编译,在编译按钮的程序中,我们添加

CSstringA destname=filename;
destname.Replace(".c",".exe");//把文件名换成.exe
CStringA cmd="gcc -o "+ destname+filename;//得到命令行中的形式
system(cmd.Getbuffer());

下面是运行

CSstringA destname=filename;
destname.Replace(".c",".exe");//把文件名换成.exe
system(destname.Getbuffer());

浏览器

加入一个文本编辑框,调整其大小,可以在里面输入网址,原来窗口上带的确定和取消分别改成进入网页和退出,并调整其位置
首先需要在窗口上右键,点击插入ActiveX控件如图
这里写图片描述
为文本编辑框添加变量,名叫text1,且类型为string,代表用户输入的网址
然后给控件添加变量,类别为control,名字叫web
然后和之前的程序一样,把控件的大小调整成和窗口一样,直接复制之前的代码就可以,但是发现它甚至覆盖了按钮= =太大了,就需要把它向下调整:

CRect rect;//MFC提供类,实现了一个矩形结构
        GetClientRect(&rect);//得到窗口客户区大小
        edit1.SetWindowPos(NULL, 0, 50, rect.Width(), rect.Height()-50, 0);//设置edit1的位置和大小(0,0)指的是相对窗口的坐标  这三行代码实现了控件和实际窗口大小相同,经过调整,再将其向下移动一点

然后调整确定的代码,添加如下代码

UpdateData(True);
web1.Navigate(text1,NULL,NULL,NULL,NULL);

再添加一个按钮实现返回
在这个按钮的代码中添加

web1.GoBack();

猜你喜欢

转载自blog.csdn.net/qq_21747841/article/details/78483998