• 指针: 用来存放变量地址的变量,就成为"指针变量".

  • 定义: 一般形式:类名标识符 *指针变量名;

    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指针那点事儿的更多相关文章

  1. iOS 关于僵尸对象和僵尸指针的那些事儿

    引言 提到僵尸就感到一种恐怖,大家都知道“僵尸”是没有生命的,但是它确实是一种存在的类似生命体的一种生物.哈哈,当然本文的重点不是讨论“僵尸”,而是有关于ios当中经常遇到的僵尸指针(Zombie P ...

  2. 面试6-----11 const和静态变量那些事儿

    6 看看const和指针的那些事儿 const在int*左边 const在int*右边 const在int*两边------>请看代码注释 (1)代码 #include <stdio.h& ...

  3. C语言中指针和数组

    C语言数组与指针的那些事儿 在C语言中,要说到哪一部分最难搞,首当其冲就是指针,指针永远是个让人又爱又恨的东西,用好了可以事半功倍,用不好,就会有改不完的bug和通不完的宵.但是程序员一般都有一种迷之 ...

  4. c语言中双维数组与指针的那点事儿

    说起c语言的指针,估计对c语言只是一知半解的同志们可能都会很头疼,尤其它跟数组又无耻的联系到一起的时候,就更加淫荡了!!! 怎么说呢,就是有一点规定:(或准则) 数组名可以看成是指向数组头元素的指针, ...

  5. MVC之前的那点事儿系列(3):HttpRuntime详解分析(下)

    文章内容 话说,经过各种各样复杂的我们不知道的内部处理,非托管代码正式开始调用ISPAIRuntime的ProcessRequest方法了(ISPAIRuntime继承了IISPAIRuntime接口 ...

  6. C 语言函数参数只能传指针,不能传数组

    今天被要求编写一个C/C++冒泡算法的程序,心想这还不是手到擒来的事儿,虽然最近都是用Javascript程序,很少写C/C++程序,但是好歹也用过那么多年的C语言: 首先想的是怎么让自己的代码看上去 ...

  7. Block编程值得注意的那些事儿

    [深入浅出Cocoa]Block编程值得注意的那些事儿   [深入浅出Cocoa]Block编程值得注意的那些事儿 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循 ...

  8. Linux下的”锁“事儿

    原由 之所以写这篇文章当然还是在面试中涉及了对本文标题的相关问题-互斥锁和自旋锁的区别.听到这个问题的时候,我是比较忐忑的.互斥锁我还能简单说一些,但是对于自旋锁的了解几乎为零.为此,将总结Linux ...

  9. Android中JNI编程的那些事儿(1)

    转:Android中JNI编程的那些事儿(1)http://mobile.51cto.com/android-267538.htm Android系统不允许一个纯粹使用C/C++的程序出现,它要求必须 ...

随机推荐

  1. JavaScript中的正则表达式详解

    摘要:javascript中的正则表达式作为相当重要的知识,本文将介绍正则表达式的相关知识和用法. 正则表达式(Regular Expression)是一门简单语言的语法规范,是强大.便捷.高效的文本 ...

  2. 什么是c/c++编译

    GCC是什么 GNU Compiler Collection的缩写,一开始是c语言的编译器,但现今可以支持多种语言的编译工作,也支持了多个硬件平台的编译.总而言之,主流的c语言编译器就是这个gcc了. ...

  3. google protocol buffer——protobuf的基本使用和模型分析

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 1.什么是protobuf ...

  4. windows下Nacos集群搭建与nginx集成

    前言: nacos集群至少需要三个(一般为奇数个)nacos实 例,其前面顶nginx,外界入口从nginx入 一.windows下Nacos集群搭建 将Nacos的解压包复制分成3份,分别是: na ...

  5. java自动拆装箱

    介绍 Java 5增加了自动装箱与自动拆箱机制,方便基本类型与包装类型的相互转换操作.(关于基本类型与包装类型之前有记录过https://www.cnblogs.com/xiuzhublog/p/12 ...

  6. 浅谈AutoML

    Auto ML的概念很广很深,本篇文章旨在概念上的一些理解.   我们之前谈过一个模型从幕后走向台前是有很多的工作要做的,AutoML的最初目标正如其名字是想自动化这个过程.实际上有很多人讨论到Aut ...

  7. centos yum 安装golang

    rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm yum install golan ...

  8. SpringCloud Alibaba之Nacos

    一.运行Nacos Nacos GitHub开源地址:https://github.com/alibaba/nacos Nacos 官方文档:https://nacos.io/zh-cn/docs/q ...

  9. Jupyter Notebook 入门指南

    https://www.jianshu.com/p/061c6e5c4b0d cmd输入 :jupyter notebook

  10. Hadoop的SecondaryNameNode的作用是什么?

    为节省篇幅,将SecondaryNameNode简称SNN,NameNode简称NN. NN与fsimage.edits文件 NN负责管理HDFS中所有的元数据,包括但不限于文件/目录结构.文件权限. ...