11月学习笔记总结

来源:互联网 发布:电脑远程软件安卓版 编辑:程序博客网 时间:2024/04/28 08:34

2012年11月17日星期六

曾军提供的代码,主要作用是将数字组成的字符串,分解成一个一维数组。

#include "iostream"
using namespace std;
#include "string"

int main()
{
string str = "12345353";
char *p_ch = new char[str.length() + 1];

for(int i = 0; i < str.length(); i++)
{
p_ch[i] = str.at(i);
}
p_ch[i] = '\0';

for(int j = 0; j < strlen(p_ch); j++)
{
cout<<p_ch[j]<<endl;
}
return 0;
}

 

自己测试后,加以注释的代码:

# include <iostream>

# include <string>

using namespace std;

 

int main()

{

         //声明并定义字符串

         string str = "0102335487";                       

         //为字符串申请一个长度为str.length()的动态内存

         char *p_ch = new char[str.length()+1];   //这里的str.length()+1一定要+1

         //用方法at将字符串中的元素循环赋值

         for(int i=0;i<str.length();i++)                     

         {

                   p_ch[i] = str.at(i);

         }                                                      

         p_ch[i]='\0';      //这里有零系统才能结束,没有这句话,系统会不停的输出内存中的垃圾数据,知道碰巧遇到一个零,才会终止。                  

        

         //将赋值的变量循环输出

         for(int j=0;j<strlen(p_ch);j++)

         {

                   cout<<p_ch[j]<<endl;

         }

 

         return 0;

}

问题:1. j<strlen(p_ch),什么意思

           2. p_ch[i]='\0'; 语句中的i,应该是属于上一个for循环中的,i的生命周期应该已经结束,作用域也不在花括号外了,为什么还能调用。

 

关于VC++6.0的编译build和compile的区别(F7与CTRL+F7)

一般人的解释如下:

buid比compile强大一点。运行的时候就知道,时间是不一样的。有人用过下面的方程式:

  BUILD = COMPILE   +   LINK   =   RESULT   IS   EXE  
  COMPILE   =   COMPILE   =   RESULT   IS   DCU

 

而比较专业的解释:

Build是从新编译所有和生成exe有关的文件,无论.pas文件是否修改过,它都会重新生成新的.dcu,并从新链接这些.dcu等等文件。   

Compile是编译修改过的文件,它只生成新修改过的.pas的相应的.dcu,并从新链接这些改变过的.dcu等等文件。

(反正这两个解释我没看懂,但至少知道build比compile做的工作多一些,而且一般我们编程序编译的时候用CTRL+F7,即compile就够了)

 

 

2012年11月18日星期日

在《操作系统》的课程中的C语言编程实验碰到的几个函数:

函数名:sleep

功能:执行挂起一段时间

注:

1.  VC中的sleep函数‘s’要大写,即Sleep;而其他的都是小写。

2.  Sleep()里面,以毫秒为单位;Linux里sleep()以为单位。

 

 

 

2012年11月19日

针对“Z码解读与加密”工作的代码增进:

# include <iostream>

# include <string>

 

using namespace std;

 

int main()

{

         string str = "123455157487814684";

         char *p_ch = new char[str.length()+1];

        

         for(int i=0;i<str.length();i++)

         {

                   p_ch[i]=str.at(i);

         }

         p_ch[i]='\0';

 

         for(int j=0;j<strlen(p_ch);j+=2)

         {

                   cout<<p_ch[j]<<p_ch[j+1]<<endl;

         }

         return 0;

}

 

其中最后一个for循环的j+=2也就是j=j+2,实现了隔一个数字输出的效果,并且修改cout<<p_ch[j]<<p_ch[j+1]<<endl;

所以运行后的结果为:

 

 

 

2012年11月20日星期二

1.       C和C++中动态申请内存:

在C++中,似乎所使用的语句要简单一些,包含的头文件是#include<iostream.h> 申请内存不需要调用函数只要一个关键字new即可。

 

注意昨天“Z码”代码中的语句:

char *p_ch = new char[str.length()+1];

这个语的意思就是为p_ch申请str.length()+1个char型变量的内存空间,注意是方括号,如果是圆括号的话,例如:

int *Array;

Array = new int(10);

就不是申请10个int型变量的内存空间了,而是申请一个int型的内存空间,然后给它赋值为10。

new 是C++的关键字,不是C的,而C++可以使用malloc。

 

以下是C语言中的动态内存申请的说明:

在C语言中要使用动态内存要包含一个头文件即 #include<malloc.h> 或者是#include<stdlib.h>,然后用C语言的系统函数 void * malloc (usigned size);来获得动态分配的内存,这个函数参数是需要申请的内存的字节数,返回的是一个申请到的内存的首地址,这个返回的内存的类型是 void ,所以需要根据需要进行强制类型转换,例如 int *array; array= (int *)malloc(sizeof(int)*10);这样就动态申请到了一个有10个int型变量的内存空间了。

 

相应的补充:现在不是很理解,以后慢慢理解

malloc和free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求,对象在创建对象的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数与析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。

 

2.       函数strlen

“Z”代码中的语句:

for(int j=0;j<strlen(p_ch);j+=2)

其中,strlen()函数包含的头文件是<string>,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止,然后返回计数器值。

百度百科对此函数的介绍:

原型:extern unsigned int strlen(char *s);,在Visual C++ 6.0中,原型为size_t strlen(const char *string);,其中size_t实际上是unsigned int,在VC6.0中可以看到这样的代码:typedef unsigned int size_t;。

  头文件:string.h

  格式:strlen (字符数组名)

  功能:计算字符串s的(unsigned int型)长度,不包括'\0'在内

  说明:返回s的长度,不包括结束符NULL。

 

3.      同上,语句:

char *p_ch = new char[str.length()+1];

其中的str.length()代表的是

String.Length

  Length 属性返回此实例中 Char 对象的个数,而不是 Unicode 字符个数。原因在于一个 Unicode 字符可能会用多个 Char 表示。使用 System.Globalization.StringInfo 类来处理每个 Unicode 字符而不是每个 Char。

 

“Z码”代码增进:

# include <iostream>

# include <string>

 

using namespace std;

 

int main()

{

         string a;

         cout<<"请输入密码:";

         cin>>a;

         //string str = "123455157487814684";

         char *p_ch = new char[a.length()+1];

        

         for(int i=0;i<a.length();i++)

         {

                   p_ch[i]=a.at(i);

         }

         p_ch[i]='\0';

 

         for(int j=0;j<strlen(p_ch);j+=2)

         {

                   cout<<p_ch[j]<<p_ch[j+1]<<endl;

         }

         return 0;

}

 

 

 

 

 

 

 

2012年11月21日星期三

1.      将输入字母大小写转换:

#include <iostream>

#include <cctype>

 

using namespace std;

 

int main()

{

         char letter = 0;

 

         cout << endl

                    << "Enter a letter:";

         cin >> letter;

         cout << endl;

 

         if (isupper(letter))                                                                                                //判断字母为大写为真,则运行以下代码

         {

                   cout << "You entered a capital letter."

                             <<endl;

                   cout << " Converting to lowercase we get "

                             << static_cast<char>(tolower(letter))                                      //由于tolowe()函数返回的值是int类型,因此把它强制转换为char类型。

                             <<endl;

                   return 0;

         }

 

         if (islower(letter))                                                                                                 //判断字母为小写为真,则运行以下代码

         {

                   cout << "You entered a small letter."

                             << endl;

                   cout << "Converting to uppercase we get "

                             << static_cast<char>(toupper(letter))                                            //同上强制转换

                             << endl;

                   return 0;

         }

 

         cout << " You id not enter a letter."

                    << endl;

         return 0;

}

其中,用到了头文件<cctype>中转换字符的函数:tolower()和toupper()。并且这两个函数的返回值是int类型的,所以在一些语句中用了强制转换static_cast<char>(),将int类型强制转换为char类型,并输出(注释中有)。

注意:以上代码描述的是,单字符的大小写转换,那么多字符的只能识别一个字母,比如我输入ea那么程序只能识别e不能识别到a,所以程序只能将e转换为大写。

所以如果需要使用多字节字符(其类型是wchar_t),就可以包含头文件<cwctype>。该头文件的名称和<cctype>只差一个w该文件包含了在<cctype>中声明的所有函数的对应多字节字符。每个测试函数名都在is的后面加上了w,所以它们的名称就变成:

iswupper(),iswdigit(),iswspace()等等

它们都传递多字节字符参数,并且返回一个int值,就像处理char类型的字符函数一样。同样,多字节符转换函数也成为towupper()和towlower()。(to后面加了w),但是对于以上代码修改使得成为转换多字符大小写暂时不能达成。

 

 

2012年11月24日星期六

关于《郝斌数据结构》的链表实现:

1.      为什么是 -858993460?

通过代码的还原,无论是视频教学的代码还是自己的代码如下:

# include <stdio.h>

 

//(是一个结构体)定义了一个数据类型,该数据类型的名字叫做struct Arr,该数据类型含有三个成员,分别是pBase,len,cnt;(只是定义数据类型,并没有定义变量)

struct Arr                           

{

         int * pBase;     //存储的是数组第一个元素的地址

         int len;     //数组所能容纳的最大数组的个数

         int cnt;     //当前数组有效元素数组的个数

                                     //int increment;      //自动增长因子

};

 

void init_arr(struct Arr array);       //初始化

bool append_arr();         //追加,添加元素到末尾

bool insert_arr();    //插入

bool delete_arr();   //删除

int get();  //可以获取到下标为什么的某个值

bool is_empty();     //判断是否空

bool is_fullI(); //判断是否满

void sort_arr();        //排序

void show_arr();     //显示

void inversion_arr();       //倒置

 

 

int main(void)

{

         struct Arr arr; //这一步并没有创建出来arr这个变量,这个变量包括三个成员pBaselencnt,它们在内存中现在还都是垃圾数字,所以就需要下一步的初始化来创建这个数组。(如同刚建好的电影院里面没有观众一样的道理)

 

         init_arr(arr);

         printf("%d\n",arr.len);

 

         return 0;

}

 

void init_arr(struct Arr array)        //结构体变量不能加减乘除但是可以相互赋值

{

         array.len = 98;

}

此时得到的结果都是-85899360,为什么会这样?

所以网上查了一下,原来不光是我有这个疑问。

类似如此的代码:

# include <stdio.h>

 

int main(void)

{

         int a;

         printf("%d",a);

}

得出的结果依然是-858993460

借用别人的经验:

1.当一个未初始化赋值的时候,他在内存就默认保存为-858993460;

2.如果变量的数据类型由于你的运算的溢出了,在内存中系统就自动改为-858993460。

注:一般的书上都会说如果一个变量未付值,系统会给他一个随机值。但实际测试VC++6.0 里实际上是-858993460。TC上的数值是随机,每次都不一样。

 

其他网络分析的观点则是:

1. vc 下未初始化的内存都是ccccccccccccccccccc

2. 设计成0xcccccccc是有特殊用意的……这个好像叫做Poison,未初始化的Pointer去取值的话会出错。肯定有人问为什么不弄成0x00000000,因为空指针是指针的有效状态,可能会误导人,而0xCCCCCCCC在Windows下永远不可能是一个指针的有效状态(不是NULL,不指向一个对象,不指向一堆对象紧接之后的区域),这就是在模拟野指针……

3. 用VC DEBUG编译的就是这个数
-858993460对应HEX为0xCCCCCCCC
0xCC在X86指令集中为int 3
DEBUG这个机制是为了程序出现内存越界时调试器可以捕捉断点这个异常
而在RELEASE下默认直接是内存清零,也就是用VC RELEASE编译以后显示的结果为0

到底如何,以后可能会慢慢清楚的,现阶段学艺不精,看不透,所以这个问题到此为止。

 

2. 数据结构学习——链表,及其内部方法的完善

阶段性代码:

# include <stdio.h>

# include <malloc.h>        //包含了malloc函数

# include <stdlib.h> //包含了exit函数

 

//(是一个结构体)定义了一个数据类型,该数据类型的名字叫做struct Arr,该数据类型含有三个成员,分别是pBase,len,cnt;(只是定义数据类型,并没有定义变量)

struct Arr                           

{

         int * pBase;      //存储的是数组第一个元素的地址

         int len;      //数组所能容纳的最大数组的个数

         int cnt;     //当前数组有效元素数组的个数

                                     //int increment;      //自动增长因子

};

 

 

void init_arr(struct Arr * pArr, int length);      //初始化           //分号不能省掉

bool append_arr();  //追加,添加元素到末尾

bool insert_arr();     //插入

bool delete_arr();    //删除

int get();  //可以获取到下标为什么的某个值

bool is_empty(struct Arr * pArr);    //判断是否空

bool is_fullI();   //判断是否满

void sort_arr();         //排序

void show_arr(struct Arr * pArr);    //显示

void inversion_arr();         //倒置

 

 

 

int main(void)

{

         struct Arr arr;  //这一步并没有创建出来arr这个变量,这个变量包括三个成员pBaselencnt,它们在内存中现在还都是垃圾数字,所以就需要下一步的初始化来创建这个数组。(如同刚建好的电影院里面没有观众一样的道理)

 

         init_arr(&arr, 6);      //不加&,要传递12个字节(三个4字节成员),而加上&,只传递一个地址,地址占4个字节,同时下面的init_arr()函数的参数要改成指针:*pArr

         show_arr(&arr);                //&arr比较好,因为如果写arr的话,也需要传三个成员,12个字节,很麻烦,而地址不存这个问题。

         //printf("%d\n",arr.len);

 

         return 0;

}

 

void init_arr(struct Arr *pArr, int length)         //结构体变量不能加减乘除但是尅相互赋值

{

         pArr->pBase = (int *)malloc(sizeof(int) * length);

        

         if (NULL == pArr->pBase)          //分配失败就会把NULL赋给pBase,同样,分配成功就会把地址分配给pBase

         //所以必须检测,值是否是NULL,如果没有检测,如果没分配成功,就全错了。

         {

                   printf("动态内存分配失败!\n");

                   exit(-1);    //终止整个程序

         }

         else

         {

                   pArr->len = length;

                   pArr->cnt = 0;

         }

         return;               //写个return给别人看到,这个函数写到这里就终止了,不写的话,会给别人造成小小的困扰,别人不清楚到底写完了没有。

}

 

bool is_empty(struct Arr * pArr)

{

         if (0 == pArr->cnt)

                   return true;

         else

                   return false;

}

 

void show_arr(struct Arr * pArr)

{

         /*if (数组为空)——如果很多歌数组的话,就需要用到函数来实现,即bool is_empty(struct * pArr);

                   提示用户数组为空

         else

                   输出数组有效内容)——伪算法*/

        

         if ( is_empty(pArr))          //这里的pArr不能写成&pArr,因为pArr已经是地址了,如果写了&,就代表了取了pArr的地址的地址,所以不需要加&pArr

         {

                   printf("数组为空!\n");

         }

         else

         {

                   for (int i=0; i<pArr->cnt; ++i)

                            printf("%d", pArr->pBase[i]);            //指向pBase这个成员

                   printf("\n");

         }

 

}

 


2012年11月27日星期二

数据结构学习——连续存储数组的算法演示

代码(最终版):

# include <stdio.h># include <malloc.h>//包含了malloc函数# include <stdlib.h>//包含了exit函数//(是一个结构体)定义了一个数据类型,该数据类型的名字叫做struct Arr,该数据类型含有三个成员,分别是pBase,len,cnt;(只是定义数据类型,并没有定义变量)struct Arr{int * pBase;//存储的是数组第一个元素的地址int len;//数组所能容纳的最大数组的个数int cnt;//当前数组有效元素数组的个数//int increment;//自动增长因子};void init_arr(struct Arr * pArr, int length);//初始化//分号不能省掉bool append_arr(struct Arr * pArr, int val);//追加,添加元素到末尾bool insert_arr(struct Arr * pArr, int pos, int val);//插入pos的值从1开始bool delete_arr(struct Arr * pArr, int pos, int * pVal);//删除,并且返回被删除数据,如果改变函数返回类型int delete_arr()那么删除成功与失败就无法判断,因为任何一个值都有可能是真,所以在不改变函数返回值类型的情况下,添加一个指针,int * pVal来接收int get();//可以获取到下标为什么的某个值bool is_empty(struct Arr * pArr);//判断是否空bool is_fullI(struct Arr * pArr);//判断是否满void sort_arr(struct Arr * pArr);//排序void show_arr(struct Arr * pArr);//显示void inversion_arr(struct Arr * pArr);//倒置int main(void){struct Arr arr;//这一步并没有创建出来arr这个变量,这个变量包括三个成员pBase、len、cnt,它们在内存中现在还都是垃圾数字,所以就需要下一步的初始化来创建这个数组。(如同刚建好的电影院里面没有观众一样的道理)int val;init_arr(&arr, 6);//不加&,要传递12个字节(三个4字节成员),而加上&,只传递一个地址,地址占4个字节,同时下面的init_arr()函数的参数要改成指针:*pArrshow_arr(&arr);//写&arr比较好,因为如果写arr的话,也需要传三个成员,12个字节,很麻烦,而地址不存这个问题。append_arr(&arr, 59);append_arr(&arr, 66);append_arr(&arr, -99);append_arr(&arr, -45);show_arr(&arr);/*if (delete_arr(&arr, 4, &val))//将val的地址,发给了函数中的 pVal,这样就可以通过函数内部pVal修改val的值,从而修改主函数的值{printf("删除成功!\n");printf("您删除的元素是:%d\n", val);//注意val需要在前面声明}else{printf("删除失败!\n");}append_arr(&arr, 2);append_arr(&arr, 3);append_arr(&arr, 4);append_arr(&arr, 5);insert_arr(&arr, 7, 99);append_arr(&arr, 6);append_arr(&arr, 7);append_arr(&arr, 8);if (append_arr(&arr, 8)){printf("追加成功!\n");}else{printf("追加失败!\n");}*/show_arr(&arr);inversion_arr(&arr);printf("倒置之后的内容是:\n");show_arr(&arr);sort_arr(&arr);printf("排序之后的内容是:\n");show_arr(&arr);//printf("%d\n",arr.len);return 0;}void init_arr(struct Arr *pArr, int length)//结构体变量不能加减乘除但是尅相互赋值{pArr->pBase = (int *)malloc(sizeof(int) * length);if (NULL == pArr->pBase)//分配失败就会把NULL赋给pBase,同样,分配成功就会把地址分配给pBase。//所以必须检测,值是否是NULL,如果没有检测,如果没分配成功,就全错了。{printf("动态内存分配失败!\n");exit(-1);//终止整个程序}else{pArr->len = length;pArr->cnt = 0;}return;//写个return给别人看到,这个函数写到这里就终止了,不写的话,会给别人造成小小的困扰,别人不清楚到底写完了没有。}bool is_empty(struct Arr * pArr){if (0 == pArr->cnt)return true;elsereturn false;}bool is_full(struct Arr * pArr){if (pArr->cnt == pArr->len)return true;elsereturn false;}void show_arr(struct Arr * pArr){/*if (数组为空)--如果很多歌数组的话,就需要用到函数来实现,即bool is_empty(struct * pArr);提示用户数组为空else输出数组有效内容)--伪算法*/if ( is_empty(pArr)) //这里的pArr不能写成&pArr,因为pArr已经是地址了,如果写了&,就代表了取了pArr的地址的地址,所以不需要加&pArr{printf("数组为空!\n");}else{for (int i=0; i<pArr->cnt; ++i)printf("%d ", pArr->pBase[i]);//指向pBase这个成员printf("\n");}}bool append_arr(struct Arr * pArr, int val){//满时返回falseif(is_full(pArr))return false;//不满时追加pArr->pBase[pArr->cnt] = val;(pArr->cnt)++;return true;}bool insert_arr(struct Arr * pArr, int pos, int val){int i;if(is_full(pArr))return false;if (pos<1 || pos>pArr->cnt+1)return false;for (i=pArr->cnt-1; i>=pos-1; --i){pArr->pBase[i+1] = pArr->pBase[i];}pArr->pBase[pos-1] = val;//该程序有漏洞,万一pos的值是负数怎么办,所以需要判断,前面加if语句(pArr->cnt)++;return true;}bool delete_arr(struct Arr * pArr, int pos, int * pVal){int i;if (is_empty(pArr))return false;if(pos<1 || pos>pArr->cnt)return false;*pVal = pArr->pBase[pos-1];//放在删除操作前面,将等待删除的元素赋给了形参pVal指向的主函数的val,因为函数的返回值中需要删除的元素,在以下的删除操作之后加的话,该元素就没有了。for (i=pos; i<pArr->cnt; ++i){pArr->pBase[i-1] = pArr->pBase[i];}pArr->cnt--;//删除完了,个数减一(同以上增加)return true;}void inversion_arr(struct Arr * pArr){int i = 0;int j = pArr->cnt-1;int t;while (i<j)//典型的a,b两个值互换,步骤:t=a;a=b;b=t;三步搞定。{t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;++i;--j;}return;}void sort_arr(struct Arr * pArr){int i,j;int t;for (i=0; i<pArr->cnt; ++i)//用冒泡排序{for(j=i+1; j<pArr->cnt; ++j){if (pArr->pBase[i] > pArr->pBase[j]){t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;}}}}