打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C语言指针入门(解决你的各种概念问题的总结,包括空指针、野指针、数组指针、指针数组、函数指针、指针函...

本文记录了一些C指针的定义,包括空指针、野指针、数组指针、指针数组、函数指针、指针函数、多级指针等等一些知识点的小结。
参考工程(vs19编写):代码下载

1.空指针:

没有赋值的指针变量(没有指向内存变量的地址),对空指针操作会造成程序的Core dump(段错误)

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p_i = 0;

	printf('p_i = %p \r\n', p_i);
	
	*p_i = 2;// 试图对空指针进行赋值操作,程序会崩溃
	
	return 0;
}

2.野指针:

指向的内存被释放了的指针,但指针的值不会清零。对其操作不可预知。

以下操作均为错误操作。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int *p_i = (int *) malloc(sizeof(int));
	*p_i = 10;
	printf('p_i = %d \r\n',*p_i);

	free(p_i);
		
	*p_i = 2;
	printf('pi = %d \r\n',*p_i);

	return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int *p_i = (int *) malloc(sizeof(int));
	*p_i = 10;
	printf('p_i = %d \r\n',*p_i);

	free(p_i);
		
	*p_i = 2;
	printf('pi = %d \r\n',*p_i);

	FILE *fp=fopen('1.txt','w');
	printf('fp is %p\r\n',fp);

	fclose(fp);

	printf('fp is %p\r\n',fp);
	//fclose(fp);
	return 0;
}

free ( p );带上p = 0;避免野指针错误。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	char* p = (char*)malloc(sizeof(char)*4);
	
	free(p);
	p = 0;

	strcpy(p,'123');
	printf('%s\r\n', p);
	return 0;
}

3.数组

数组名、数组地址、数字首元素地址均为同一地址。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	char num[20] = 'hello word';
	
	printf('数组名     %p \r\n', num);
	printf('数组地址   %p \r\n', &num);
	printf('数组首元素 %p \r\n', &num[0]);

	printf('打印以数组名     %s \r\n', num);
	printf('打印以数组地址   %s \r\n', &num);
	printf('打印以数组首元素 %s \r\n', &num[0]);
	return 0;
}

结果:

sizeof的坑

sizeof(数组)会得到数组长度,但是通过函数传入数组的指针sizeof却是指针的大小。

如果数组的长度小于指针的大小,会导致程序崩溃,如下代码。不同系统指针大小不一致。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fun(char* p);

int main()
{
	char str[3] ;

	printf('%d\r\n', sizeof(str));

	fun(str);
	
	
	return 0;
}

void fun(char* p)
{
	printf('%d\r\n', sizeof(p));
	memset(p, 0, sizeof(p));

	scanf('%s',p);

	printf('%%p :%p \r\n',p);
	printf('%%s :%s \r\n',p);

}

建议:不要在函数里面调用memset时,使用sizeof计算长度。

补充:结构体用sizeof计算指针也会出错。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Student
{
	int age;
	char name[21];
};

void fun(struct Student* p)
{
	printf('in fun() sizeof: %ld\r\n', sizeof(p));// sizeof(struct Student)
	memset(p, 0, sizeof(p));// 不建议使用,指清除了指针大小个字节
	// 建议改为下述代码,使用sizeof(struct Student)
    // memset(p, 0, sizeof(struct Student));
}

int main()
{
	struct Student stu = { 22,'LiHua' };

	printf('in main() sizeof :%ld\r\n', sizeof(stu));

	fun(&stu);
	return 0;
}

vs19编译结果:(指针4字节)

虚拟机结果:(指针8字节)

为什么结构体大小28?

因为int 4字节,结构体4字节对齐,所以为28。

4.地址的运算

地址可加减运算:+1表示加一个存储单位的地址,-1减一个存储单位的地址。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char    cc[4];
	int     ii[4];
	double  dd[4];

	printf('  char: %p %p %p %p\r\n', cc, cc+1, cc+2, cc+3);
	printf('   int: %p %p %p %p\r\n', ii, ii+1, ii+2, ii+3);
	printf('double: %p %p %p %p\r\n', dd, dd+1, dd+2, dd+3);
	return 0;
}

vs19运行结果:(char + 1,int + 4,double + 8)

同样的使用地址操作可以直接访问数组元素,如*(cc+1)cc[1]等效。

众所周知,C语言的标准库没有字符串截取函数。为什么?笔者认为可能是没有必要。因为可以直接地址运算操作地址实现。

字符串截取举例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char src[12] = 'hello world';
	char dest[10];
	memset(dest, 0, 10);

	// 将src截取后面world赋值给dest
	strncpy(dest,src + 6, 5);// 地址操作

	printf('dest:%s\r\n',dest);
	return 0;
}

vs19运行结果:

5.字符串常量的地址:

在C里面字符串实际就是以'\0’为结束符的char类型一维数组,故同样可以作为一个地址。它的值为字符串的首地址。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HD 'hello world'

int main()
{
	char *str = 'hello world';
	
	char* str1 = '23333';

	printf('HD:%s \r\n', str + 6);

	printf('str1:%s\r\n',str1);
	return 0;
}

结果:

但因为是常量,所有并不能直接通过str[0] = 'H’来改变字符串的值,使字符串变成“Hello word”。这种做法是错误的。

6.函数指针

定义:C程序每一个函数都有一个入口地址,所谓函数指针就是指向函数入口地址的指针变量。

应用:调用函数和做函数的参数。

定义格式:

返回值类型 (* 函数指针)(参数列表...)

返回值和参数列表应该和要指向的函数保持一致。

此外:函数名也是指针,即fun_max&fun_max等效。

改变指针变量的指向不同的函数,可以实现类似多态的效果。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 返回最大值
int fun_max(int x, int y)
{
	if (x > y) return x;

	return y;
}

// 返回最小值
int fun_min(int x, int y)
{
	if (x < y) return x;

	return y;
}

int main()
{
	int a = 2;
	int b = 5;
	// 定义函数指针
	int (*fun_ptr)(int, int);// 格式要匹配,返回值、参数及参数个数顺序都要一致。

	fun_ptr = &fun_max;		// 函数名也是指针,与fun_ptr = fun_max;等效
	printf('max:%d\r\n', fun_ptr(a,b));

	fun_ptr = fun_min;
	printf('min:%d\r\n', fun_ptr(a, b));

	return 0;
}

运行结果:

max:5
min:2 

函数指针常常和typedef组合使用,更直观。
如上可以写为:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 格式要匹配,返回值、参数及参数个数顺序都要一致。
typedef int (* _fun_ptr_t)(int,int);

// 返回最大值
int fun_max(int x, int y)
{
	if (x > y) return x;

	return y;
}
// 返回最小值
int fun_min(int x, int y)
{
	if (x < y) return x;

	return y;
}
int main()
{
	int a = 2;
	int b = 5;
	// 使用typedef定义函数指针
	_fun_ptr_t fun_ptr;
	
	fun_ptr = &fun_max;		// 函数名也是指针,与fun_ptr = fun_max;等效

	printf('max:%d\r\n', fun_ptr(a,b));

	fun_ptr = fun_min;
	printf('min:%d\r\n', fun_ptr(a, b));

	return 0;
}

7.指针函数:

定义:返回值为一个地址的函数

#include<stdio.h>

char* getword(char);

char* getword(char c)
{
    switch (c)
    {
    case'A':return'Apple';
    case'B':return'Banana';
    case'C':return'Cat';
    case'D':return'Dog';
    default:return'None';
    }
}
int main()
{
    char input;
    printf('请输入一个大写字母:\n');
    scanf('%c', &input);

    printf('%s\n', getword(input));
}

测试输入字母输出对应字符串

比如:

请输入一个大写字母:
C
Cat

8.数组指针与指针数组

指针数组:

int *p1[10];

解释:[]的优先级比*高,p[10]表示一个大小为10个单位的数组,int *再来修饰数组的内容,表示p1数组为一个存储10个int型指针的数组。

数组指针:指向一个数组的指针。

int (*p2)[10];

解释:(*p2)表示一个指针,[10]说明是一个数组,int修饰数组元素的类型,综上就是定义了一个指针p2,它指向有10个int元素数组的首地址。

无聊。。。。

9.多级指针

无聊的一个概念,说白了就是指针指向指针。

举例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	int         i = 2;
	int*       pi = &i;
	int**     ppi = &pi;
	int***   pppi = &ppi;
	printf('%d\r\n',       i);
	printf('%d\r\n',     *pi);
	printf('%d\r\n',   **ppi);
	printf('%d\r\n', ***pppi);

	return 0;
}

类似俄罗斯套娃,要是乐意可以一直“取地址”再“解引用”。

运行结果:(说明了这都是2)

2
2
2
2

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
《C语言程序设计》第7章 指针、函数和数组写字字帖
C|函数指针与回调函数模拟实现委托与反射
C语言面试题
C/C++中的指针和数组(二)
C语言难点分析整理
sizeof(数组)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服