C指针那点事儿
指针: 用来存放变量地址的变量,就成为"指针变量".
定义: 一般形式:类名标识符 *指针变量名;
int *p;
float *q;
"*"是说明符,用来说明这个变量是个指针变量,是不能省略的,但不属于变量名的一部分
前面的类型标志符表示指针变量所只想的变量的类型,而且只能指向这种类型的变量
示例1:值交换
```c
void swap(char *v1, char *v2) {
// 中间变量
char temp;
// 取出v1指向的变量的值
temp = *v1;
// 取出v2指向的变量的值,然后赋值给v1指向的变量
*v1 = *v2;
// 赋值给v2指向的变量
*v2 = temp;
}
int main()
{
char a = 10, b = 9;
printf("更换前:a=%d, b=%d\n", a, b);
swap(&a, &b);
printf("更换后:a=%d, b=%d", a, b);
return 0;
}
```
示例2:函数多个返回值
```c
// 计算2个整型的和与差
int sumAndMinus(int v1, int v2, int *minus) {
// 计算差,并赋值给指针指向的变量
*minus = v1 - v2;
// 计算和,并返回和
return v1 + v2;
}
int main()
{
// 定义2个int型变量
int a = 6, b = 2;
// 定义2个变量来分别接收和与差
int sum, minus;
// 调用函数
sum = sumAndMinus(a, b, &minus);
// 打印和
printf("%d+%d=%d\n", a, b, sum);
// 打印差
printf("%d-%d=%d\n", a, b, minus);
return 0;
}
```
示例3:用指针遍历字符串
// 定义一个指针p
char *p;
// 定义一个数组s存放字符串
char s[] = "mj";
// 指针p指向字符串的首字符'm'
p = s; // 或者 p = &s[0];
for (; *p != '\0'; p++) {
printf("%c \n", *p);
}
指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的。
返回指针的函数的一般形式为:类型名 * 函数名(参数列表)
示例4:比如下面这个函数,返回一个指向char类型变量的指针
```c
// 将字符串str中的小写字母变成大写字母,并返回改变后的字符串
// 注意的是:这里的参数要传字符串变量,不能传字符串常量
char * upper(char *str) {
// 先保留最初的地址。因为等会str指向的位置会变来变去的。
char *dest = str;
// 如果还不是空字符
while (*str != '\0') {
// 如果是小写字母
if (*str >= 'a' && *str <= 'z') {
// 变为大写字母。小写和大写字母的ASCII值有个固定的差值
*str -= 'a' - 'A';
}
// 遍历下一个字符
str++;
}
// 返回字符串
return dest;
}
> **_指向函数的指针_**函数作为一段程序,在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。函数有自己的地址,那就好办了,我们的指针变量就是用来存储地址的。因此,可以利用一个指针指向一个函数。其中,函数名就代表着函数的地址。
定义的一般形式:函数的返回值类型 (*指针变量名)(形式参数1, 形式参数2, ...);
```c
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
int main()
{
// 定义一个指针变量p,指向sum函数
int (*p)(int a, int b) = sum;
// 或者 int (*p)(int, int) = sum;
// 或者 int (*p)() = sum;
// 利用指针变量p调用函数
int result = (*p)(1, 3);
// 或者 int result = p(1, 3);
printf("%d", result);
return 0;
}
指向指针的函数注意
1> 由于这类指针变量存储的是一个函数的入口地址,所以对它们作加减运算(比如p++)是无意义的。难道p++就会指向下一个函数了?可笑至极!!没这回事。
2> 返回指针的函数的定义char *upper(char *str) 和 指向函数的指针的定义int ( *p)(int a, int b)非常相似,使用时特别注意区分
3> 指向函数的指针变量主要有两个用途:
调用函数
将函数作为参数在函数间传递。我这么一说,可能还不是很明白,举个例子。
#include <stdio.h>
// 减法运算
int minus(int a, int b) {
return a - b;
}
// 加法运算
int sum(int a, int b) {
return a + b;
}
// 这个counting函数是用来做a和b之间的计算,至于做加法还是减法运算,由函数的第1个参数决定
void counting( int (*p)(int, int) , int a, int b) {
int result = p(a, b);
printf("计算结果为:%d\n", result);
}
int main()
{
// 进行加法运算
counting(sum, 6, 4);
// 进行减法运算
counting(minus, 6, 4);
return 0;
}
每个结构体变量都有自己的存储空间和地址,因此指针也可以指向结构体变量
结构体指针变量的定义形式:struct 结构体名称 *指针变量名
有了指向结构体的指针,那么就有3种访问结构体成员的方式
结构体变量名.成员名
(*指针变量名).成员名
指针变量名->成员名
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 定义一个结构体类型
struct Student {
char *name;
int age;
};
// 定义一个结构体变量
struct Student stu = {"MJ", 27};
// 定义一个指向结构体的指针变量
struct Student *p;
// 指向结构体变量stu
p = &stu;
/*
这时候可以用3种方式访问结构体的成员
*/
// 方式1:结构体变量名.成员名
printf("name=%s, age = %d \n", stu.name, stu.age);
// 方式2:(*指针变量名).成员名
printf("name=%s, age = %d \n", (*p).name, (*p).age);
// 方式3:指针变量名->成员名
printf("name=%s, age = %d \n", p->name, p->age);
return 0;
}
C指针那点事儿的更多相关文章
- iOS 关于僵尸对象和僵尸指针的那些事儿
引言 提到僵尸就感到一种恐怖,大家都知道“僵尸”是没有生命的,但是它确实是一种存在的类似生命体的一种生物.哈哈,当然本文的重点不是讨论“僵尸”,而是有关于ios当中经常遇到的僵尸指针(Zombie P ...
- 面试6-----11 const和静态变量那些事儿
6 看看const和指针的那些事儿 const在int*左边 const在int*右边 const在int*两边------>请看代码注释 (1)代码 #include <stdio.h& ...
- C语言中指针和数组
C语言数组与指针的那些事儿 在C语言中,要说到哪一部分最难搞,首当其冲就是指针,指针永远是个让人又爱又恨的东西,用好了可以事半功倍,用不好,就会有改不完的bug和通不完的宵.但是程序员一般都有一种迷之 ...
- c语言中双维数组与指针的那点事儿
说起c语言的指针,估计对c语言只是一知半解的同志们可能都会很头疼,尤其它跟数组又无耻的联系到一起的时候,就更加淫荡了!!! 怎么说呢,就是有一点规定:(或准则) 数组名可以看成是指向数组头元素的指针, ...
- MVC之前的那点事儿系列(3):HttpRuntime详解分析(下)
文章内容 话说,经过各种各样复杂的我们不知道的内部处理,非托管代码正式开始调用ISPAIRuntime的ProcessRequest方法了(ISPAIRuntime继承了IISPAIRuntime接口 ...
- C 语言函数参数只能传指针,不能传数组
今天被要求编写一个C/C++冒泡算法的程序,心想这还不是手到擒来的事儿,虽然最近都是用Javascript程序,很少写C/C++程序,但是好歹也用过那么多年的C语言: 首先想的是怎么让自己的代码看上去 ...
- Block编程值得注意的那些事儿
[深入浅出Cocoa]Block编程值得注意的那些事儿 [深入浅出Cocoa]Block编程值得注意的那些事儿 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循 ...
- Linux下的”锁“事儿
原由 之所以写这篇文章当然还是在面试中涉及了对本文标题的相关问题-互斥锁和自旋锁的区别.听到这个问题的时候,我是比较忐忑的.互斥锁我还能简单说一些,但是对于自旋锁的了解几乎为零.为此,将总结Linux ...
- Android中JNI编程的那些事儿(1)
转:Android中JNI编程的那些事儿(1)http://mobile.51cto.com/android-267538.htm Android系统不允许一个纯粹使用C/C++的程序出现,它要求必须 ...
随机推荐
- github渗透测试工具库
本文作者:Yunying 原文链接:https://www.cnblogs.com/BOHB-yunying/p/11856178.html 导航: 2.漏洞练习平台 WebGoat漏洞练习平台: h ...
- 简谈DFS
所谓DFS就是“不撞南墙不回头”的一种搜索.其时间复杂度为O(V+E). 能算出从起点到终点的全部路径,在算法执行的过程中需要一个visit[vi]数组来维护每个结点的访问情况,这样就能避免重复访问. ...
- 微信小程序携带参数跳转页面/获取页面栈
页面跳转携带参数(以传递两个参数为例) a.wxml 页面传递 1 <navigator url="/pages/b/b?id=1&sid='289'"> &l ...
- ubuntu 绝望事件
@ubuntu.com hi!大家好,早上发生了很有意思的事情 显示器分辨率(x2) 系统 2560x1440 Ubuntu 20.04.1 LTS 上面的表格是现在的环境 开机进入锁屏页面,正常显示 ...
- VMware Workstation 15 Pro安装带图形化界面的CentOS7
1.双击打开“VMware Workstation”,然后选择“创建新的虚拟机” 2.在安装向导中,选择“稍后安装操作系统”,然后点击“下一步”继续安装 3.在“客户机操作系统”中选择“Linux(L ...
- css3新属性position: sticky 一分钟实现 导航栏悬停功能
css3新属性position: sticky 一分钟实现 导航栏悬停功能 前言 正文 前言 想必很多前端小伙伴经常会在开发中遇到这样一个需求,就是在下划时,导航栏悬停在屏幕最上方,例如咱们的csdn ...
- leetcode刷题记录——树
递归 104.二叉树的最大深度 /** * Definition for a binary tree node. * public class TreeNode { * int val; * Tree ...
- python列表表达式
[expression for i in iterable if condition] expression 就是对每一个元素的具体操作表达式;iterable是某个可迭代对象,如列表,元组或字符串等 ...
- 区块链入门到实战(30)之Solidity – 基础语法
一个 Solidity 源文件可以包含任意数量的合约定义.import指令和pragma指令. 让我们从一个简单的 Solidity 源程序开始.下面是一个 Solidity 源文件的例子: prag ...
- 最强云硬盘来了,让AI模型迭代从1周缩短到1天
摘要:华为云擎天架构+ Flash-Native存储引擎+低时延CurreNET,数据存储和处理还有啥担心的? 虽然我们已经进入大数据时代,但多数企业数据利用率只有10%,数据的价值没有得到充分释放. ...