个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

    • 内存
    • 数组
    • 指针
      • 1 动态内存分配
        • 1.1 malloc 和 free
        • 1.2 calloc 和 realloc
      • 2 高级声明
      • 3 函数指针
        • 3.1 回调函数
        • 3.2 转换表/转移表
    • 字符串
    • 预处理
    • 结构和联合
    • 文件操作
    • 标准函数库
    • C语言总结
  • CPlusPlus

  • Lua技术栈

  • edoyun

  • 内存管理

  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • C语言
Agnes001
2021-03-27

指针

# 1 动态内存分配

# 1.1 malloc 和 free

分别用于执行动态内存分配和释放。这些函数维护一个可用内存池。malloc从内存池提取一块合适的内存,并返回一个指向这块内存的指针,可以自己初始化,也可以使用calloc函数;free把它还给内存池。

#inlude <stdlib.h>
void *malloc(size_t size); // 参数是需要分配的字节数,对每个从malloc返回的指针需要进行检查,确保不是NULL
void free(void *pointer);

free之后要记得将指针置零,指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。如果此时不把p设置为NULL,会让人误以为p是个合法的指针。

如何杜绝野指针?
“野指针”不是NULL 指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if 语句很容易判断。但是“野指针”是很危险的,if 语句对它不起作用。
“野指针”的成因主要有两种:
(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL 指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如
char *p = NULL;
char *str = (char *) malloc(100);
(2)指针p 被free 或者delete 之后,没有置为NULL,让人误以为p 是个合法的指针。

# 1.2 calloc 和 realloc

// 内存分配函数
void *calloc(size_t num_elements, size_t element_size); // 返回指向内存的指针之前把它初始化为0,参数为所需元素的数量和每个元素的字节数
void *realloc(void *ptr, size_t new_size); // 修改一个原先已经分配的内存块的大小

警告:

必须检查所请求的内存是否分配成功。

# 2 高级声明

int f; /* 一个整型变量 */
int *f; /* 一个指向整型的指针 */ // 表达式*f声明为一个整数

int f(); /* f声明为一个函数,它的返回值是一个整数 */
int *f(); /* f是一个函数,它的返回值类型是一个指向整型的指针 */

int (*f)(); /* f是一个函数指针,所指向的函数返回一个整型值 */
// 程序中每个函数都位于内存中的某个位置,所以存在指向那个位置的指针是完全可能的
int *(*f)(); /* f是一个函数指针,所指向的函数的返回值一个整型指针,必须对其进行间接访问操作才能得到一个整型值 */

int f[]; /* 一个整型数组 */
int *f[]; /* f是一个数组,它的元素类型是指向整型的指针 */
int f()[]; /* f是一个函数,它的返回值是一个整型数组,但这个声明是非法的,函数只能返回标量值,不能返回数组 */
int (*f[])();/* f是一个元素为某种类型的指针的数组,数组元素的类型是函数的指针,它所指向的函数的返回值是一个整型值 */
int *(*f[])(); /* 指针数组,指针所指向的类型是返回值为整型指针的函数 */

int (*f)(int, folat); /* f是函数指针,所指的函数接收两个参数,分别是一个整型值和浮点型值,并返回一个整型值 */
int *(*g[])(int, float); /* g是一个数组,数组的元素类型是一个函数指针,它所指向的函数接收两个参数,分别是一个整型值和浮点型值,并返回一个整型指针 */

# 3 函数指针

两个用途:转换表和作为参数传递给另一个函数

int f(int);
int (*fp)(int) = &p;
// 初始化表达式中的&操作符是可选的,因为函数名被使用时总是由编译器把它转换成函数指针。&操作符只是显式地说明了编译器将隐式执行的任务

int ans;
ans = f(25); /* 函数名f首先被转换成一个函数指针,该指针指定函数在内存中的位置,然后,函数调用操作符调用该函数,执行开始于这个地址的代码 */
ans = (*fp)(25); /* 对fp执行间接访问操作,它把函数指针转换成一个函数名,这个转换并不是真正需要的,因为编译器在执行函数调用操作符之前又会把它转换回去,不过这条语句的效果和第1条语句是完全一样的 */
ans = fp(25); /* 与前两条语句的效果是一样的,间接访问符并非必需,因为编译器需要的是一个函数指针,这个例子显示了函数指针通常是如何使用的 */

# 3.1 回调函数

// 在一个单链表中查找一个值
Node *
search_list(Node *node, int const value)
{
    while(node != NULL)
    {
        if(node->value == value)
			break;
        node = node->link;
    }
    return node;
}
// 一种更为通用的方法是使查找函数与类型无关。不同类型的比较使用函数指针实现,调用者编写一个函数用于比较两个值,然后把一个指向这个函数的指针作为参数传递给查找函数,然后查找函数调用这个函数来执行值的比较。
// 回调函数:用户把一个函数指针作为参数传递给其他函数,后者将“回调”用户的函数
// void *  表示"一个指向未知类型的指针",使用时,它必须被强制转换成正确的类型。
// 在这个例子中,回调函数比较两个值。查找函数向比较函数传递两个指向需要进行比较的值的指针,并检查比较函数的返回值,例如。零表示相等的值,非零值表示不相等的值。
#include <stdio.h>
#include "node.h"
Node *
search_list(Node *node, void const *value, 
            int (*compare)(void const *, void const *))
{
    while(node != NULL)
    {
        if(compare(&node->value, value) == 0)
            break;
        node = node->link;
    }
    return node;
}
// 比较函数
int
compare_ints(void const *a, void const *b)
{
    if( *(int *)a == *(int *)b)
		return 0;
    else
    	return 1;
}
// 调用
desired_node = search_list(root, &desired_value, compare_ints);
desired_node = search_list(root, "desired_value", strcmp);

# 3.2 转换表/转移表

#include <stdio.h>
#include <string.h>
#define M 4
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
int (*oper_func[])(int, int) = {
 add, sub, mul, div
};
char oper_sequence[M][10] = {
 "add", "sub", "mul", "div"
};
int main()
{
 char oper[10];
 int seq;
 int a,b;
 int result;
 int i;
 printf("Operator:");
 scanf("%s",oper);
 printf("a:");
 scanf("%d",&a);
 printf("b:");
 scanf("%d",&b);
 for(i=0; i<M; i++)
 {
  if(strncmp(oper_sequence[i], oper, 3) == 0)
   seq = i;
 }
 result = oper_func[seq](a, b);
 printf("result is %d/n", result);
 return 0;
}
int add(int a, int b)
{
 return a+b;
}
int sub(int a, int b)
{
 return a-b;
}
int mul(int a, int b)
{
 return a*b;
}
int div(int a, int b)
{
 return a/b;
}
编辑此页
#point
数组
字符串

← 数组 字符串 →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式