zoukankan      html  css  js  c++  java
  • 指针与数组的区别 —— 《C语言深度剖析》读书心得

    原书很多已经写的很清楚很精炼了,我也无谓做无意义的搬运,仅把一些基础和一些我自己以前容易搞混的地方写一下。


    1. 意义:

    指针:

    指针也是一种类型,长度为4字节,其存放的内容只能是一个地址(4字节)。

    比如

    char* ptr;

    ptr指向一个地址,而这个地址理想的情况下存放着一个char型数据,特殊情况下也可能会指向NULL,甚至变成野指针

    数组:


    数组代表的是一段连续的内存地址,而并非指针那样代表的只是一个地址。

    一般数组会有名字,比如

    char a[100] ;

    即把一段长度为100个sizeof(char)的地址段命名为a。数组也可能是匿名的,比如数组指针

    char (*p)[10];

    这里的数组没有名字,但是数组的首地址存放在p指针中。

    对于具名数组(比方说char a[10];),a代表的是数组首元素(即a[0])的首地址,而&a代表的是整个数组的首地址。尽管a与&a一般相等,但意义上有所区别。最简单做个实验,看看(a + 1)和(&a + 1)的结果,你会发现

    1 char a[10];
    2 // Assuming that a == 0x0012ff6c
    3 
    4 (a + 1) == 0x0012ff6c + sizeof(char)
    5 (&a + 1) == 0x0012ff6c + 10 * sizeof(char)

     P.S. a的地址不可修改,即不能出现a作为左值的情况(诸如a = ptr是错误的),但可以ptr = a获取a的首元素的首地址。


    2. 声明定义:

    指针:

     1 // 声明,切记此时的ptr是必须初始化的,一般暂时不用会将其指向NULL。
     2 char* ptr1;
     3 // Definition
     4 ptr1 = NULL;
     5 char* ptr2 = NULL;
     6 
     7 int i;
     8 char* ptr3 = &i;
     9 
    10 char* ptr4 = (char *) malloc(6sizeof(char));  // 意义和匿名数组中 char(*ptr4)[6] 一样,只不过申请方式有所区别。
    11 
    12 char* ptr5 = new char[6];  // C++适用, new 和 malloc的区别在此不赘述

     这里注意,指针声明的时候其类型是(char *),也就是说实际上是 (char *) ptr1,这就是为什么下面赋值的时候只需要ptr1 = NULL即可,而不是*ptr1 = NULL。对于一个指针类型ptr,*是取ptr指向的地址所存放的内容。

    数组:

    1 char* a[6];
    2 char* b[6] = {'l', 'h', 'f', 'c', 'w', 's'};
    3 char* c[] = {'l', 'h', 'f', 'c', 'w', 's'};

    3. 访问:

    访问有两种形式:

    1. 以下标方式访问: p[3]

    2. 以指针方式访问: *(a+1)

    指针和数组都具有这两种访问方式。

    指针:

     1 char* s = "Lhfcws";
     2 s = s + 1; // 将s指针以后一位
     3 
     4 printf("%s", s); // 输出 hfcws , L没了。
     5 
     6 printf("%c", s[0]);  // 输出 h
     7 
     8 printf("%c", *(s));  // 输出 h
     9 
    10 // 注:即使此时s = s + 5 编译器也不会报错(有的会warning),但是一般在做这种指针操作的时候要做检查,因为超出范围指针会指向不可预料的地方。

     这里注意,指针声明的时候其类型是(char *),也就是说实际上是 (char *) ptr1,这就是为什么下面赋值的时候只需要ptr1 = NULL即可,而不是*ptr1 = NULL。对于一个指针类型ptr,*是取ptr指向的地址所存放的内容。

    数组:

     1 char a[] = "Lhfcws";
     2 
     3 // a = a + 1;  此处会报错,a不可作为左值。
     4 
     5 
     6 printf("%c", a[0]);  // 输出 L
     7 
     8 printf("%c", *(a));  // 输出 L
     9 
    10 // 插一个 strlen 函数,这里是我曾经忽略的地方,strlen会检查到结束,和字符数组原来长度没有关系。
    11 printf("%d", strlen(a));   // 6
    12 
    13 a[5] = 0x00;   //
    14 
    15 printf("%d", strlen(a));   // 5

    4. 传参:

    指针:

     1 char* ptr;
     2 char* ha = "hahaha";
     3 
     4 void reset(char* str) {
     5   str = ha;
     6 }
     7 
     8 void myoutput(char* str) {
     9      str[0] = 'l';
    10      printf("%s", str);   
    11 }
    12 
    13 void main() {
    14   ptr = new char[6];
    15   strcpy(ptr, "Lhfcws");
    16 
    17     myoutput(ptr);      // 输出 lhfcws
    18     printf("%s", ptr);    // 还是输出 lhfcws
    19   reset(ptr);
    20   printf("%s", ptr);    // 还是输出 lhfcws
    21 
    22 }

     上述例子中:

    myoutput 因为传的是指针,所以即使你只是在函数里局部修改,他也会影响到内存里变量的内容。

    reset并未改变原内存上的内容,而只是将str的指针指向了另一块内存。(这点和许多语言机制是一样的,要区分修改对象内容和变量名绑定)

    数组:

     1 void fun(char a[10])
     2 {
     3     char c = a[3];
     4     printf("%c
    ", c);
     5 
     6     a[0] = 'A';
     7   i = sizeof(a);
     8 }
     9 
    10 void fun1(char *p)
    11 {
    12     char c = p[3];//或者是 char c = *(p+3);
    13     printf("%c
    ", c);
    14 
    15     p[1] = 'B';
    16 }
    17 
    18 int main()
    19 {
    20     char b[100] = "abcdefg";
    21     fun(b);
    22     fun1(b);
    23     printf("%s
    ", b);
    24     return 0;
    25 }

     结果为:

    d
    d
    ABcdefg
    

     但注意,fun中传进去参数写着 char a[10], 但实际上,C 语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。

    可以查看一下 i 值,应为 4.


    5. 指针数组和数组指针:

    同样还有函数指针和指针函数,其实很好分辨。语文里有个概念叫偏正短语。即两个名词连在一起,前面那个名词起的是修饰作用,真正做名词的还是后面那个。

    指针数组:

    就是存放指针的数组。如 int * a[10];

    数组指针:

    就是指向数组的指针。如 int (* p)[10]; (* 和 [] 的优先级问题此处不赘述)

    P.S.

    函数指针:

    1 char * (*pf)(char * p1,char * p2);
    2 pf = &fun;    // 假设已经定义 fun(char* p1, char* p2)
    3 (*pf) ("aa","bb");

    指针函数:

    就是返回类型为一个指针的函数:

    char *strstr(char *str1, char *str2);
  • 相关阅读:
    在字符串中查找指定字符(15)
    说反话 (20)
    鼠标经过显示问题
    Java数据库连接池-proxool
    mysql中MAX()函数和count()函数的技巧使用
    Java中多线程问题
    eclipse开发文档模板
    方法调用中的别名问题
    php类的定义
    通知浏览器下载文件,而不是直接打开下载
  • 原文地址:https://www.cnblogs.com/lhfcws/p/3203969.html
Copyright © 2011-2022 走看看