【C语言】进阶指针(一)

目录

前言: 

一、字符指针

二、指针数组与数组指针

(一)指针数组

(二)数组指针

三、数组传参与指针传参

(一)数组传参

(二)指针传参


前言: 

进阶指针我打算分三篇文章进行讲解,第一篇主要围绕数组与指针进行,第二篇主要围绕函数指针进行,最后一篇会引入面试题讲解。

指针的基本概念:

1、指针就是个变量,用来存放地址,地址唯一标识一块内存空间。

2、指针的大小是固定的4/8个字节(32位/64位)

3、指针是有类型,指针的类型决定的指针+-整数的步长,指针解引用操作的权限。

一、字符指针

字符指针就是指针类型为字符的指针:char*。

可以这样定义:

int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}

 如果是字符串呢?

int main()
{
	char* pstr = "hello world.";
	printf("%s\n", pstr);
	return 0;
}

 注意这里指针变量pstr中存放的是字符串中首字符的地址

一道面试题:

int main()
{
    char str1[] = "hello world.";
    char str2[] = "hello world.";
    const char* str3 = "hello world.";
    const char* str4 = "hello world.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");
    return 0;
}

 输出结果:

str1 and str2 are not same

str3 and str4 are same

分析:str1与str2为两个数组,而数组名代表首元素地址,所以str1与str2不相同。而str3与str4指向的是同一个字符串常量,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存

二、指针数组与数组指针

(一)指针数组

指针数组是数组,数组存放的内容是指针,那么很简单定义数组的时候,数组类型定义为XXX*即可,如:

int* arr1[10]; //整型指针的数组
char* arr2[4]; //一级字符指针的数组
char** arr3[5];//二级字符指针的数组

(二)数组指针

数组指针是指针,指针指向的内容为数组。

观察下面的代码,哪个是数组指针?

int* p1[10];
int (*p2)[10];

注:[]操作符的优先级高于*。

分析:p1为指针数组。p2先于*结合,即p2为指针变量,指针变量的类型为int [10]整型数组,所以p2为数组指针。

【C语言】进阶指针(一)_第1张图片

我们知道数组名arr表示首元素的地址,那么&arr 取出的是不是首元素的地址呢?

其实数组名表示数组首元素的地址有两个例外:

1、sizeof(arr),sizeof计算的是整个数组大小,单位为字节。

2、&arr,此时取出的是整个数组的地址。

 我们利用下面的代码进行验证:

int main()
{
	int arr[10] = { 0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

 结果为:

【C语言】进阶指针(一)_第2张图片

 我们发现&arr+1跳过的是整个数组的大小。

数组指针一般用于二维数组中。如:

void print_arr1(int arr[3][5], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

void print_arr2(int(*arr)[5], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
    print_arr1(arr, 3, 5);
    //数组名arr,表示首元素的地址
    //但是二维数组的首元素是二维数组的第一行
    //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    //可以数组指针来接收
    print_arr2(arr, 3, 5);
    return 0;
}

三、数组传参与指针传参

如何将【数组】或【指针】作为参数传给函数呢?

(一)数组传参

正确设计:

void test1(int arr[])
{}
void test1(int arr[10])
{}
void test1(int* arr)
{}
void test2(int* arr[20])
{}
void test2(int** arr)
{}
void test3(int arr[3][5])
{}
void test3(int arr[][5])
{}
void test3(int (*arr)[5])
{}
int main()
{
	int arr1[10] = { 0 };
	int* arr2[20] = { 0 };
	int arr3[3][5] = { 0 };
	test1(arr1);
	test2(arr2);
	test3(arr3);
}

错误设计:

void test3(int arr[][])//err
{}
void test3(int* arr)//err
{}
void test3(int* arr[5])//err
{}
void test3(int** arr)//err
{}
int main()
{
	int arr1[10] = { 0 };
	int* arr2[20] = { 0 };
	int arr3[3][5] = { 0 };
	test1(arr1);
	test2(arr2);
	test3(arr3);
}

 错误分析:

首先要搞清楚函数参数的类型,test3(arr3)中明显传入的是arr3数组的首元素地址,又arr3为二维数组,所以该函数实际传入参数为arr3首行元素的地址,本质是指针

然后我们看函数定义中设计的参数:

void test3(int arr[][])二维数组可以省略行,但是不能省略列,所以该函数设计错误。
void test3(int* arr)此函数设计参数类型为指针数组,本质是数组,与传入参数不符,所以该函数设计错误。
void test3(int* arr[5])同上。
void test3(int** arr)此函数设计参数类型为二级指针数组,本质是数组,与传入参数不符,所以该函数设计错误。

(二)指针传参

void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

当函数的参数部分为一级指针时,该函数能接收什么参数呢?

比如:void test(char* p)

以下供参考: 

void test(char* p)
{}

int main()
{
	char ch = 'w';
	char ptr = &ch;
	char arr[] = "abcdef";
	test(&ch);
	test(ptr);
	test(arr);
}

 当函数的参数部分为二级指针时,该函数又能接收什么参数呢?比如:

void test1(int** p1)

void test2(char** p2)

以下供参考: 

void test1(int** p)
{}
void test2(char** p)
{}
int main()
{
	int n = 10;
	int* p1 = &n;
	int** pp = &p1;
	test1(pp);
	test1(&p1);
	char c = 'b';
	char* pc = &c;
	char** ppc = &pc;
	char* arr[10];
	test2(&pc);
	test2(ppc);
	test2(arr);
	return 0;
}

今天的内容就分享到这,接下来博主还会继续跟进进阶指针的更新,关注博主不迷路

你可能感兴趣的:(C语言,c语言,学习,程序人生,笔记)