数组指针和字符串

Posted danzel-aria233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组指针和字符串相关的知识,希望对你有一定的参考价值。

刚刚结束了第六章的学习,这里结合一下老师发的ppt和大纲外加教材来小小的自我总结一下

第六章 数组、指针和字符串

 

6.1数组

  •  数组的初始化时,第一维的下标个数可以不用显式说明:

int a[2][3]={1,2,3,4,5,6};

int a[][3]={1,2,3,4,5,6};

  上面两种等价。

  • 数组作为函数参数

 

1 void test(int a[][4],int r){
2        a[0][0]=10;      
3 }
4 int main(){
5        int b[3][4]={1};
6        test(b,3);
7 }

 

  与普通的函数参数不一样,这个时候是传递了数组的地址,所以函数中进行的改变,实际数组的元素也会发生改变

  • 对象数组

  声明和访问形式

类名 数组名[下标表达式];

数组名[下标表达式].成员名

   例如:

 

location a[2]={location(1,2),location(3,4)};
cout
<<a[1].x<<","<<a[1].y;

 


 

 

6.2指针

   指针这里越过基本概念,大概知道指针是通过地址指向目标就行,通过实敲代码来理解最好.

  我把几乎所有知识点都敲到了一个代码里面,下面的各段代码有时候需要结合起来看。

6.2.3 * &

  * 是指针运算符,也是解析 

  &是取地址运算符

6.2.4.1 指针的赋值

 1     int a;
 2     int b[]={99};
 3 /*    int *ptr;
 4     ptr=&a;
 5 */
 6     int *ptr=&a;//这两种定义的效果相同,
 7     //ptr是储存的地址,只有定义的时候可以这样定义,改变的时候要把地址给ptr,值给*ptr 
 8     
 9     int *p=b;//数组名称实际上是一个指针常量,所以可以直接给
10     //这种方式也可以 
11 /*    int *p;    p=b;     */
12 
13     a=10;
14     cout<<"a="<<a<<endl;
15     //*ptr++;//这样得出来的指针所指的值不对,a的值也没有改变 
16     *ptr+=1;//这样以后指针对应的a的值改变了 
17     cout<<"a="<<a<<endl;
18     cout<<"*ptr="<<*ptr<<endl;//输出的是地址上的那个值 
19     cout<<"ptr="<<ptr<<endl;//输出的只是地址 
20     cout<<"*p="<<*p<<endl;
21     cout<<"p="<<p<<endl;

 

6.2.4.2 const相关的指针

    /*
    -----------------------------------------------------------------------------------
    */
    cout<<endl<<"----------常指针知识点:------------"<<""<<endl;
    /*注意区分指向常量的指针 和 指针类型的常量*/ 
    const int *p1=&a;//指向常量的指针,代表地址的p1本身可以改变,而指向的值不能改变 ;弱常指针 
    int *const p2=&a;//指针类型的常量,代表地址的p2本身是常量不能改变,而指向的值依然是变量; 强常指针
    int c=108;
    cout<<"*p1="<<*p1<<"  a="<<a<<endl;
    p1=&c;
    cout<<"*p1="<<*p1<<"  a="<<a<<"   c="<<c<<endl;
/*    *p1=110;    此句话会出错,因为这是指向常量的指针*/
/*    p2=&c;此句话也会出错,这是指针类型的常量,指针本身所指向的地址不能改变,此时地址还是a的地址*/
    cout<<"*p2="<<*p2<<"  a="<<a<<endl;
    *p2=19;
    cout<<"*p2="<<*p2<<"  a="<<a<<endl;

 

6.2.4.3 void类型的指针

 1 /*
 2     -----------------------------------------------------------------------------------
 3     */
 4     cout<<endl<<"----------void类型指针------------"<<""<<endl;
 5     void *pv;//但是可以声明void类型的指针 
 6     //void voidobject  不能声明void类型的变量 
 7     int i=5;
 8     pv=&i;
 9     int *pi=static_cast<int *>(pv);
10     //这是强制转换类型,把void指针转换为int指针赋值给pi 
11     cout<<"*pi="<<*pi<<endl;
12     cout<<" pi="<<pi<<endl;
13     cout<<" pv="<<pv<<endl;//pi pv地址一样,只是指针类型不一样 
14     //cout<<"*pv="<<*pv<<endl;
15     //任何类型的指针都可以赋值给void类型的指针变量
16     //void类型指针一般只在指针指向的数据类型不确定时候使用

 

6.2.5指针运算

 1   /*
 2     -----------------------------------------------------------------------------------
 3     */
 4     cout<<endl<<"----------指针的运算------------"<<""<<endl;    
 5     int *pp;
 6 /*    pp+n; 指针pp后方第n个数的地址 
 7     pp++;指针pp后方第1个数的地址 
 8     pp--; 指针pp前方第1个数的地址 
 9 */
10     //*(pp+1)这是pp指向位置后第一个数的内容
11     //等同于 pp[1]        *(pp-1)  =   pp[-1]
12     //空指针
13     pp=0;
14     pp=NULL; //空指针不指向任何地址
15     /*
16     同类型的指针可以做关系运算 > < >= <= == !=
17     可以与空指针(0 NULL )做关系运算
18     多个关系运算可以构成逻辑运算    
19     */ 
20     int ap[5]={0,1,2,3,4};
21     pp=ap;int *qq=(ap+3);
22     cout<<"qq-pp="<<qq-pp<<endl;//指针做减法运算,qq到pp相隔了三个整型数据 
23     //cout<<"qq+pp="<<qq+pp<<endl;没法做加法运算 
24     cout<<"ap[0]=*pp="<<*pp<<endl;
25     (*pp)++;
26     cout<<"ap[0]=*pp="<<*pp<<endl;
27     
28     ap[1]==*pp++;
29     ap[2]==*(pp++);//*pp++ *(pp++)等效,
30     //因为++后置优先级更高,都是先pp++ ,地址变化,再取指针
31     ap[2]==*qq--;
32     cout<<"pp="<<pp<<"  qq="<<qq<<" (ap+2)=&ap[2]="<<&ap[2]<<endl; 
33     cout<<"*pp="<<*pp<<"  *qq="<<*qq<<" ap[2]="<<ap[2]<<endl; 
34     

 

 

  • 举例子例如定义了*p=&a;

  p只是储存了a的地址,*p才是a所代表的值,p++或者对p进行运算都不能改变a,只是改变*p所指向的值。

  这个地址的运算在数组里面有大用处,因为数组元素的地址是连续的。

  • 空指针的地址是0或者NULL

6.2.6 用指针处理数组元素

 1     /*
 2     -----------------------------------------------------------------------------------
 3     */
 4     cout<<endl<<"----------指针处理数组元素------------"<<""<<endl;     
 5     int array[5]={0,1,2,3,4};
 6     //array == &array[0] == &array  数组名其实就是一个指针变量
 7     //array+3 == &array[3]
 8     *array==array[0];
 9     *(array+1)==array[1]; 
10     for(int *pa=array;pa<(array+5);pa++){
11 //    for(int *pa=&array[0];pa<&array[5];pa++)与上一行等价
12 /*  pa指向了数组每个元素的地址,数组的地址是连续的,
13     所以是小于array【5】的地址,pa++是依次后移一个位置 */ 
14         cout<<*pa<< ;    
15     }cout<<endl;

 

  • 教材在6.2.4就讲过,数组的名称实际上就是一个不能被赋值的指针,即指针常量,为上文提到的强常指针(不能改变地址,但是可以通过指针改变所指向的值)

  array=&array=&array[0]  数组名这个指针指向了第一个元素(挺重要的,之后运用挺多)

  array+i=&array[i]  数组的运算

6.2.7指针数组

 1     /*
 2     -----------------------------------------------------------------------------------
 3     */
 4     cout<<endl<<"----------指针数组------------"<<""<<endl;
 5     int l1[]={1,0,0};
 6     int l2[]={0,1,0};
 7     int l3[]={0,0,1};
 8     int *ps[3]={l1,l2}; 
 9     ps[2]=l3;
10     cout<<"ps[0]="<<ps[0]<<"  *ps[0]="<<*ps[0]<<endl; 
11     cout<<"l1="<<l1<<"  &l1="<<&l1<<endl;
12     cout<<"ps[0][0]="<<ps[0][0]<<"  l1[0]="<<l1[0]<<endl;
13     cout<<"&ps[0][0]="<<&ps[0][0]<<"  &l1[0]="<<&l1[0]<<endl;
14     //ps[0]=l1=&l1   ps[1]=l2=&l2;
15     cout<<"*(ps[0]+1)="<<*(ps[0]+1)<<" l1[0+1]="<<l1[1]<<endl; 
16     //ps[i][j]  ==  *(ps[i]+j) 
17     int array2[3][3]={{11,12,13},{21,22,23},{31,32,33}};
18     //*(*(array2+i)+j)  ==  array2[i][j] 

 

数组指针并不是很难,

实际就是一个数组,只不过每一个元素都是指针。

语法形式为:

数据类型 *数组名[下标表达式]

只不过要注意区分数组指针和指针数组的概念(此知识点之后补上)

 

6.2.8 用指针作为函数参数

 

1     /*
2     void fun1(int a,int b);
3     void fun2(int *c,int *d);
4     int p,q,e[],f[];
5     fun1(p,q);
6     fun2(&p,&q);
7     fun2(e,f);
8     //fun1不会改变变量本来的值,变的只是形参,fun2的形参是指针,会改变变量。 
9     */ 

 

6.2.9 指针型函数

语法形式

数据类型 *函数名(参数表){
函数体;
}

基本没有深入讲相关知识点,只是提了一下,所以这里也一笔带过

6.2.10 指向函数的指针

 1 void print(double ){
 2     cout<<"A test"<<endl;
 3 }
 4 void write(double data){
 5     cout<<"this test is "<<data<<endl;
 6 }
 7 double message(double data){
 8     return data;
 9 }
10 class node{
11     public:
12         int n,m;
13         node(int n1){
14             n=n1;
15         };
16         void print();
17     private:
18         int b;
19 };
20 void node:: print(){
21     cout<<"6666"<<endl;
22 } 
23 int main(){
24     cout<<endl<<"----------指向函数的指针-----------"<<""<<endl;
25     //数据类型 (*函数指针名)(形参表)
26     //函数指针名=函数名;   函数指针名=&函数名   两种用法相同 
27     void(*pf1)(double);
28     double(*pf2)(double);
29     print(3.14);
30     pf1=&print;
31     pf1(3.14);
32     pf1=&write;
33     pf1(3.14);
34     //pf1=&message;  有错误,这是void类型的函数指针 
35     pf2=message;
36     cout<<pf2(3.14)<<endl;

 

语法形式:

数据类型 (*函数指针名)(形参表)

这里还涉及到了typedef 这个好像在之前章节讲过,还没看,先放这,一会复习前面章节再补上

6.2.11.1对象指针

  感觉和数据指针函数指针这些都大同小异

  用途:多态的实现

  Ps:定义对象的时候会调用类的构造函数,而指针不会。

  可以通过指针来调用对象的成员,不过有特殊形式

对象指针名->成员名

  Or

(*对象指针名).成员名

 

6.2.11.2this 指针

这个指针是直接隐藏于类的每一个非静态成员函数里面的

主要是知识点,教材上也没有实际运用

据说函数形参名称于类的数据成员名称一样,可以用这个区分

大概是

Class node{

       Public:

              Int n;

              Void print(int n){

                     This->n=n;}

}

6.2.11.3指向类的非静态成员指针(指向成员的指针)

       不考这个知识点,暂时空出来以后再说。

 


 

6.3动态内存

 1 class node{
 2     public:
 3         node(){
 4             cout<<"调用了默认构造函数"<<endl; 
 5         }
 6         node(int x,int y){
 7             this->x=x;
 8             this->y=y;
 9             cout<<"调用了构造函数"<<endl;
10         }
11         ~node(){
12             cout<<"调用了析构函数"<<endl; 
13         }
14         void move(int newx,int newy);
15     private:
16         int x,y;
17 };
18 
19 inline void node::move(int newx,int newy){
20     x=newx;y=newy;
21 }
22 
23 int main(){
24     int *p1=new int(6);
25     int *p2=new int();//int *p2=new int;
26     cout<<"p1="<<p1<<" *p1="<<*p1<<endl;
27     delete p1;
28     delete p2;
29     *p1=1;//delete删除了指向的内存空间,指针本身还在 
30     node *pn;
31     pn=new node;
32     delete pn;
33     pn=new node(1,1);
34     delete pn;
35     cout<<"----------申请多个--------"<<endl;
36     //申请多个动态对象数据
37     node *p=new node[2];
38     p[0].move(1,2);
39     p[1].move(3,4); 
40     delete []p;
41     return 0;
42 }

 

 

 

建立和删除堆对象使用运算符 new 和 delete

(在程序里面用了一下this指针,没有出错,真好)

 


 

6.5深复制和浅复制

啊这部分文字好多(巨懒)

咕咕咕

 


 

6.6 字符串

  • string是c++库黎明预定义的类,可以直接使用
  • 字符串是一个字符型的数组,以 结尾
  • 字符串之间的大小比较:字典序
  • 读入:cin getline

  cin读入字符串会以空格 tab制表符 回车作为分隔符

  getline读入一整行,以回车作为分隔符

getline(cin,字符串名);

getline(cin,字符串名,分隔符);   getline(cin,s1,,);

 

  还有gets get cin.get cin.getline getchar scanf等很多读入方式,之后来做个整合。

 


 

#6.4 vector(老师未讲)

定义形式:

vector<元素类型>数组对象名(数组长度);

调用方式和数组一样的 a[i],比较有用的是里面的size

a.size()就是数组a的大小

课本没有讲太多的用法

诸如此类还有 string pair vector map 等,也等以后一同梳理(咕咕咕

 

以上是关于数组指针和字符串的主要内容,如果未能解决你的问题,请参考以下文章

对数组中的字符串进行排序,使其稀疏

当指针指向数组时,为啥 operator(*) 的值不起作用?

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针