写在前头:
我不能保证此文中,我的观点和理解全是对的,这也不是一篇教学贴,只是我偶尔突发奇想了几个特殊的场景,然后用实验得到结果,对结果进行分析,遂成此文。所以文中肯定存在错误,我也没想到会上首页,引来众人围观。
最后,欢迎拍砖,我觉得错了不要紧,改就是了,最惨的是不知道自己错在哪。
首先看一下man手册中的定义,
void *malloc(size_t size);
向系统申请size个Bytes长的连续内存,返回一个void类型的指针,指向这块儿内存的首地址。这块申请到的内存是不洁的(也就是非全0x00,内容可以是任意的,随机的)
如果size的值是0,那么返回的指针要么是指向NULL,要么是指向一个unique的地址,这个地址是可以被free释放的。(这里的解释是有问题的,例子(8)会证明)
void free(void *ptr);
释放ptr指向的内存空间,ptr必须是之前调用过malloc,calloc,realloc这三个函数返回的,否则,如果free(ptr)已经执行过了,而又执行一次,那么会导致意外发生(undefined behavior occurs.),如果ptr指向的是NULL,则不会做任何操作。
(1)假设有
那么p获得的内存块的长度到底是多少?能否往里面写入数据?
答:不妨用这段代码来测试:
这段代码结果如下所示:Fedora14:
我重新编译、运行了很多次,最后打印结果都是135159;
这个结果证明了malloc(0)返回的指针指向的是一个非NULL的内存地址处,并且该处的值是0x00,并且对于该进程,不仅该处是可写的,而且之后的135159个Bytes也都是可写的,也就是属于这个进程空间。直到最后,可能写到别的进程的空间里面去了,才被内核发来段错误信号,自己结束了。
其实在写该处就已经是内存越界了,往后继续写更加是内存越界,只是刚好那么巧,该处往后的内
对话框头文件XXXDlg.h:
1.添加成员变量NOTIFYICONDATA m_nid;
2.添加tray消息响应函数的声明
afx_msg LRESULT OnTrayNotify(WPARAM wParam, LPARAM lParam);
对话框实现文件XXXDlg.cpp:
1.定义tray消息 #define UM_TRAYNOTIFY WM_USER + 11
2.CXXXDlg的构造函数添加
memset(&m_nid, 0, sizeof(m_nid)); // Initialize NOTIFYICONDATA struct m_nid.cbSize = sizeof(m_nid); m_nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
3.CXXXDlg的析构函数添加
m_nid.hIcon = NULL; Shell_NotifyIcon(NIM_DELETE, &m_nid);
4.添加消息映射:
BEGIN_MESSAGE_MAP(CMFC2Dlg, CDialog) //... ON_MESSAGE(UM_TRAYNOTIFY, &CMFC2Dlg::OnTrayNotify) //... END_MESSAGE_MAP()
5.OnInitDialog函数添加:
m_nid.hWnd = GetSafeHwnd(); m_nid.uCallbackMessage = UM_TRAYNOTIFY;
// Set tray icon and tooltip m_nid.hIcon = m_hIcon;
// Set tray notification tip information CString strToolTip = _T("托盘程序"); _tcsncpy_s(m_nid.szTip, strToolTip, strToolTip.GetLength()); Shell_NotifyIcon(NIM_ADD, &m_nid);
6.OnTrayNotify函数的实现: LRESULT CXXXDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam) { UINT uMsg = (UINT)lParam;
switch(uMsg) { case WM_RBUTTONUP: { //右键处理 CMenu menuTray; CPoint point; int id; GetCursorPos(&point); menuTray.LoadMenu(IDR_MENU_TRAY); id = menuTray.GetSubMenu(0)->TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this); #if 0 CString strInfo; strInfo.Format(L"menuid %d", id); LPCTSTR strtmp; strtmp = strInfo.GetBuffer(0); MessageBox(strtmp, L"test"); #endif switch(id){ case IDR_TRAY_EXIT: OnOK(); break; case IDR_TRAY_RESTORE:
//窗口前端显示 SetForegroundWindow(); ShowWindow(SW_SHOWNORMAL); break; default: break; } break; } case WM_LBUTTONDBLCLK: SetForegroundWindow(); ShowWindow(SW_SHOWNORMAL); break; default: break; } return 0; }
7.添加WM_SIZE消息处理:
void CMFC2Dlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy);
if(nType == SIZE_MINIMIZED){ ShowWindow(SW_HIDE); } } 8.菜单。
添加菜单资源 , 比如IDR_MENU_TRAY.
定义一个子菜单Tray,有若干个菜单项,比如“恢复窗口”, ID是IDR_TRAY_RESTORE,“退出”, ID是IDR_TRAY_EXIT。
在OnTrayNotify函数中捕获右击消息,弹出菜单,参考第6步。
至此,添加托盘的功能基本完成。
本文链接
本程序主要利用C语言中链表和文件的相关知识,实现了能够增删改查操作的简易通讯录程序。根目录下的ctt文件是存放通讯录信息的文件,可以直接用文本编辑器打开。但是不要改动固定的格式。代码中,多处出现重复的条件判断,导致代码重复。不过,有机会的话会进行修改。
部分代码如下:
* @Desc:这是一个实现通讯录的C源代码
* @Author:乌鸟
* @Version:0.1
* @URL:http://huxuemail.web-104.com
* @QQ交流群:235173087(欢迎加入)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
//这里定义的是联合体中字符数组的长度。
#define C_NAME_SIZE 10
#define C_SEX_SIZE 3
#define C_AGE_SIZE 5
#define C_PHONE_SIZE 12
#define C_QQ_SIZE 12
#define C_PROVINCE_SIZE 20
#define C_CITY_SIZE 20
#define C_COMMENT_SIZE 100
//亲,很明显,这是函数说明!
void insRecord();//插入一条记录的实现
void inputs(char *prompt,char *info,int count);//插入一条记录时,逐行输入信息的实现
struct addr *linkNode(struct addr *i,struct addr *top);//输入完一条记录后,将当前的缓冲节点连接到链表中的实现
struct addr *find(char *name);//查找出指定的节点的实现
void seaRecord();//查找记录的实现
void delRecord();//删除记录的实现
int selectMenu();//主菜单的实现
void disRecord(addr *info);//显示一条记录的实现
void disRecords();//显示全部记录的实现
void getInfo(); //根据ctt文本中的记录,逐条返回数据项,并实现将信息插入链表,即程序启动的初始化状态的实现
void initInputs(char *initInfo[]);//输入完一条记录后,将当前的缓冲节点连接到链表中的实现
void saveRecords();//将链表中的信息全部写到磁盘文件中的实现
void saveToFile(addr *info);//将每条信息记录放到新建的文件中的实现
void editRecord();//修改记录的实现
void about();//显示作者信息的实现
//全局的东东
//联合体
struct addr
{
char c_name[C_NAME_SIZE];
char c_sex[C_SEX_SIZE];
char c_age[C_AGE_SIZE];
char c_phone[20];
char c_qq[C_QQ_SIZE];
char c_province[C_PROVINCE_SIZE];
char c_city[C_CITY_SIZE];
char c_comment[C_COMMENT_SIZE];
struct addr *next;//pointer to next entry ^^
};
//全局指针变量,info存储当前缓冲的节点、start和last存储最后一个节点、head存储头节点
struct addr *info,*start,*last,*head;
//初始化用,与head有关的变量
static int n = 0;
源代码下载地址
本文链接