C 指针和数组

指针与数组详解
本文详细解释了指针的概念及其与地址的关系,并对比了指针与数组的不同之处,还介绍了字符指针在函数中的应用。

    指针是一种用于存放另一个变量地址的变量。

一、指针和地址

    机器的存储器通常由连续编号(或编址)的存储单元序列组成,这些存储单元可以单个或相连成组的方式操作。通常一个字节可以表示一个字符,两个相连的存储单元可以表示一个短整数,而四个相连的字节则构成一个长整数。指针由能存放一个地址的一组存储单元(通常是两个或四个字节)构成。

     int x = 1, y = 2, z[10];
     int *p;           // p是指向整数的指针,也可以看做 (int *)p
    
     p = &x;           // p指向x
     y = *p;           // y等于p指向的值,也就是1
     p = &z[0];        // p指向z[0]

    int *p;

    一个指针只能指向一个特定的类型的对象,每个指针对象也有一确定的数据类型(void类型除外,void类型的指针可以转换成指向任何对象类型的指针,但它不能间接引用它自身)。

二、指针和数组

    指针和数组之间的关系十分密切,数组下标可以完成的任何运算都可以用指针来实现。一般指针运算比数组下标运算的速度快,所以用好指针是很重要的。

    但是指针和数组并不是相等的。

    int a[5];

    int *p;

    他们都具有指针值,也可以进行间接访问和下标引用操作。

    区别在于声明一个数组时,编译器将根据声明指定的的元素的数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置。

    声明一个指针变量时,编译器只为指针本身保留空间,它并不为任何整型值分配内存空间。指针变量为初始化为指向任何现有的内存空间,如果他是一个自动变量,它甚至根本不会被初始化。           

    上面声明之后,表达式*a是完全合法的,表达式*b却是非法的。*b将访问内存中某个不确定的位置,或者导致程序终止。   

    b = &a[0]; 

    执行赋值语句后,b执行现有内存空间,b和a具有相同的值。一个数组的名字即该数组第0个元素的位置,所以上面语句也可以写成:

    b = a;

    对于数组啊a[i]的引用也可以写为 *(a+i)的形式。当然如果做取地址符&应用时,也可以写成 &a[i]或 a+i 的形式也是相同的。相应的,如果b是一个指针,那么表达式中可以使用具有下标的指针b, b[i]和 *(b+i) 的含义一样。但是一点要注意,指针是变量,但是数组名不是变量,因而像 a = b 和 a++ 这样的语句是非法的。

三、字符指针与函数

    字符串常量最常见的用处或许就是作为函数变元:

    printf("hello world\n");

    当这样的一个字符串出现在程序中时,实际上时通过字符指针指向访问它,上述函数printf接收的是一个指向字符数组的头一个字符的指针。

    语句

    char *p;

    p = "hello world";

    把一个指向该字符的数组指针赋值给指针变量p,其中并未进行字符串的复制,只涉及到指针的操作。c语言中没有提供将一个完整的字符串作为一个整体处理的运算符。

    下面两个定义差别很大:

    char a[] = "hello world";
    char  *p = "hello world";
     a是一个足以存放字符串初值和空字符'/0'的一位数组。可以更改数组中的单个字符,但是a是一个不可改变的常量,它总是指向同一个存储区。p是一个指针,其初值指向一个字符串常量,之后它可以被修改指向其他地址。

在C语言中,数组指针之间存在着密切关系,尽管它们在概念上是不同的。以下是关于C语言数组指针关系的一些要点: - **数组名作为指针**:在大多数情况下,数组名在表达式中会被当作指向其第一个元素的指针。例如,如果你有一个数组`int arr[10];`,那么`arr`在大多数上下文中会被当作一个指向`arr[0]`的指针。 - **地址运算**:可以对数组名进行地址运算(如`&arr`或`arr + 1`),这会得到整个数组的地址或指向下一个元素的指针。同样地,也可以对指向数组元素的指针进行地址运算。 - **访问数组元素**:使用数组下标(如`arr[i]`)与使用指针偏移(如`*(arr + i)`)在访问数组元素上是等效的。 ```c #include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 使用数组下标访问元素 printf("arr[2] = %d\n", arr[2]); // 使用指针偏移访问元素 printf("*(arr + 2) = %d\n", *(arr + 2)); return 0; } ``` - **函数参数**:当数组作为函数参数传递时,它实际上会退化为指向其第一个元素的指针。因此,在函数内部,无法知道数组的大小(除非作为另一个参数传递),但可以通过指针访问数组的元素。 ```c #include <stdio.h> void printArray(int *arr, int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[5] = {1, 2, 3, 4, 5}; printArray(arr, 5); return 0; } ``` - **指针数组数组指针**:指针数组是一个数组,其元素是指针。例如,`int* ptrArray[10];`定义了一个可以存储10个整数指针数组数组指针是一个指向数组指针。例如,`int (*arrayPtr)[10];`定义了一个指向包含10个整数的数组指针。 - **动态内存分配**:使用`malloc`、`calloc`或`realloc`等函数分配的内存区域通常是通过指针来访问的,这些内存区域在逻辑上可以被视为数组(尽管它们在物理上可能不是连续的)。 需要注意的是,数组的大小在编译时是固定的,而指针可以指向任意大小的内存区域(只要该区域已被分配且指针已正确初始化)。对指针进行解引用(即使用`*`操作符)时要特别小心,确保指针指向有效的内存区域,否则可能会导致未定义的行为或程序崩溃[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值