深入浅出之指针

一、指针的概念

         在程序中,我们所定义的变量,都要在内存中占有一个可标识的存储区域。每一个存储区域由若干个字节组成,在内存中每一个字节都有一个“地址”,一个存储区域的“地址”指的是存储区域中第一个字节的地址。

       指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”意思是说通过它能找到以它为地址的内存单元。

      指针并不是用来存储数据的,而是用来存储数据在内存中地址,它是内存数据的快捷方式,通过这个快捷方式,即使你不知道这个数据的变量名也可以操作它。

二、指针与指针变量

    2.1 直接访问与间接访问

     直接访问:通过变量名或地址访问程序中一个实体的存储空间方式(直接通过定义的变量来获取变量的数值)

     间接访问:通过把地址存放在一个变量中,然后通过先找出地址变量中值,再由此地址找到最终要访问的变量的方法(通过指针的形式,指向原来变量存储的值)

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个整形变量
    int num = 5;

    //! 定义一个指针
    int *p = &num;

    //! 直接访问形式,就是直接通过原来的变量名来进行访问
    qDebug("%d",num);
    //! 间接的访问形式,就是间接通过指针指向的变量,来间接的访问原来变量的,此处的*为指向的意思
    qDebug("%d",*p);
    return a.exec();
}

输出为:
5
5

2.2 p、*p和&p的区别

p是一个指针变量的名字,表示此指针变量指向的内存地址。

*p表示此指针指向的内存地址中存放的内容,一般是一个和指针类型一致的变量或者常量。
&p就是取指针p的地址。

&p和p有什么区别?
区别在于,指针p同时也是个变量,既然是变量,编译器肯定要为其分配内存地址,就像程序中定义了一个int型的变量i,编译器要为其分配一块内存空间一 样。而&p就表示编译器为变量p分配的内存地址,而因为p是一个指针变量,这种特殊的身份注定了它要指向另外一个内存地址,程序员按照程序的需要 让它指向一个内存地址,这个它指向的内存地址就用p表示。而且,p指向的地址中的内容就用*p表示。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个变量
    int num = 5;
    //! 定义一个指针
    int *p;
    p = &num;
   // *p = 5;

    //! 定义个二级指针
    int **pp;
    pp = &p;

    //! 输出变量num的地址
    qDebug("num address=%x",&num);
    qDebug("num address=%x",p);
    qDebug("num value=%x",*p);
    qDebug("p address =%x",&p);
    return a.exec();
}
输出:
num address=e3b2f850
num address=e3b2f850
num value=5
p address =e3b2f858

2.3 *和&运算

先理解地址和数据,想象内存里面是一个个的小盒子,每个盒子对应一个编号,这个编号就是地址,盒子里存放的就是数据。

&是取地址运算符,如有 int a; 即有一个小盒子里面存放的数据起名叫a,&a就是取a的地址,即该盒子的编号。

*(地址)是取值运算符,这里*是解引用操作符,可以理解成打开对应地址编号的盒子,取出里面的数据。*(&a) 就是打开a对应的小盒子,取出里面的数据,即*(&a)和a等价。

(*p)操作是这样一种运算,返回p 的值作为地址的那个空间的取值。

(&p)则是这样一种运算,返回当时声明p 时开辟的地址。

2.4 *&p和&*p区别

根据运算优先级,*&p 等价于*(&p)。&*p 等价于&(*p)。

1、如果p是int *指针变量,那么*&p = p,&*p = p,都是p。

2、如果p是一个int变量,那么*&p = p;而&*p是非法的,因为*p非法。

比如int p =10;那么*&p = *(&p) = p = 10(即从p的地址取值),而&*p = &(*p) 则非法,因为p=10,*10是取内存地址为10的值,这在c语言中是不合法的。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个变量
    int num = 5;
    //! 定义一个指针
    int *p;
    p = &num;
   // *p = 5;

    //! 定义个二级指针
    int **pp;
    pp = &p;

    //! 输出变量num的地址
    qDebug("p address =%x",*(&p));
    qDebug("p address =%x",&(*p));
    return a.exec();
}
输出:
p address =6ff6f900
p address =6ff6f900

2.5 指针与指针变量区别

系统为每一个内存单元分配一个地址值,C/C++把这个地址值称为“指针”。如有int i=5;,存放变量i的内存单元的编号(地址)&i被称为指针。
“指针变量”则是存放前述“地址值”的变量,也可以表述为,“指针变量”是存放变量所占内存空间“首地址”的变量(因为一个变量通常要占用连续的多个字节空间)。比如在int i=5;后有一句int *p=&i;,就把i的指针&i赋给了int *型指针变量p,也就是说p中存入着&i。所以说指针变量是存放指针的变量。
有一个事实值得注意,那就是有不少资料和教科书并没有如上区分,而是认为“指针是指针变量的简称”,如对int *p=&i;的解释是:声明一个int *型指针p,并用变量i的地址初始化;而严格说应该是声明一个int *型指针变量p才对。所以有时看书要根据上下文理解实质,而不能过于拘泥于文字表述。

2.6 一级指针与二级指针

我们定义一个指针变量int *p; p是指针变量专门用来存放地址

int *p=&a;相当于int *p; p=&a;

p存放的是a的地址,*p也等价于 a。指针变量p既然是变量,也同变量a一样对应一个小盒子,也有一个地址编号,&p就是取指针p的地址。这样就好理解二级指针了。

*p和**p的区别

int *p :一级指针,表示p所指向的地址里面存放的是一个int类型的值

int **p :二级指针,表示p所指向的地址里面存放的是一个指向int类型的指针(即p指向的地址里面存放的是一个指向int的一级指针)

例:

int a=5; //定义整形变量

int *p=&a; //定义一个指针指向这个变量

int **p1=&p; //定义一个二级指针指向p指针 

以上3行输出的值都是5 。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个变量
    int num = 5;
    //! 定义一个指针
    int *p;
    p = &num;
   // *p = 5;

    //! 定义个二级指针
    int **pp;
    pp = &p;

    //! 输出变量num的地址
    qDebug("%x",**pp);
    return a.exec();
}
输出:
5

2.7 sizeof(p) 与 sizeof(*p)

对于任何指针变量p,变量p本身就是指针,它的大小就是指针的大小。p是p指向的,而*p的大小是被指向的大小。

sizeof(p)是指针本身的大小。这取决于地址总线的大小。这意味着对于64位系统,地址总线大小将是64位(8字节),因此指针将是8字节长(这表明您的系统是64位)。在32位系统上,它的大小是32位(4字节)。

如果sizeof(*p)返回的是p所指向的大小,那么您就知道int的大小(在您的例子中p指的是)是4字节,这在32位和64位系统上都是正常的。

例子1:

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个变量
    int num = 5;
    //char num = 5;
    //! 定义一个指针
    int *p;
    p = &num;

    qDebug("size of int = %d",sizeof(int));
    qDebug("size of p = %d",sizeof(p));
    qDebug("size of *p = %d",sizeof(*p));
    return a.exec();
}

输出:
size of int = 4
size of p = 8
size of *p = 4

例子2: 

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个变量
    //int num = 5;
    char num = 5;
    //! 定义一个指针
    char *p;
    p = &num;

    //! 输出变量num的地址
    qDebug("size of char = %d",sizeof(char));
    qDebug("size of p = %d",sizeof(p));
    qDebug("size of *p = %d",sizeof(*p));
    return a.exec();
}
输出:
size of char = 1
size of p = 8
size of *p = 1

 例子3:

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一个数组
    int array[10]={1,2,3,4};

    //! 定义一个指针
    int *p = array;

    qDebug("sizeof of array = %d\n",sizeof(array)/sizeof(array[0]));
    qDebug("sizeof of array = %d\n",sizeof(p)/sizeof(*p));

    return a.exec();
}
输出:
sizeof of array = 10

sizeof of array = 2

2.8 指针初始化

对指针进行初始化或赋值只能使用以下四种类型的值  
:

1. 0 值常量表达式,例如,在编译时可获得 0 值的整型 const对象或字面值常量 0。

2. 类型匹配的对象的地址。

3. 另一对象末的下一地址。

4. 同类型的另一个有效指针。

把 int 型变量赋给指针是非法的,尽管此 int 型变量的值可能为 0。但允许把数值 0 或在编译时可获得 0 值的 const 量赋给指针:

int ival;

int zero = 0;

const int c_ival = 0;

int *pi = ival; // error: pi initialized from int value of ival

pi = zero;// error: pi assigned int value of zero

pi = c_ival;// ok: c_ival is a const with compile-time value of 0

pi = 0;// ok: directly initialize to literal constant 0 [1]

除了使用数值 0 或在编译时值为 0 的 const 量外,还可以使用 C++ 语言从 C 语言中继承下来的预处理器变量 NULL,该变量在 cstdlib头文件中定义,其值为 0。如果在代码中使用了这个预处理器变量,则编译时会自动被数值 0 替换。因此,把指针初始化为 NULL 等效于初始化为 0 值 [1]
 :

// cstdlib #defines NULL to 0

int *pi = NULL; // ok: equivalent to int *pi = 0; [1]

2.9 const 指针

2.9.1 指向常量的指针变量

定义:const 数据类型 *指针变量名 或 数据类型 const *指针变量名

const char *p;
p = "abcd";

//! 错误,指针指向的对象是一个常量,不能被赋值
p[2] = 'e';
//! 正常,可以修改指针变量p的值
p='ghjk';

注意:指针变量指向的对象的值不能被改变,而指针变量的值可以改变(可以改变指向),本质是指向内容是常量,而指针还是变量。

2.9.2 指向变量的指针常量

 定义:数据类型 * const 指针常量名

char str[]="abcd";
char *const p=str;

//! 正确,指针p指向的对象是一个变量
p[3] = 'e';
//! 错误,指针p指向对象是一个常量
p="ghjk";

注意:指针常量的值不能修改,而指针常量所指向的值是可以修改的,本质指针是常量,而指向内容是变量。

2.9.3 指向常量的指针常量

定义 :const 数据类型 * const 指针常量

char str[]="abcd";
const char * const p = str;
//! 错误,指针常量所指向的对象是一个常量
p[3]='e';
//! 错误,指针常量是一个常量
p="ghjk";

注意:指针常量的值和指针常量所指向的对象的值均不能改变。

2.10 void指针类型

void指针类型,可以用来指向一个抽象类型的数据,在将它的值赋给另一个指针变量时,要进行强制类型转换使之适合于赋值的变量的类型。

char *p1;
void *p2;

p1 = (char *)p2;//! (char *)表示强制转换成,强制将空指针转换成字符型指针

2.10 int *p = 5对不对?

     5是int型,p是int *型,等号两边类型不匹配。

    写成int *p=(int *)5;就对了。把整数5 强制类型转换为整型指针, 在赋值给整型指针p,这个时候p 指向 地址 0x00000005 所表示的内存空间

三. 指针与数组 

3.1 一维数组的指针表示方法

a[i]       下标法

*(a+i)    地址法

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 定义一维数组
    int array[] = {1,3,5,7,9};
    //! 定义指针
    int *p;

    //! 下标法
    for (int i = 0; i < 5; i++){
        qDebug("array1 = %d",array[i]);
    }
    //! 地址法
    for(int i = 0; i < 5; i++){
        qDebug("%array2 = %d",*(array+i));
    }
    //! 指针法
    /*for (p = array; p < array+5; p++)
    {
        qDebug("array3=%d",*p);
    }*/
   /* p = array;
    for (int i = 0; i < 5; i++,p++){
        qDebug("array3=%d",*p);
    }*/
    for (int i = 0; i < 5; i++){
        qDebug("array3=%d",*(p+i));
    }
    return a.exec();
}

以上几种表示方法均可以,但如下几种方式不可以,因为a的值是数组首地址,它是一个常数,其值是不能自增的。指针p是变量,p的值可以不断变化,而p的值是地址,因此p可以不断改变其指向。

for (int i = 0; i < 5; i++){
    qDebug("array=%d",a++);
}

 3.2 二维数组的指针表示方法

含义表示形式备注
第0行第1列元素地址a[0]+1,*a+1,*(a+0)+1,&a[0][1]
第0行第1列元素的值*(a[]0]+1),*(*a+1),a[0][1]
#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int array[2][2]={1,2,3,4};
    int *p;
    for (p=array[0];p<array[0]+4;p++){
        qDebug("array=%d",*p);
    }
    for (p=*array;p<*array+4;p++){
        qDebug("array=%d",*p);
    }
    for (p=&array[0][0];p<&array[0][0]+4;p++){
        qDebug("array=%d",*p);
    }
    return a.exec();
}

指针的类型取决于它所指向的对象,如果将p=a[0]改写成p=a就会出错,虽然是a[0]和a的值相同,但是a是二级指针,而a【0】是一级指针,二者的指向的对象不同,类型不同;

二维数组中的一级指针和二级指针可以用行指针和列指针来说明,二级指针(数组名)指向行,一级指针用来指向的是某行的中的列。指向行和指向列的指针不是同一类型的指针。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int array[2][2]={1,2,3,4};
    int (*p)[2];
    p =array;
    for (int i = 0; i < 2; i++){
        for (int j = 0; j < 2; j++){
        qDebug("array=%d",*((*p+i)+j));
        }
    }
    return a.exec();
}

上列中p是指向行的指针变量,因此应该赋予它行地址,于是p=a是合法的。 

3.3 指针与字符数组

字符串是存放在字符数组中的。因此为了对字符串操作,可以定义一个字符数组,也可以定义一个字符指针,通过指针的指向来访问所需要的字符。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    char string[]="C Language";
    char *p;
    p = string;
    qDebug("%s",string);
    qDebug("%s",p);
    return a.exec();
}

常用的字符串函数: 

1strcpy(s1, s2);
复制字符串 s2 到字符串 s1。
2strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾。
3strlen(s1);
返回字符串 s1 的长度。
4strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。
5strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    char str1[11] = "Hello";
    char str2[11] = "World";
    char str3[11];
    char ch='o';
    char str4[] = "orl";
    int  len ;

    //! 复制 str1 到 str3
    strcpy( str3, str1);
    qDebug("strcpy( str3, str1) : %s",str3);

    //! 连接 str1 和 str2
    strcat( str1, str2);
    qDebug("strcat( str1, str2): %s",str1);

    //! 连接后,str1 的总长度
    len = strlen(str1);
    qDebug("strlen(str1) : %d",len);

    //! 查找字符ch
    char *pos = strchr(str1,ch);
    qDebug("strchr :%d",pos-str1);

    //! 查找字符串
    pos = strstr(str2,str4);
    qDebug("strchr :%d",pos-str2);

    //! 字符串比较
    int ret = strcmp(str1,str2);
    qDebug("strcmp :%d",ret);
    return a.exec();
}
输出:
strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10
strchr :4
strchr :1
strcmp :-1

3.4 指针数组与数组指针

3.4.1 指针数组

指针数组:首先是一个数组,而数组的元素是指针,也就是说,如果数组元素都是相同类型的指针,则称这个数组为指针数组。所谓相同类型的指针是说指针所指向的对象类型是相同的。指针数组是数组元素为指针的数组,其本质为数组。

定义形式:int *p【10】

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 指针数组
    int ix=0;
    int array[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
    int *p[3];
    for(ix;ix<3;ix++) p[ix]=array[ix];
    for(int i = 0;i<3;i++)
    {
        for(int j=0;j<4;j++)//注意这里的j要赋值等于0,要不然只能输出第一行1234,达不到预期的效果
        {
            qDebug("%d",p[i][j]); //或者 *(*(p+i)+j) 或者 *(p[i]+j)
        }
    }

    }
    return a.exec();
}

3.4.2 数组指针

数组指针是指向数组首元素的地址的指针其本质为指针(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动);

定义方法:(*指针变量名)[长度]即(*P)[n]

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //! 数组指针
    int array[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
    int (*p)[4];
    //p=(int(*)[4])array;
    p =array;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4;j++) {
            qDebug("%d",p[i][j]); //或者 *(*(p+i)+j) 或者 *(p[i]+j)
        }
    }

    return a.exec();
}

3.4.3 二者区别

1) 定义形式:

指针数组:int *p【10】

数组指针:int (*p)【10】

“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10 个指向int 类型数据的指针,即指针数组。至于p2 就更好理解了,在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。我们可以借助下面的图加深理解:

2) 所占存储空间的区别

数组指针只是一个指针变量,是C 语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间.




3)应用上的区别

指针数组一般用于处理二维数组。指向一维数组的指针变量用于处理二维数组也是非常方便的。

数组指针和指针数组在处理同一个二维数组时,数组指针的元素个数和指针数组的数组长度不相同,数组指针的元素个数和二维数组的列长度相同。 而指针数组的数组长度和二维数组的行长度相同。

在处理字符串的问题上,使用指针数组处理就比使用数组指针方便多了。因为多个字符串比用二维字符数组处理字符串更加方便,更加的节省内存空间。

相比于比二维字符数组,指针数组有明显的优点:一是指针数组中每个元素所指的字符串不必限制在相同的字符长度;二是访问指针数组中的一个元素是用指针间接进行的,效率比下标方式要高。 但是二维字符数组却可以通过下标很方便的修改某一元素的值,而指针数组却无法这么做。

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int i;

    const char *string[3] = {"Mei","Zuo","Chuan"};

    const char* p;
    if (strcmp(string[0],string[1]) > 0){
        p = string[0];
        string[0] = string[1];
        string[1] = p;
    }

    if (strcmp(string[0],string[2]) > 0){
        p = string[0];
        string[0] = string[2];
        string[2] = p;
    }

    if (strcmp(string[1],string[2]) > 0){
        p = string[1];
        string[1] = string[2];
        string[2] = p;
    }



    for(i=0;i<3;i++){
        qDebug("%s, ",string[i]);

    }
    return a.exec();
}

4. 指针与函数

4.1 指针作为函数参数

#include <QCoreApplication>
void sub(int *px,int *py){
   qDebug("sub:%d",*px-*py);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int x = 20,y = 10;
    sub(&x,&y);

    return a.exec();
}

用指针(地址)作为函数参数,可以“实现通过被调用的函数改变主函数中变量的值”的目的。

4.2 数组指针作为函数参数

实参形参
数组名数组名
数组名指针变量
指针变量数组名
指针变量指针变量
#include <QCoreApplication>

int arr_add(int arr[],int n){
    int sum = 0;
    for (int i = 0; i < n; i++){
        sum = sum+arr[i];
    }
    return sum;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int *p,total;
    p = array[0];
    total = arr_add(p,12);
    qDebug("%d",total);

    return a.exec();
}
输出:total=78

数组名代表数组的起始地址,用数组名作为参数传递的是地址(将数组起始地址传给被调用函数的形参),既然地址可以作为参数传递,那么指向数组的指针变量也可以作为函数参数。

#include <QCoreApplication>

int arr_add(int *arr,int n){
    int sum = 0;
    for (int i = 0; i < n; i++){
        sum = sum+*(arr+i);
    }
    return sum;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int *p,total;
    p = array[0];
    total = arr_add(p,12);
    qDebug("%d",total);

    return a.exec();
}

4.3 指向函数的指针(函数指针)

一个函数包括一系列的质量,在内存中占据一片存储单元,它有一个起始地址,即函数的入口地址,通过这个地址可以找到该函数,这个地址就称为函数的指针

函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。

定义:类型标识符 (*指针变量名)(形参列表)

int (*p)(),它表示p指向一个返回整型值的函数,注意*p两侧的括弧不能省略,如果写成int *p()就成了返回指针值的函数。

#include <QCoreApplication>

int arr_add(int *arr,int n){
    int sum = 0;
    for (int i = 0; i < n; i++){
        sum = sum+*(arr+i);
    }
    return sum;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int *p,total;
    p = array[0];
    int (*pt)(int *arr,int n);
    pt = arr_add;
    total = (*pt)(p,12);
    qDebug("%d",total);

    return a.exec();
}

注意:在用指针变量调用函数之前,应先将函数入口地址赋给指针变量。

4.4 指针函数

指针函数是一个函数。函数都有返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。

类型名 *函数名(函数参数列表);

#include <QCoreApplication>

int* arr_add(int *arr,int n){
    static int sum = 0;
    int *point;
    point = &sum;
    for (int i = 0; i < n; i++){
        sum += *(arr+i);
    }
    return (int *)point;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    //float arr_add(),arr_avr();
    int *p;
    p = array[0];
    int* (*pt)(int *arr,int n);
    pt = arr_add;

    int *total = (*pt)(p,12);

    return a.exec();
}
输出:
78

如果static去掉,这样是不对的。因为sum是个局部变量,返回的是sum的地址的副本。而该函数在结束时会回收sum,sum地址指向的值会被后续的别的函数分配和更改。如果使用该指针指向的值会是不确定的。因此才有“永远不要从函数中返回局部自动变量的地址“。

4.5 main函数的参数

 main(int argc,char *argv[]),第一个形参argc是个整型变量,第二个形参argv是一个指针数组,其元素指向字符型数据。

int main(int argc,char *argv[]){

    while(argc > 1){
         ++argv;
         printf("%s",*argv);
         --argc;
    }
}

如果从键盘输入的命令:cfile cmputer C_Language

则输出:

computer

C_Language

5. 指针小结

定义形式含义
int *p;p指向整型数据的指针变量
int (*p)[n]

p为指向含有n个元素的一维数组的指针变量,数组指针

int(*p)()p为指向函数的指针,该函数返回一个整型值,函数指针
int *p[n]定义指针数组,它含有n个元素,每个元素指向一个整形数据,指针数组
int *p()p为带回一个指针的函数,该指针指向整型数据,指针函数
int **pp是一个指针变量,它指向一个指向整型数据的指针变量,即指向指针变量的指针,二级指针
int (**p)[n]p是一个指向另一个指针变量的指针变量,被指向的指针变量指向一个含有n个整型数据的一维数组

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值