C语言之数组指针指针数组
Posted 流楚丶格念
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言之数组指针指针数组相关的知识,希望对你有一定的参考价值。
数组与指针的爱恨情仇
数组和指针
问题导引
指针和数组并不是相等的。为了说明这个概念,请考虑下面两个声明:
int a[10];
int *b;
声明一个数组时,编译器根据声明所指定的元素数量为数组分配内存空间,然后再创建数组名,指向这段空间的起始位置。声明一个指针变量的时候,编译器只为指针本身分配内存空间,并不为任何整型值分配内存空间,指针并未初始化指向任何现有的内存空间。
因此,表达式*a
是完全合法的,但是表达式*b
却是非法的。*b
将访问内存中一个不确定的位置,将会导致程序终止。另外,如果是b++
的话是可以通过编译的,而a++
却不行,因为a是一个常量值。
b++; // 可以
a++; // 报错
作为函数参数的数组名
当一个数组名作为一个参数传递给一个函数的时候发生什么情况呢?我们现在知道数组名其实就是一个指向数组第1个元素的指针,所以很明白此时传递给函数的是一份指针的拷贝。所以函数的形参实际上是一个指针。
此时,系统也会对指针进行拷贝,然后进行一系列函数操作,当对数据操作的时候,指针指向的仍然是原数据,操作的仍是原数据本身,所以这里的即使对指针拷贝也是当做实际参数。
但是为了使程序员新手容易上手一些,编译器也接受数组形式的函数形参。因此下面两种函数原型是相等的:
int print_array(int *arr);
int print_array(int arr[]);
问题1:我们可以使用任何一种声明,但哪一个更准确一些呢?
答案是指针形式。因为实参实际上是个指针,而不是数组。同样sizeof arr值是指针的长度,而不是数组的长度。
现在我们清楚了,为什么一维数组中无须写明它的元素数目了,因为形参只是一个指针,并不需要为数组参数分配内存。另一方面,这种方式使得函数无法知道数组的长度。如果函数需要知道数组的长度,它必须显式传递一个长度参数给函数。
代码上看指针数组与数组指针
int* a[4] 指针数组
-
表示:数组a中的元素都为int型指针
-
元素表示:
*a[i]
、*(a[i])
是一样的,因为[]优先级高于*
int (*a)[4] 数组指针
-
表示:指向数组a的指针
-
元素表示:
(*a)[i]
从代码声明中看的出来,他们俩只有一个括号的区分,那么下面我们来具体说明一下:
数组指针:指向数组的指针
数组指针,它是指针,指向数组的指针。
它是指针,它是指针,它是指针。重要的事情说三遍。
数组的类型由元素类型和数组大小共同决定,例如:int array[5]
的类型为 int[5]
;
数组指针的定义
C语言可通过typedef定义一个数组类型:
定义数组指针有一下三种方式:
方式一
void test01(){
//先定义数组类型,再用数组类型定义数组指针
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//有typedef是定义类型,没有则是定义变量,下面代码定义了一个数组类型ArrayType
typedef int(ArrayType)[10];
//int ArrayType[10]; //定义一个数组,数组名为ArrayType
ArrayType myarr; //等价于 int myarr[10];
ArrayType* pArr = &arr; //定义了一个数组指针pArr,并且指针指向数组arr
for (int i = 0; i < 10;i++){
printf("%d ",(*pArr)[i]);
}
printf("\\n");
}
方式二
void test02(){
int arr[10];
//定义数组指针类型
typedef int(*ArrayType)[10];
ArrayType pArr = &arr; //定义了一个数组指针pArr,并且指针指向数组arr
for (int i = 0; i < 10; i++){
(*pArr)[i] = i + 1;
}
for (int i = 0; i < 10; i++){
printf("%d ", (*pArr)[i]);
}
printf("\\n");
}
方式三
void test03(){
int arr[10];
int(*pArr)[10] = &arr;
for (int i = 0; i < 10; i++){
(*pArr)[i] = i + 1;
}
for (int i = 0; i < 10; i++){
printf("%d ", (*pArr)[i]);
}
printf("\\n");
}
输出:
指针数组:数组元素为指针
指针数组,它是数组,数组中的元素为指针。
其实就是我们熟知的存数据的数组。
他又分两种:栈区指针数组(系统自动分配空间)与堆区指针数组(程序员通过malloc new分配空间)
栈区指针数组
不申请内存空间:
#include<stdio.h>
#include<string.h>
// 数组做函数函数,退化为指针
void array_sort(char** arr, int len) {
for (int i = 0; i < len; i++) {
for (int j = len - 1; j > i; j--) {
//比较两个字符串
if (strcmp(arr[j - 1], arr[j]) > 0) {
char* temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
}
// 打印数组
void array_print(char** arr, int len) {
for (int i = 0; i < len; i++) {
printf("%s\\n", arr[i]);
}
printf("--------------------------\\n");
}
void test() {
//主调函数分配内存
//指针数组
char* p[] = { "bbb", "aaa", "ccc", "eee", "ddd" };
//char** p = { "aaa", "bbb", "ccc", "ddd", "eee" }; //错误
int len = sizeof(p) / sizeof(char*);
//打印数组
printf("排序前:\\n");
array_print(p, len);
//对字符串进行排序
array_sort(p, len);
//打印数组
printf("排序后:\\n");
array_print(p, len);
}
int main()
{
test();
return 0;
}
运行结果:
堆区指针数组
动态申请内存空间:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//分配内存
char** allocate_memory(int n) {
if (n < 0) {
return NULL;
}
char** temp = (char**)malloc(sizeof(char*) * n);
if (temp == NULL) {
return NULL;
}
//分别给每一个指针malloc分配内存
for (int i = 0; i < n; i++) {
temp[i] = (char *)malloc(sizeof(char) * 30);
sprintf(temp[i], "%2d 大家好!", i + 1);
}
return temp;
}
//打印数组
void array_print(char** arr, int len) {
for (int i = 0; i < len; i++) {
printf("%s\\n", arr[i]);
}
printf("--------- 打印完了 -------------\\n");
}
//释放内存
void free_memory(char** buf, int len) {
if (buf == NULL) {
return;
}
for (int i = 0; i < len; i++) {
free(buf[i]);
buf[i] = NULL;
}
free(buf);
}
void test() {
int n = 10;
char** p = allocate_memory(n);
//打印数组
array_print(p, n);
//释放内存
free_memory(p, n);
}
int main()
{
test();
return 0;
}
运行结果:
以上是关于C语言之数组指针指针数组的主要内容,如果未能解决你的问题,请参考以下文章