精华内容
下载资源
问答
  • C语言指针理解C语言指针理解C语言指针理解
  • 深入理解C语言指针

    万次阅读 多人点赞 2019-09-28 08:36:51
    而这个编号可以暂时理解指针,就像酒店的门牌号一样。 1.1、变量和地址 先写一段简单的代码: void main(){ int x = 10, int y = 20; } 这段代码非常简单,就是两个变量的声明,分别赋值了 10、20。我们把内存...

    一、指针的概念

    要知道指针的概念,要先了解变量在内存中如何存储的。在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为指针,就像酒店的门牌号一样。

    1.1、变量和地址

    先写一段简单的代码:

    void main(){
    	int x = 10, int y = 20;
    }
    

    这段代码非常简单,就是两个变量的声明,分别赋值了 10、20。我们把内存当做一个酒店,而每个房间就是一块内存。那么“int x = 10;”和“int y = 20;”的实际含义如下:

    1. 去酒店订了两个房间,门牌号暂时用 px、py 表示
    2. 让 10 住进 px,让 20 住进 py
    3. 其中门牌号就是 px、py 就是变量的地址
    4. x 和 y 在这里可以理解为具体的房间,房间 x 的门牌号(地址)是 px,房间 y 的门牌号(地址)是 py。而 10 和 20,通过 px、py 两个门牌,找到房间,住进 x、y。用户(变量的值)和房间(变量)以及房间号(指针、地址)的关系

    1.2、指针变量和指针的类型

    指针变量就是一个变量,它存储的内容是一个指针。如果用前面的例子,可以理解为指针变量就是一张房卡,房卡存储了房间号的信息。

    在我们定义一个变量的时候,要确定它的类型。int x、char ch、float、、、在定义指针变量时也是一样的,必须确定指针类型。int 变量的指针需要用 int 类型的指针存储,float 变量的指针需要用 float 类型的指针存储。就像你只能用酒店 A 的房卡存储酒店 A 中房间号的信息一样。

    二、变量的指针与指针变量

    变量的指针就是变量的存储地址,指针变量就是存储指针的变量。

    2.1、指针变量的定义及使用

    (1)指针变量的定义

    指针变量的定义形式如:数据类型 *指针名;例如:

    //分别定义了 int、float、char 类型的指针变量
    int *x;
    float *f;
    char *ch;
    

    如上面的定义,指针变量名为 x、f、ch。并不是*x、*f、*ch

    (2)指针变量的使用

    • 取地址运算符&:单目运算符&是用来取操作对象的地址。例:&i 为取变量 i 的地址。对于常量表达式、寄存器变量不能取地址(因为它们存储在存储器中,没有地址)。
    • 指针运算符*(间接寻址符):与&为逆运算,作用是通过操作对象的地址,获取存储的内容。例:x = &i,x 为 i 的地址,*x 则为通过 i 的地址,获取 i 的内容。

    代码示例:

    //声明了一个普通变量 a
    int a;
    //声明一个指针变量,指向变量 a 的地址
    int *pa;
    //通过取地址符&,获取 a 的地址,赋值给指针变量
    pa = &a;
    //通过间接寻址符,获取指针指向的内容
    printf("%d", *pa);
    

    (3)“&”和“*”的结合方向

    “&”和“*”都是右结合的。假设有变量 x = 10,则*&x 的含义是,先获取变量 x 的地址,再获取地址中的内容。因为“&”和“*”互为逆运算,所以 x = *&x。

    接下来做个小练习,输入 x、y 两个整数,然后将其中的值大的赋值给 x,小的赋值给 y。即:假设输入 x = 8,y = 9。就将 9 赋值给 x,8 赋值给 y。

    void main(){
    	//声明两个普通变量
    	int x, y;
    	//声明两个指针变量
    	int *px, *py;
    	//声明一个临时变量,用于交换
    	int t;
    	//输入两个值,赋值给 x、y
    	scanf("%d", &x);
    	scanf("%d", &y);
    	//给指针变量 px、py 赋初值(关联变量 x、y)
    	px = &x;
    	py = &y;
    	//利用指针来对比 x、y 的值,如果 x 的值比 y 的值小,就交换
    	if(*px < *py){
    		//交换步骤,其中*px == x、*py == y
    		t = *px;
    		*px = *py;
    		*py = t;
    	}
    	printf("x =  %d, y = %d", *px, *py);
    }
    
    输入:23 45
    输出结果为:x = 45, y = 23
    

    2.2、指针变量的初始化

    指针变量与其它变量一样,在定义时可以赋值,即初始化。也可以赋值“NULL”或“0”,如果赋值“0”,此时的“0”含义并不是数字“0”,而是 NULL 的字符码值。

    //利用取地址获取 x 的地址,在指针变量 px 定义时,赋值给 px
    int x;
    int *px = &x;
    //定义指针变量,分别赋值“NULL”和“0”
    int *p1= NULL, *p2 = 0;
    

    2.3、指针运算

    (1)赋值运算

    指针变量可以互相赋值,也可以赋值某个变量的地址,或者赋值一个具体的地址

    int *px, *py, *pz, x = 10;
    //赋予某个变量的地址
    px = &x;
    //相互赋值
    py = px;
    //赋值具体的地址
    pz = 4000;
    

    (2)指针与整数的加减运算

    1. 指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
    2. 指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。
    //定义三个变量,假设它们地址为连续的,分别为 4000、4004、4008
    int x, y, z;
    
    //定义一个指针,指向 x
    int *px = &x;
    
    //利用指针变量 px 加减整数,分别输出 x、y、z
    printf("x = %d", *px);		//因为 px 指向 x,所以*px = x
    
    //px + 1,表示,向前移动一个单元(从 4000 到 4004)
    //这里要先(px + 1),再*(px + 1)获取内容,因为单目运算符“*”优先级高于双目运算符“+”
    printf("y = %d", *(px + 1));		
    printf("z = %d", *(px + 2));
    

    (3)关系运算

    假设有指针变量 px、py。

    1. px > py 表示 px 指向的存储地址是否大于 py 指向的地址
    2. px == py 表示 px 和 py 是否指向同一个存储单元
    3. px == 0 和 px != 0 表示 px 是否为空指针
    //定义一个数组,数组中相邻元素地址间隔一个单元
    int num[2] = {1, 3};
    
    //将数组中第一个元素地址和第二个元素的地址赋值给 px、py
    int *px = &num[0], *py = &num[1];
    int *pz = &num[0];
    int *pn;
    
    //则 py > px
    if(py > px){
    	printf("py 指向的存储地址大于 px 所指向的存储地址");
    }
    
    //pz 和 px 都指向 num[0]
    if(pz == px){
    	printf("px 和 pz 指向同一个地址");
    }
    
    //pn 没有初始化
    if(pn == NULL || pn == 0){
    	printf("pn 是一个空指针");
    }
    

    三、指针与数组

    之前我们可以通过下标访问数组元素,学习了指针之后,我们可以通过指针访问数组的元素。在数组中,数组名即为该数组的首地址,结合上面指针和整数的加减,我们就可以实现指针访问数组元素。

    3.1、指向数组的指针

    如以下语句:

    int nums[10], *p;
    

    上面语句定义了一个数组 nums,在定义时分配了 10 个连续的int 内存空间。而一个数组的首地址即为数组名nums,或者第一个元素的首地址也是数组的首地址。那么有两种方式让指针变量 p 指向数组 nums:

    //数组名即为数组的首地址
    p = nums;
    //数组第一个元素的地址也是数组的首地址
    p = &nums[0];
    

    上面两句是等价的。
    如下几个操作,用指针操作数组:

    1. *p = 1,此操作为赋值操作,即将指针指向的存储空间赋值为 1。此时 p 指向数组 nums 的第一个元素,则此操作将 nums 第一个元素赋值为 0,即 nums[0] = 1。
    2. p + 1,此操作为指针加整数操作,即向前移动一个单元。此时 p + 1 指向 nums[0]的下一个元素,即 nums[1]。通过p + 整数可以移动到想要操作的元素(此整数可以为负数)。
    3. 如上面,p(p + 0)指向 nums[0]、p + 1 指向 nums[1]、、、类推可得,p+i 指向 nums[i],由此可以准确操作指定位置的元素。
    4. 在 p + 整数的操作要考虑边界的问题,如一个数组长度为 2,p+3 的意义对于数组操作来说没有意义。

    下面写一段代码,用指针访问数组的元素:

    //定义一个整形数组,并初始化
    int nums[5] = {4, 5, 3, 2, 7};
    
    //定义一个指针变量 p,将数组 nums 的首地址赋值给 p,也可以用p = &nums[0]赋值
    int *p = nums, i;			//i 作为循环变量
    
    //p 指向数组第一个元素(数组首地址),我们可以直接用间接寻址符,获取第一个元素的内容
    printf("nums[0] = %d\n", *p);			//输出结果为 nums[0] = 4
    
    //我们可以通过“p + 整数”来移动指针,要先移动地址,所以 p + 1 要扩起来
    printf("nums[1] = %d\n", *(p + 1));		//输出结果为 nums[1] = 5
    
    //由上面推导出*(p + i) = nums[i],所以我们可以通过 for 循环变量元素
    for(i = 0; i < 5; i++){
    	printf("nums[%d] = %d", i, *(p + i));
    }
    

    注:数组名不等价于指针变量,指针变量可以进行 p++和&操作,而这些操作对于数组名是非法的。数组名在编译时是确定的,在程序运行期间算一个常量。

    3.2、字符指针与字符数组

    在 C 语言中本身没有提供字符串数据类型,但是可以通过字符数组和字符指针的方式存储字符串。

    (1)字符数组方式

    这个在前面应该学习过,这里就不赘述了。

    char word[] = "zack";
    printf("%s", word);
    

    (2)字符指针方式

    指针方式操作字符串和数组操作字符串类似,可以把定义的指针看做是字符数组的数组名。在内存中存储大致如下,这里为了方便换了个字符串:在这里插入图片描述

    //除了定义一个字符数组外,还可以直接定义一个字符指针存储字符串
    char *sentence = "Do not go gentle into that good night!";
    
    //此时可以做字符串的操作
    //输出
    printf("%s", sentence);
    
    //通过下标取字符
    printf("%c", sentence[0]);
    
    //获取字符串长度,其中 strlen 是 string.h 库中的方法
    printf("%d", strlen(sentence));
    

    注:字符指针方式区别于字符数组方式,字符数组不能通过数组名自增操作,但是字符指针是指针,可以自增操作。自增自减少会实现什么效果大家可以自己尝试运行一下

    下面做个小练习,利用字符指针将字符数组 sentence 中的内容复制到字符数组 word 中:

    //定义字符数组 sentence 和 word,给 sentence 赋初值
    char sentence[] = "Do not go gentle into that good night!", word[100];
    
    //定义字符指针,指向 word
    char *ch = word;
    int i;
    
    //循环赋值
    for(i = 0; sentence[i] != '\0'; i++){
    	*(ch + i) = sentence[i];
    }
    
    //在当 i 等于 sentence 的长度(sentence 的长度不包含'\0')时,
    //i 继续自增,此时判断 sentence[0] != '\0'不符合,跳出循环,则 i 比 sentence 长度大 1
    *(ch + i) = '\0';
    
    //输出字符串,因为 ch 指向 word,所以输出结果是一样的
    printf("ch = %s, word = %s", ch, word);
    

    注:指针变量必须初始化一个有效值才能使用

    3.3、多级指针及指针数组

    (1)多级指针

    指针变量作为一个变量也有自己的存储地址,而指向指针变量的存储地址就被称为指针的指针,即二级指针。依次叠加,就形成了多级指针。我们先看看二级指针,它们关系如下:指针变量 p 指向变量 x,二级指针变量指向指针变量 p
    其中 p 为一级指针,pp 为二级指针。二级指针定义形式如下:

    数据类型 **二级指针名;
    

    和指针变量的定义类似,由于*是右结合的,所以*pp 相当于*(*p)。在本次定义中,二级指针的变量名为 pp,而不是**p。多级指针的定义就是定义时使用多个“*”号。下面用一个小程序给大家举例:

    //定义普通变量和指针变量
    int *pi, i = 10;
    //定义二级指针变量
    int **ppi;
    
    //给指针变量赋初值
    pi = &i;
    
    //给二级指针变量赋初值
    ppi = &pi;
    
    //我们可以直接用二级指针做普通指针的操作
    //获取 i 的内容
    printf("i = %d", **ppi);
    //获取 i 的地址
    printf("i 的地址为%d", *ppi);
    

    注:在初始化二级指针 ppi 时,不能直接 ppi = &&i,因为&i 获取的是一个具体的数值,而具体数字是没有指针的。

    (2)指针数组

    指针变量和普通变量一样,也能组成数组,指针数组的具体定义如下:

    数据类型 *数组名[指针数组长度];
    

    下面举一个简单的例子熟悉指针数组:

    //定义一个数组
    int nums[5] = {2, 3, 4, 5, 2}, i;
    
    //定义一个指针数组
    int *p[5];
    
    //定义一个二级指针
    int **pp;
    
    //循环给指针数组赋值
    for(i = 0; i < 5; i++){
    	p[i] = &nums[i];
    }
    
    //将指针数组的首地址赋值给 pp,数组 p 的数组名作为 p 的首地址,也作为 p 中第一个元素的地址。
    //数组存放的内容为普通变量,则数组名为变量的指针;数组存放的内容为指针,则数组名为指针的指针。
    pp = p;
    
    //利用二级指针 pp 输出数组元素
    for(i = 0; i < 5; i++){
    	//pp == &p[0] == &&nums[0],nums[0] == *p[0] == **pp
    	printf("%d", **pp);
    	
    	//指针变量+整数的操作,即移动指针至下一个单元
    	pp++;
    }
    

    3.4、指针与多维数组

    讲多维数组是个麻烦的事,因为多维数组和二维数组没有本质的区别,但是复杂度倒是高了许多。这里我主要还是用二维数组来举例,但是还是会给大家分析多维数组和指针的关系。

    (1)多维数组的地址

    先用一个简单的数组来举例:

    int nums[2][2] = {
    	{1, 2},
    	{2, 3}
    };
    

    我们可以从两个维度来分析:

    1. 先是第一个维度,将数组当成一种数据类型 x,那么二维数组就可以当成一个元素为 x 的一维数组。
    2. 如上面的例子,将数组看成数据类型 x,那么 nums 就有两个元素。nums[0]和 nums[1]。
    3. 我们取 nums[0]分析。将 nums[0]看做一个整体,作为一个名称可以用 x1 替换。则 x1[0]就是 nums[0][0],其值为 1。
      在这里插入图片描述

    我们知道数组名即为数组首地址,上面的二维数组有两个维度。首先我们把按照上面 1 来理解,那么 nums 就是一个数组,则nums 就作为这个数组的首地址。第二个维度还是取 nums[0],我们把 nums[0]作为一个名称,其中有两个元素。我们可以尝试以下语句:

    printf("%d", nums[0]);
    

    此语句的输出结果为一个指针,在实验过后,发现就是 nums[0][0]的地址。即数组第一个元素的地址。

    如果再多一个维度,我们可以把二维数组看做一种数据类型 y,而三维数组就是一个变量为 y 的一维数组。而数组的地址我们要先确定是在哪个维度,再将数组某些维度看成一个整体,作为名称,此名称就是该维度的地址(这里有些绕)。

    例:

    //假设已初始化,二维数组数据类型设为 x,一维数组数据类型设为 y
    int nums[2][2][2];
    
    //此数组首地址为该数组名称
    printf("此数组首地址为%d", nums);
    
    //此数组可以看做存储了两个 x 类型元素的一维数组,则 nums[0] = x1 的地址为
    printf("第二个维度的首地址为%d", nums[0]);
    
    //而 x1 可以看做存储了两个 y 类型元素的一维数组,则 y1 = x1[0] = nums[0][0]
    printf("第三个维度的首地址为%d", nums[0][0]);
    
    

    三维数组实际存储形式如下:
    在这里插入图片描述
    实际存储内容的为最内层维度,且为连续的。对于 a 来说,其个跨度为 4 个单元;对 a[0]来说,其跨度为 2 个单元;对 a[0][0]来说,跨度为一个单元。有上面还可以得出:

    a == a[0] == a[0][0] == &a[0][0][0];
    

    上面的等式只是数值上相等,性质不同。

    (2)多维数组的指针

    在学习指针与数组的时候,我们可以如下表示一个数组:

    int nums[5] = {2, 4, 5, 6, 7};
    int *p = nums;
    

    在前面讲指针数组时,所有指针数组元素都指向一个数字,那么我们现在可以尝试用指针数组的每个元素指向一个数组:

    //定义一个二维数组
    int nums[2][2] = {
    	{1, 2},
    	{2, 3}
    };
    
    //此时 nums[0]、和 nums[1]各为一个数组
    int *p[2] = {nums[0], nums[1]};
    
    //我们可以用指针数组 p 操作一个二维数组
    
    //p 为数组 p 的首地址,p[0] = nums[0] = *p,**p = nums[0][0]
    printf("nums[0][0] = %d", **p);
    
    //指针 + 整数形式,p+1 移动到 nums 的地址,*(p +1) = nums[1],则**(p + 1) = nums[1][0]
    printf("nums[1][0] = %d", **(p + 1));
    
    //先*p = nums[0],再*p + 1 = &nums[0][1],最后获取内容*(*p + 1)即为 nums[0][1]
    printf("nums[0][1] = %d", *(*p + 1));
    

    这里可能不能理解为什么*p + 1 = &nums[0][1],而不是 nums[1]。*p 获得的是一个一维数组,而 int 数组 + 1 的跨度只有 4 个字节,也就是一个单元。前面 p 是一维数组的指针,其跨度为一个数组。所以*p + 1 = &nums[0][1],而 p + 1 = nums[1]。

    四、指针与函数

    前面学习函数学到,函数参数可以为 int、char、float 等,但是在操作时,这些参数只作为形参,所有操作都只在函数体内有效(除对指针的操作外),那么今天来学习一下指针作为函数参数。

    4.1、函数参数为指针

    我们直接做一个练习,定义一个函数,用来交换两个变量的内容。

    void swap(int *x, int *y);
    void main(){
    	int x = 20, y = 10;
    	swap(&x, &y);
    	printf("x = %d, y = %d", x ,y);
    }
    void swap(int *x, int *y){
    	int t;
    	t = *x;
    	*x = *y;
    	*y = t;
    }
    

    代码非常简单,我也就不细讲了。这里传入的参数为指针,所以调用 swap 方法后 x,y 的内容发生了交换。如果直接传入 x,y,那么交换只在 swap 中有效,在 main 中并没有交换。

    4.2、函数的返回值为指针

    返回值为指针的函数声明如下:

    数据类型 *函数名(参数列表){
    	函数体
    }
    //例如:
    int s;
    int *sum(int x, int y){
    	s = x + y;
    	return &s;
    }
    

    在函数调用前要声明需要对函数声明(有点编译器不需要)

    int s;
    void mian(){
    	int *r = sum(10, 9);
    	printf("10 + 9 + %d", *r);
    }
    int *sum(int x, int y){
    	s = x + y;
    	return &s;
    }
    

    除了上面的操作,更实用的是返回一个指向数组的指针,这样就实现了返回值为数组。

    4.3、指向函数的指针

    C 语言中,函数不能嵌套定义,也不能将函数作为参数传递。但是函数有个特性,即函数名为该函数的入口地址。我们可以定义一个指针指向该地址,将指针作为参数传递。

    函数指针定义如下:

    数据类型 (*函数指针名)();
    

    函数指针在进行“*”操作时,可以理解为执行该函数。函数指针不同与数据指针,不能进行+整数操作。

    下面举个例子,来使用函数指针:

    #include <string.h>
    /**
    *	定义一个方法,传入两个字符串和一个函数指针 p,用 p 对两个字符串进行操作
    */
    void check(char *x, char *y, int (*p)());
    void main(){
    	//string.h 库中的函数,使用之前需要声明该函数。字符串比较函数
    	int strcmp();
    	char x[] = "Zack";
    	char y[] = "Rudy";
    	
    	//定义一个函数指针
    	int (*p)() = strcmp;
    
    	check(x, y, p);
    }
    void check(char *x, char *y, int (*p)()){
    	if(!(*p)(x, y)){
    		printf("相等");
    	}else{
    		printf("不相等");
    	}
    }
    

    利用函数指针调用方法具体操作如下:

    (*p)(x, y);
    

    指针除了这些地方,还在结构体中用处巨大。今天就先讲到这里~·

    展开全文
  • 由于一般(无指针)语句不需要知道地址&amp;a,也并不会使用到,所以对开发者“不可见”。在编程时,看起来就像是变量a等于1,操作变量a,就可以实现对该值的改变(实际上是在操作地址&amp;a的值,而开发者...

    • 普通的语句 
    int a = 1;

    内存中地址为&a的地方存储了值1。

    由于一般(无指针)语句不需要知道地址&a,也并不会使用到,所以对开发者“不可见”。在编程时,看起来就像是变量a等于1,操作变量a,就可以实现对该值的改变(实际上是在操作地址&a的值,而开发者看到变量a始终对应地址&a的值)。

    • 数组
    int is[] = {1, 2, 3, 4, 5};

    数组存放在内存地址&is~&(is+4),每个地址存储了一个值。

    is与&is都对应数组的起始地址,两者相等,称之为指针,指向数组第一个数据。

    对于指针可以通过*is取到数组第一个值1,同理*(is+1)取到2……

    这样编写较为麻烦,可以(语法糖)简写 *is: is[0],*(is+1):is[1]……

    • 指针
    int* p = is;

    指针通过int*定义,is为数组起始地址,那么指针p指向数组。

    *p访问到is[0],p[0]也访问到is[0];*(p+1)、p[1]访问到is[1]……


    当我们想通过地址来操纵数据时才需要指针,指针p代表内存中地址,*p则是该内存地址中存储的值。

    对于指针p,*p就相当于普通变量a/b。


    代码:

        int a = 1;
        int b = 10;
        cout<<"a = "<<a<<" &a = "<< &a;
        cout<<"\nb = "<<b<<" &b = "<< &b;
    
        int is[] = {1, 2, 3, 4, 5};
        cout<<"\nis = "<<is<<" &is="<<&is << " *is="<<*is;
        cout<<"\nis[0] = "<<is[0] <<" &is[0] = "<<&is[0];
        cout<<"\nis[1] = "<<is[1] <<" &is[1] = "<<&is[1];
    
        int* p = is; // type of is : int*
        //int m = is; //error: invalid conversion from ‘int*’ to ‘int’
        cout<<"\n*p = "<<*p<<" p="<<p<< " p[0]="<<p[0]<<endl;

    输出:

    a = 1 &a = 0x7fff8cb86110
    b = 10 &b = 0x7fff8cb86114
    is = 0x7fff8cb86120 &is=0x7fff8cb86120 *is=1
    is[0] = 1 &is[0] = 0x7fff8cb86120
    is[1] = 2 &is[1] = 0x7fff8cb86124

    *p = 1 p=0x7fff8cb86120 p[0]=1



    展开全文
  • 当一维数组做函数参数的时候,会退化为指针 一维数组做函数参数的时候,c/c++编译器会做优化 int a[10] ----->int a[] ---->int *a 所以数组作函数参数的时候只能传指针 3.函数调用的时候,把数组首地址...

    一维数组做函数参数的用法:

    1. 当一维数组做函数参数的时候,会退化为指针
    2. 一维数组做函数参数的时候,c/c++编译器会做优化

                       int a[10]  ----->int a[] ---->int *a

                       所以数组作函数参数的时候只能传指针

        3.函数调用的时候,把数组首地址和有效数据长度传给被调用函数才是最正确的做法

     

    //在函数调用哪个的时候 实参的值机械的传给形参(c int数组场景)

    关于形参的理解:

             写在函数上形参变量,还是写在函数里面的变量,

             从CC++编译的角度来讲,是没有任何区别的(分配4字节内存);

             只不过是 写在函数上形参变量 ,具有对外的属性而已

     

    下面给出程序具体实例

    #include "stdlib.h"
    #include "string.h"
    #include "stdio.h"
    
    //当数组当做函数参数的话的时候会退化为指针 
    int printfArray(int a[]) //这里形参a[10]跟a[]效果一样
    {
    	int i = 0;
    	int num = 0;
    
    	num = sizeof(a) / sizeof(*a);  //这里num值为1
    	printf("num=%d.\n", num);
    	for (i = 0; i < 10; i++)
    	{
    		printf("%d ", a[i]);
    	}
    	printf("\n");
    	return 0;
    }
    
    //int a[10]  -=-->int a[] ---->int *a
    //数组做函数形参的时候,如果在形参中定义int a[10]语句,
    //c/c++编译器 会做优化,技术推演如下
    //int a[10]  -=-->int a[] ---->int *a
    //总结:函数调用的时候,把数组首地址和有效数据长度传给被调用函数才是最正确的做法
    //在函数调用哪个的时候 实参的值机械的传给形参(c int数组场景)
    
    //关于形参:
    /*
    		写在函数上形参变量,还是写在函数里面的变量,
    		从CC++编译的角度来讲,是没有任何区别的(分配4字节内存);
    		只不过是 写在函数上形参变量 ,具有对外的属性而已
    */
    
    
    int printfArray04(int *a, int num)
    {
    	int i = 0;
    	for (i = 0; i < num; i++)
    	{
    		printf("%d ", a[i]);
    	}
    	printf("\n");
    	return 0;
    
    }
    
    
    int sortArray(int a[])
    {
    	int i = 0, j = 0;
    	int tmp;
    	for (i = 0; i < 10; i++) //外层循环
    	{
    		for (j = i + 1; j < 10; j++) //内层循环
    		{
    			if (a[i] > a[j])
    			{
    				tmp = a[i];
    				a[i] = a[j];
    				a[j] = tmp;
    			}
    		}
    	}
    	return 0;
    }
    void main()
    {
    	//定义数组 打印数组 数组排序
    	int i = 0, j = 0;
    	int num2;
    	int a[10] = { 1,3,4,5,65,76,7,34,4,32 };
    	int tmp;
    	
    	num2 = sizeof(a) / sizeof(*a); //这里num2值为10
    	printf("num2:%d \n", num2);
    
    	printf("排序之前\n ");
    	printfArray04(a, 10);
    	sortArray(a);
    
    	printf("排序之后\n ");
    	printfArray(a);
    
    	system("pause");
    }
    

     

    展开全文
  • 深入理解C语言指针的奥秘深入理解C语言指针的奥秘深入理解C语言指针的奥秘深入理解C语言指针的奥秘
  • 深入理解C语言指针.PDF深入理解C语言指针常州轻工职业技术学院信息系 丁 辉摘 要:指针是c语言的精华和核心部分,充分体现了c语言的灵活性,增强了c语言的功能。本文从指针的定义、指针的功能及 由于指针的使用带来...

    深入理解C语言指针.PDF

    深入理解C语言指针

    常州轻工职业技术学院信息系 丁 辉

    摘 要:指针是c语言的精华和核心部分,充分体现了c语言的灵活性,增强了c语言的功能。本文从指针的定义、指针

    的功能及 由于指针的使用带来的安全性等方面深入地分析 了c语言的指针 。

    关键词 :C语 言;指针 ;安全

    在计算机中,所有的数据及程序都是存放在存储器中的。一般把存储 {intk,h=8,p.

    器中的—个字节空间称为—个 内存单元,为了正确地访问这些内存单元 p=&h;

    k--p;

    必须为每个内存单元编上号 ,根据—个内存单元的编号即可准确地找到该

    fi(“%d’% ”.p1k

    内存单元,内存单元的编号叫做地址 。根据内存单元的地址就可以找到所 }

    需的内存单元,通常也把这个地址称为指针。定义指针的 目的是为了通过 执行时输出结果如下:

    指针去访问内存单元。 -82,一82(此结果是不确定的)

    在c语言中,允许用—个变量来存放指针,这种变量称为指针变量。 同样对于这样的使用 ,TurboC 2.0编译系统也不会提示任何错误

    因此 ,—个指针变量的值就是某个内存单元的地址或称为某 内存单元的指 和警告 ,但结果没有意义。

    针。注意内存单元的指针和内存单元的内容是两个不同的概念。既然指针 c.指针变量可以赋空值,但不能不赋值,即:

    变量的值是—个地址 ,那么这个地址不仅可以是变量的地址 ,也可以是其 p=NULL;可以,但如下的程序

    它数据结构的地址,如数组 、函数种等。数组或函数都是连续存放的,通 mdnO

    过访问指针变量取得了数组或函数的首地址 ,也就找到了该数组或函数。 (intp;

    这样一来,凡是出现数组,函数的地方都可以用—个指针变量来表示,只 *P-~-56;

    要该指针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概

    }

    念十分清楚 ,程序本身也精练 ,高效。在c语言中,一种数据类型或数据

    虽然TurboC20编译系统不会提示任何错误和警告.但是这样使用

    结构往往都 占有一组连续的内存单元。

    是很危险的,因为P的值是无法预料 的,有可能修改 了一个在用单元的

    1 指针变量的定义 值。对于这样的使用,用户需要特别注意。

    其一般形式为 :类型说明符 +变量名;

    指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋

    对指针变量的类型说明包括+内容: 予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至

    (1浦 针类型说明,即定义变量为一个指针变量.其标志是变量名前

    死机。指针变量的赋值只能赋予地址,决不能赋予任何其它数据 ,否则将

    的 “+”;

    展开全文
  • 理解C语言指针

    千次阅读 2019-03-25 14:40:45
    C语言指针理解 本人在初学的时候认为c语言中指针很好理解,但身边好多同学一直在说老师讲的指针太抽象了,看不到,摸不着,非常难理解,甚至学了4年计算机,毕业了,不少同学还说不清楚指针是什么,遇到指针的问题...
  • 十分详细讲述了C语言中的指针的用法 灵活使用C语言指针--深入理解C语言指针
  • C语言指针相关知识理解以及总结

    千次阅读 多人点赞 2017-07-17 09:05:31
    C语言指针相关知识理解以及总结,什么是指针,关于*和&,指针变量运算,C语言数组指针(指向数组的指针),C语言字符串指针,二级指针,C语言指针数组,C语言与二维数组,函数指针,指针总结
  • 对于C语言指针理解

    千次阅读 多人点赞 2019-02-17 17:57:35
    对于C语言指针理解 学习c语言中最难得部分就是指针了 指针是什么? 指针本身是一个变量,它存储的是数据在内存中的地址而不是数据本身的值。它的定义如下: 指针的形式: 类型 *变量名 比如int *p就是一个整型的...
  • C语言指针,详解

    2018-06-08 11:53:26
    C语言指针详解,对C语言指针理解模糊的同仁,可以作为参考,学习。
  • C语言指针深入理解

    2019-09-25 23:31:17
    在学习C语言时,指针一直是一个难题。但是在C语言中,指针是个非常强大的东西。理解好指针,会给你C语言的学习带了更多的便利。对一些底层的东西,也理解的更加...希望本次Chat可以让大家对C语言指针理解透彻。...
  • 很多小伙伴都反馈说C指针不容易学习,看到C指针就头疼,今天带你一小时透彻了解C语言指针! 【知识点】 1、指针与内存那些事 2、指针与数据类型的理解 3、指针的剖析 4、透彻理解指针的应用 学习教程:指针...
  • 指针是C语言的特色之一,它允许程序员直接操纵内存。这一块内容也是比较抽象的,很多人不管是小白还是稍有经验的程序员,其实对C语言指针理解都是模糊的,其实就是没有搞懂C语言指针的实质和规律。
  • C语言指针理解

    千次阅读 2018-11-24 21:21:45
    对于C语言初学者而言,指针部分有点复杂,也有些难理解,可以说是C语言学习之路上的第一道坎,在阅读了不少书籍资料和实验后,决定写下这篇博客,供大家参考。  什么是指针?  指针也是一种变量,存放的是某块...
  • 深入理解C语言指针深入理解C语言指针深入理解C语言指针
  • 深入理解C语言指针的奥秘深入理解C语言指针的奥秘
  • com原文:C语言语法笔记 – 高级用法 指针数组 指针指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针指针 二维数组指针 结构体指针 链表 | I ...C语言数组和指针理解&...
  • 深入理解C语言指针类型

    千次阅读 多人点赞 2018-05-24 15:01:46
    C语言指针类型
  • C语言指针变量的理解

    2020-02-10 22:29:37
    都说指针是C语言的灵魂,这只有正真理解掌握了...C语言指针是什么? 我们要知道计算机中的所有数据都必须放在内存中,不同类型的数据占用的字节数不一样; 例如 int 占用 4 个字节,char 占用 1 个字节。为了正...
  • C语言指针

    千次阅读 多人点赞 2018-03-30 22:19:08
    c语言指针学习指针只有两层含义,1:指向地址,2:指针有类型,类型是其指向的内存空间数据的类型,表示从首地址开始取多少字节。C语言相比于其他高级语言,不仅是运行速度快,而且还能够直接操作硬件,操作硬件就是...
  • 所有学过C语言的人都知道,C语言难在它的指针的使用和理解,今天,我带给大家C语言指针的教程,供大家学习交流,如果有讲的不对的地方,请给作者邮箱留言(邮箱在底部)。 指针是什么?指针是指向某个变量、...
  • 深入理解C语言指针和结构体

    千人学习 2019-01-05 21:23:58
    本课程的主要目的是通过介绍C语言指针指针变量、静态内存分配、动态内存分配以及结构体等知识,实现C语言到Java以及Python编程的一个完美过渡.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 119,971
精华内容 47,988
关键字:

c语言指针理解

c语言 订阅