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++的程序出现,它要求必须 ...
随机推荐
- 树堆(Treap)学习笔记 2020.8.12
如果一棵二叉排序树的节点插入的顺序是随机的,那么这样建立的二叉排序树在大多数情况下是平衡的,可以证明,其高度期望值为 \(O( \log_2 n )\).即使存在一些极端情况,但是这种情况发生的概率很 ...
- Node学习基础之安装node以及配置环境变量
第一步去node官网下载nodejs 我放在D盘 接着在cmd输入node -v 就能得到node的版本号 还有npm -v 下来进入安装好的目录 nodejs目录 创建两个文件夹 node_cach ...
- day1 计算机的组成
1.计算机,是用于高速计算的电子机器,具有数值计算, 逻辑判断,储存记忆的功能. 2.计算机由硬件系统和软件系统组成构成. 3.计算机中所有的运行程序都是在内存中进行的,暂时存放在CPU中的运算数据 ...
- HTTP基础 --响应
响应,由服务端返回给客户端,分为三部分:响应状态码(Response Status Code),响应头(Response Headers)和响应体(Response Body). 响应状态码 响应服务 ...
- java基本数据类型总结 类型转换 final关键字的用法
java基本数据类型总结 Java数据类型总结 数据类型在计算机语言里面,是对内存位置的一个抽象表达方式,可以理解为针对内存的一种抽象的表达方式.接触每种语言的时候,都会存在数据类型的认识,有复杂的. ...
- 尝试写一写4gl与4fd
4gl DATABASE ds GLOBALS "../../config/top.global" DEFINE g_curs_index LIKE t ...
- javaScript高级含Es6
JavaScript高级第01天笔记 1.面向过程与面向对象 1.1面向过程 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了. 1.2 ...
- UnitTest单元测试框架解析【实用篇】
UnitTest是展开自动化测试的基础——这个框架很重要!首先我们先自己写一个测试类: 1.被测试类 Widthget.py: # coding: utf-8class Widthget: def _ ...
- 07.初步学习redis哨兵机制
[ ] 一.哨兵(sentinal)的介绍 哨兵是redis集群架构中非常重要的一个组件,主要功能如下: 集群监控,负责监控redis master和slave进程是否正常工作 消息通知,如果某个re ...
- 【Flutter 实战】全局点击空白处隐藏键盘
老孟导读:为什么要实现点击空白处隐藏键盘?因为这是 iOS 平台的默认行为,Android 平台由于其弹出的键盘右上角默认带有关闭键盘的按钮,所以点击空白处不会隐藏键盘. 对于单个页面来说,通过为 T ...