当前位置:网站首页>C语言指针的进阶(上篇)
C语言指针的进阶(上篇)
2022-07-01 08:30:00 【清炒莲藕拌饭】
博主: 清炒莲藕拌饭
博客:(10条消息) 清炒莲藕拌饭的博客_CSDN博客-C语言领域博主
专栏:(10条消息) C语言_清炒莲藕拌饭的博客-CSDN博客
专栏介绍:包含从C语言初阶到进阶各各知识点进行讲解,用C语言写的各种小程序,大体围绕C基础为主的专栏;
*本篇博客介绍重点️
1. 字符指针
2. 数组指针
3. 指针数组
4. 数组传参和指针传参
5. 函数指针
前言回顾:
1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。 4. 指针的运算。
1.字符指针
前面我们应该也见过 char* 字符指针,一般出现下面使用情况:
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
int main()
{
const char* pstr = "hello";//这里是把一个字符串放到pstr指针变量里了吗?
printf("%s\n", pstr);
return 0;
}
打印结果就是hello,那是不是pstr里面就存放的字符串hello呢?千万不要这样认为,指针变量都是存放地址的,pstr应该说是存放字符串首元素的地址,printf打印就会按照这个地址打印下去,遇到\0就会停止打印;
上面的代码看明白了我们来看下面这段代码:
#include <stdio.h> int main() { char str1[] = "hello bit."; char str2[] = "hello bit."; const char *str3 = "hello bit."; const char *str4 = "hello bit."; 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==str2 和 str3==str4是什么意思,这个表达式其实表示在比较它们的地址是否相同,那么str1和str2它们是两个不相同的数组,地址怎么可能一样呢?而str3和str4它们都是字符常量,不需要在内存中开辟新的空间,它们的首地址都是指向字符‘h’的,所以地址肯定也一样;
2.指针数组
指针数组就是一个存放指针类型的数组,它里面的元素都是指针类型;
int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5]; //二级字符指针的数组
优先级理解:arr1先和[ 10 ]结合,说明这就是一个数组,数组的类型是它前面int *,说明这是一个指针数组,用来存放指针的;
3.数组指针
3.1 数组指针的定义
数组指针是什么?
它是指针,指向数组的指针,我们前面已经知道有int *pa 整型指针 , float *pb 浮点型指针,它们都是指向某个类型的指针,那么数组指针也一样,它指向的类型是一个数组;
int * arr1[10] = { 0 };
int (* arr2)[10] = { 0 }; //arr1和arr2分别是什么?
arr1前面我们已经介绍过了,它是指针数组;
arr2注意看它的(*arr2),这说明无论如何arr2已经和*结合了,这就表明arr2就是指针了而不是数组名了,因为它没有机会和[10]去结合了,而指向的类型就是int [10],所以我们叫它数组指针;
注意:因为[ ]的优先级比*高,arr2会先和[10]结合,所以你如果想要的是一个数组指针就必须加上()让*和arr2先结合,这样才能保证arr2是一个数组指针;
3.2 &数组名VS数组名
int arr[10] = { 0 };
&arr和arr有什么不一样的吗?好像是一模一样的,arr是数组首元素地址&arr同样也是首元素地址,居然一样何必这么麻烦还要用&呢?
我的答案是NO! 编程讲究严谨,那么它的语法更是如此,存放的内容一样不代表它们意义就相等了,空口无凭下面我就带大家来研究&arr和arr的区别;
我们打印它们的地址确实一样
#include <stdio.h> int main() { int arr[10] = {0}; printf("%p\n", arr); printf("%p\n", &arr); return 0; }
运行结果:
但是我们来看下面这段代码:
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("arr+1 = %p\n", arr + 1);
printf("&arr= %p\n", &arr);
printf("&arr+1= %p\n", &arr + 1);
return 0;
}
运行结果:
这说明什么?&arr和arr虽然值一样,但是它们的意义肯定不一样,所以有些事我们不要被表象迷惑,事情有疑点那我们就刨根问底然后将它斩于马下;事实上&arr是代表数组所有元素的地址,但是总得有一个地址来表达它们,但是空间又有限不可能将所有的元素地址表达出来,所以还是使用了数组首元素来来代表它们,但是它的意义却不一样了;
思考:
&arr大家可以仔细想一想它是什么?它是不是一个数组指针啊,确实是的,&arr所指向的就是arr整个数组,在本案例中它的类型是int (*)[10];
数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40.
3.3数组指针的使用
既然有数组指针这个东西那我们应该怎么使用呢?
栗子1(不常用):
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
//但是我们一般很少这样写代码
return 0;
}
栗子2(常用):
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
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++)
{
int j = 0;
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;
}
学了指针数组和数组指针我们来一起回顾并看看下面代码的意思:
int arr[5]; //整型数组
int *parr1[10]; //指针数组
int (*parr2)[10]; //数组指针
int (*parr3[10])[5]; //存放数组指针的数组
4.数组参数,指针参数
在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?
4.1一维数组传参
#include <stdio.h>
void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr[20])//ok
{}
void test2(int **arr)//ok
{}
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
return 0;
}
4.2 二维数组传参
void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}
4.3 一级指针传参
#include <stdio.h>
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;
}
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
4.4 二级指针传参
#include <stdio.h>
void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int*p = &n;
int **pp = &p;
test(pp);
test(&p);
return 0;
}
当函数的参数为二级指针的时候,可以接收什么参数?
边栏推荐
猜你喜欢
Li Kou 1358 -- number of substrings containing all three characters (double pointer)
Gateway-88
P4 installation bmv2 detailed tutorial
[detailed explanation of Huawei machine test] judgment string subsequence [2022 Q1 Q2 | 200 points]
What is 1cr0.5mo (H) material? 1cr0.5mo (H) tensile yield strength
《MATLAB 神经网络43个案例分析》:第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断
MD文档中插入数学公式,Typora中插入数学公式
2022.2.15
CPU设计实战-第四章实践任务一简单CPU参考设计调试
避免按钮重复点击的小工具bimianchongfu.queren()
随机推荐
你了解数据是如何存储的吗?(C整型和浮点型两类)
Adding color blocks to Seaborn clustermap matrix
栈实现计算器
The use of word in graduation thesis
Leetcode t31: prochain arrangement
爬虫知识点总结
Leetcode t39: combined sum
华为机试真题专栏订阅指引
《微机原理》-绪论
Audio audiorecord create (I)
串口转WIFI模块通信
《MATLAB 神经网络43个案例分析》:第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断
[deep analysis of C language] - data storage in memory
MATLAB小技巧(23)矩阵分析--模拟退火
TypeError: __ init__ () got an unexpected keyword argument ‘autocompletion‘
Luogu p1088 [noip2004 popularization group] Martians
Serial port to WiFi module communication
leetcode T31:下一排列
Configuration and startup of Chang'an chain synchronization node
On several key issues of digital transformation