C语言中由于指针的灵活性,导致指针能代替数组使用,或者混合使用,这些导致了许多指针和数组的迷惑,因此,刻意再次深入探究了指针和数组这玩意儿,其他类型的数组比较简单,容易混淆的是字符数组和字符指针这两个。

1.数组的本质

数组是多个元素的集合,在内存中分布在地址相连的单元中,所以可以通过其下标访问不同单元的元素。。

2.指针。

指针也是一种变量,只不过它的内存单元中保存的是一个标识其他位置的地址。。由于地址也是整数,在64位平台下,指针默认为8位。(32位平台下,指针默认为4位)

3.指针的指向

指向的直接意思就是指针变量所保存的其他的地址单元中所存放的数据类型。

int  * p ;//p 变量保存的地址所在内存单元中的数据类型为整型
float *q;// q变量保存的地址所在内存单元中的数据类型为浮点型

不论指向的数据类型为那种,指针变量其本身永远为整型,因为它保存的地址。

字符串赋给一个指针变量

char  *s ;
s = "China";

4.字符数组

char  str[10]; //定义了一个有十个元素的数组,元素类型为字符
char  str[10] = {"hello world"};//初始化

C语言中没有真正的字符串类型,可以通过字符数组表示字符串,因为它的元素地址是连续的,这就足够了。
C语言中字符串常量的本质表示其实是一个地址,规定数组代表数组所在内存位置的首地址,也是 str[0]的地址,即str = &str[0];

5.char * 与 char a[ ]

char  *s;
char  a[ ] ;

a代表字符串的首地址,而s 这个指针也保存字符串的地址(其实首地址),即第一个字符的地址,这个地址单元中的数据是一个字符,

可以 s = a;但不能 a = s;

C语言中数组名可以复制给指针表示地址, 但是却不能赋给给数组名,它是一个常量类型,所以不能修改。。

   当然也可以这样:
char  a [ ] = "hello";
char *s =a;
for(int i= 0; i < strlen(a) ; i++)
    printf("%c", s[i]);
//  printf("%c",*s++)

字符指针可以用间接操作符 ∗ * 取其内容,也可以用数组的下标形式 [ ],数组名也可以用 *操作,因为它本身表示一个地址 。。
比如 printf(“%c”,*a); 将会打印出 ‘h’

char * 与 char a[ ] 的本质区别:

当定义 char a[10 ] 时,编译器会给数组分配十个单元,每个单元的数据类型为字符。。
定义 char *s 时, 这是个指针变量,只占四个字节,32位,用来保存一个地址。。

sizeof(a) = 10sizeof(s)  = 4//编译器分配4个字节32位的空间,这个空间中将要保存地址
printf("%p",s);//表示 s 的单元中所保存的地址
printf("%p",&s);//表示变量本身所在内存单元地址

一句话来概括,就是 c h a r ∗ s char *s chars 只是一个保存字符串首地址的指针变量, char a[ ] 是许多连续的内存单元,单元中的元素为char ,
之所以用 c h a r ∗ char * char能达到char a [ ] 的效果,还是字符串的本质,地址,即给你一个字符串地址,便可以随心所欲的操所他。但是,char* 和 char a[ ] 的本质属性是不一样的。。

6.char ** 与char * a[ ] ;

  • char *a [ ]

由于[ ] 的优先级高于* 所以a先和 [ ]结合,他还是一个数组,数组中的元素才是char * ,前面讲到char * 是一个变量,保存的地址。。

char *a[ ] = {"China","French","America","German"}sizeof(a) = 32

字符串常量的本质是地址,a 数组中的元素为char * 指针,指针变量占四个字节,那么四个元素就是32个字节了

#include <stdio.h>

int main()
{
  char *a [ ] = {"China","French","America","German"};
  printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]);
  return 0;
 }

在这里插入图片描述
可以看到数组中的四个元素保存了四个内存地址,这四个地址中就代表了四个字符串的首地址,而不是字符串本身。四个地址不是连续的。

#include <stdio.h>
#include<iostream>


int main()
{
    char *a [ ] = {"China","French","America","German"};
    printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]); //数组元素中保存的地址
    printf("%p %p %p %p\n",&a[0],&a[1],&a[2],&a[3]);//数组元素单元本身的地址
    std::cout<<sizeof(a);

    return 0;
}

在这里插入图片描述
0x7fff2258ff70 0x7fff2258ff78 0x7fff2258ff80 0x7fff2258ff88,这四个是元素单元所在的地址,每个地址相差8个字节,这是由于每个元素是一个指针变量占8个字节

  • char s**

二级指针保存的是一级指针的地址,它的类型是指针变量,而一级指针保存的是指向数据所在的内存单元的地址,虽然都是地址,但是类型是不一样的

在 char** s 中,s 是一个指针,这个指针(s)指向一块内存地址,该内存地址中存储的是 char* 类型的数据。指针的加减运算在这里的体现为:a + 1 表示地址加8字节(在32位系统中,地址加4字节)。

char* 也是一个指针,用 *s 表示,这个指针(*s)指向一块内存地址,该内存地址中存储的是 char 类型的数据。指针的加减运算在这里的体现为:(*a) + 1 表示地址加1字节。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐