征服C语言指针系列(1)重点笔试题详解

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 征服C语言指针系列(1)重点笔试题详解

1.指针与数组结合题型

1.一维数组

1.1.sizeof和整型数组

先上代码,大家可以先自己做一下这些题,

注意:

1.在32位平台下,指针大小为4个字节,在64位平台下,指针大小为8个字节

2.在这里所说的指针就是地址,地址就是指针

int a[] = { 1,2,3,4 };
  //1.
  printf("%d\n", sizeof(a));
  printf("%d\n", sizeof(a + 0));
  printf("%d\n", sizeof(*a));
  printf("%d\n", sizeof(a + 1));
  printf("%d\n", sizeof(a[1]));
  //2.
  printf("%d\n", sizeof(&a));
  printf("%d\n", sizeof(*&a));
  printf("%d\n", sizeof(&a + 1));
  printf("%d\n", sizeof(&a[0]));
  printf("%d\n", sizeof(&a[0] + 1));
答案是
1.  16
  4或者8
  4
  4或者8
  4
2.  4或者8
  16
  4或者8
  4或者8
  4或者8
解析:
1.答案:16
知识点:
考查对于sizeof(数组名)的理解,
注意:数组名一般情况下代表数组首元素的地址,只有两种情况代表整个数组的地址:
(1).sizeof(数组名)
(2).&数组名
解析:
sizeof(数组名):求整个数组的大小(即所占字节数):4(数组元素个数)*4(int类型占4个字节的单位)=16
2.答案:4或者8:
注意:只有当sizeof(只有数组名这一个符号)时,sizeof(数组名)才代表整个求数组的大小
所以:此时a为数组首元素的地址,(a+0)为数组首元素的地址,而地址就是指针,就是4个字节或者8个字节
3.答案:4
此时:a为数组首元素的地址,*a为数组首元素,首元素为int类型,大小4个字节
4.答案:4或者8
与第二题如出一辙,只不过是代表数组第二个元素的地址
5.答案:4
a[1]代表数组第二个元素,为int类型,大小为4个字节
6.答案:4或者8
&a代表整个元素的地址,是地址,就是指针类型,就是4个或8个字节
7.答案:16
&a代表整个数组的地址,*&a等价于a,也就是说*&a就是a,所以等价于sizeof(a)也就是求整个数组的大小,也就是16个字节
8.答案:4或者8
&a+1,
&a+1,是地址,只要是地址大小就是4或者8个字节
补充:
其中&a的类型是int(*a)[4],也就是说&a的类型是一个数组指针,指向的数组的元素为int类型,数组元素的个数为4个,
所以:&a+1所"迈出的步长"为4个int类型,也就是说&a+1指向数组a末尾位置
9.答案:4或8
&a[0],是地址,所以大小为4或者8个字节
补充:
a[0]:数组首元素,&a[0]就是数组首元素的地址
10.答案:4或8
&a[0]+1,是地址,所以大小为4或者8个字节
补充:
&a[0]是数组首元素的地址,所以&a[0]+1就是数组第二个元素的地址
总结:
1.数组名一般情况下代表数组首元素的地址,只有两种情况代表整个数组的地址:
(1).sizeof(数组名)
(2).&数组名
2.sizeof(数组名):其中数组名代表整个数组的地址,那么为什么sizeof(数组名)不是计算地址的大小呢?
是sizeof这个操作符本身的特性,使得出现了这个特例
其实这个特例的出现才是sizeof用处最多的方面,
例如:在计算数组中所含元素个数时,我们就通常使用
int sz = sizeof(arr)/sizeof(arr[0]);来计算数组中所含元素个数
也就是说求一个类型所含字节大小才是sizeof设计的核心原因和用途,所以规定了sizeof(数组名)就是求整个数组的大小这么一个规定
补充:
&a是整个数组的地址,不过具体值还是数组首元素的地址,
只不过这个指针类型和a这个指针类型不同,前者是int(*)[4]类型,后者是int*类型

1.2.sizeof和字符数组

//字符数组
  char arr[] = { 'a','b','c','d','e','f' };
  //1.
  printf("%d\n", sizeof(arr));
  printf("%d\n", sizeof(arr + 0));
  printf("%d\n", sizeof(*arr));
  printf("%d\n", sizeof(arr[1]));
  //2.
  printf("%d\n", sizeof(&arr));
  printf("%d\n", sizeof(&arr + 1));
  printf("%d\n", sizeof(&arr[0] + 1));
答案:
1.  6
  4或8
  1
  1
2.  4或8
  4或8
  4或8
解析:
1.答案:6
sizeof(数组名):求整个数组的大小
arr一共只有6个元素,每个元素为char类型,所以计算结果为6*1=6
注意:
将arr与char arr[]="abcdef"相区分开来,
其中前者在数组末尾没有'\0',而后者有'\0'
补充:
1.使用sizeof 计算字符串大小时'\0'也会包含在所计算的字符串大小之内
2.strlen计算字符串长度时,遇到'\0'后才会停止,求得的长度不包含'\0'
---------------------------------------------------------------
2.答案:4或8
arr+0为数组首元素的地址,是地址,大小就为4或者8个字节
3.答案:1
arr是数组首元素的地址,*arr就是数组首元素,数组首元素为char类型,大小为1个字节
4.答案:1
arr[1]就是数组第二个元素,为char类型,大小为1个字节
5.答案:4或8
&arr:是整个数组的地址,是地址,大小就为4或者8个字节
6.答案:4或8
&arr+1:是整个数组末尾的地址,是地址,大小就为4或者8个字节
7.答案:4或者8
&arr[0]+1:是数组第二个元素的地址,是地址,大小就为4或者8个字节
其中第6,7题可见1.2sizeof和整型数组中的第8,10题的补充
> 补充:
> size_t strlen ( const char * str );
> 也就是说strlen的参数是一个char*类型的指针,
> 所以在计算一个字符串的长度的时候传入一个地址,
> strlen函数通过传入的地址开始依次往下开始读取地址所指向的内容
> 一直读到'\0',返回在读到'\0'之前的元素的个数
因为参数为char*类型,所以如果传入了其他类型的指针变量,均转化为char*类型,也就是限制了"指针变量的步长"为1

1.3 字符数组和strlen

char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", strlen(arr));
  printf("%d\n", strlen(arr + 0));
  printf("%d\n", strlen(*arr));
  printf("%d\n", strlen(arr[1]));
  printf("%d\n", strlen(&arr));
  printf("%d\n", strlen(&arr + 1));
  printf("%d\n", strlen(&arr[0] + 1));
在这里为了表示方便,我们假定随机值为x
答案是:
  x
  x
  非法访问
  非法访问
  x
  x-6
  x-1
解析:
1.答案:x.
上面提到过strlen只有读到'\0'时才会停止,而这种字符数组的末尾是不会自动追加'\0'的
所以strlen读到了该字符串末尾后发现没有'\0',所以继续向后读取知道读到了'\0',所以计算出的'\0'之前的字符个数为随机值x
2.答案:x.
传入的是arr+0,也就等同于传入arr,计算出从数组首元素开始往后读取到'\0'之前的字符个数,也就完全等同于第一题
3.答案:非法访问
前提知识:前面提到过:
1.arr代表数组首元素地址,*arr代表数组首元素
所以传入的是字符'a'
2.strlen的参数类型是char*,也就是需要传入一个地址,我们将字符'a'传入后,字符'a'在内存中实际存储的是字符'a'所对应得ascii码值,即97
题解:
所以strlen函数就认为97是个地址,于是访问97所对应的地址空间,
而97所对应的内存空间里面存放的是什么,是不清楚的,
有可能存放的是很重要的数据,所以不能被任意访问,
所以编译器会报错,因为操作系统为了保护电脑,不允许编译器访问这个地址空间,所以为非法访问
4.答案:非法访问
与第3题如出一辙,只不过传入的是arr[1],也就是数组第二个元素,即字符'b',所对应的ascii码值为98
5.答案:x
前置条件:前面补充过,详见1.1末尾补充内容
&arr是整个数组的地址,不过具体值还是数组首元素的地址,是不过这个指针类型和arr这个指针类型不同,前者是char(*)[6]类型,后者是char*类型
题解:
所以传入strlen这个函数的参数与传入arr这个参数所对应的值一样,
又因为前面提到过strlen的参数类型是char*,所以&arr被转化为char*类型,
限制了"指针变量的步长"为1
所以在strlen这个函数中传入&数组名和数组名和数组名+0,
三者本质上完全相同,没有差别
6.答案:随机值x-6
前面补充过,&arr的类型是char(*)[6]类型,
所以该指针变量的"步长"为6,所以&arr+1指向了数组末尾位置,
所以它是从f后面的地址开始计算,所以为x-6
7.答案:x-1
&arr[0]+1:就是数组第二个元素,所以strlen函数从数组第二个元素开始计算长度,所以少计算了字符'a'

1.4 字符串(另一类型的字符数组)与sizeof

char arr[] = "abcdef";
  printf("%d\n", sizeof(arr));
  printf("%d\n", sizeof(arr + 0));
  printf("%d\n", sizeof(*arr));
  printf("%d\n", sizeof(arr[1]));
  printf("%d\n", sizeof(&arr));
  printf("%d\n", sizeof(&arr + 1));
  printf("%d\n", sizeof(&arr[0] + 1));
答案:
注意:
这里的字符数组末尾有'\0',是C语言规定,编译器自动追加的,只不过没有显示出来而已
1.  7
  4或8
  1
  1
  4或8
  4或8
  4或8
解析
1.答案:7
前面提到过,sizeof(数组名):计算整个数组的大小,包括'\0'\
2.答案:4或8
arr+0是数组首元素的地址,是地址,大小就为4或8个字节
3.答案:1
*arr:数组首元素,为char类型,大小为1
4.答案:1
arr[1]:数组第二个元素,为char类型,大小为1
5.答案:4或8
&arr:整个数组的地址,是地址,大小就为4或8个字节
6.答案:4或8
&arr+1:整个数组末尾的地址,是地址,大小就为4或8个字节
7.答案:4或8
&arr[0]+1:数组第二个元素的地址,是地址,大小就为4或8个字节

1.5 字符串(另一类型的字符数组)与strlen

char arr[] = "abcdef";
  printf("%d\n", strlen(arr));
  printf("%d\n", strlen(arr + 0));
  printf("%d\n", strlen(*arr));
  printf("%d\n", strlen(arr[1]));
  printf("%d\n", strlen(&arr));
  printf("%d\n", strlen(&arr + 1));
  printf("%d\n", strlen(&arr[0] + 1));
这里为了表示方便:随机值为x
答案:
  6
  6
  非法访问
  非法访问
  6
  x
  5
解析:
1.答案:6
前面提到过:strlen函数求'\0'之前的字符个数,这里为6个
2.答案:6
前面提到过,对于strlen函数而言,传入arr,arr+0,&arr,本质均相同,所以同第一题
3.答案:非法访问,同1.3的第三题
4.答案:非法访问,同1.3的第四题
5.答案:6,同第一题
6.答案:随机值x,
因为&arr+1是数组末尾的地址,也就是在这个字符串末尾的'\0'之后那个元素的首地址
7.答案:5
&arr[0]+1:数组第二个元素的地址,所以为6-1=5

1.5 指针指向的字符串与sizeof

补充:对于一个数组而言,以arr数组为例
int arr[]={1,2,3,4,5,6,7,8,9};
int i 代表从0到8的数字
arr[i] 就等价于 *(arr+i)
而且,同理,对于而言:
char* p = "abcdef";
p[i] 就等价于 *(p+i)
char* p = "abcdef";
  printf("%d\n", sizeof(p));
  printf("%d\n", sizeof(p + 1));
  printf("%d\n", sizeof(*p));
  printf("%d\n", sizeof(p[0]));
  printf("%d\n", sizeof(&p));
  printf("%d\n", sizeof(&p + 1));
  printf("%d\n", sizeof(&p[0] + 1));
答案:
  4或者8
  4或者8
  1
  1
  4或者8
  4或者8
  4或者8
解析:
1.答案:4或者8
p就是数组首元素的地址,是地址,大小就为4或者8个字节
2.答案:4或者8
p+1是数组第二个元素的地址,是地址,大小就为4或者8个字节
3.答案:1
P是数组首元素的地址,*p就是数组的首元素,也就是字符'a',char类型,大小为1个字节
4.答案:1
前面补充过:p[i] 就等价于 *(p+i)
所以p[0]就是*(p+0),也就是*p,也就等同于第3题
5.答案:4或8
&p是指向指针p的二级指针,指针就是地址,大小就为4或者8个字节
6.答案:4或8
&p+1是指向指针p之后的空间的二级指针,指针就是地址,大小就为4或者8个字节.
7.答案:4或8
&p[0]+1是数组第二个元素的地址,是地址,大小就为4或者8个字节

我们可以通过这张图来仔细看一下:第5,6题

看红色箭头,也就是说,&p是指向p的二级指针,&p+1是指向p末尾的二级指针,但它们都是指针,是指针,大小就为4或8个字节

1.5 指针指向的字符串与strlen

char* p = "abcdef";
  printf("%d\n", strlen(p));
  printf("%d\n", strlen(p + 1));
  printf("%d\n", strlen(*p));
  printf("%d\n", strlen(p[0]));
  printf("%d\n", strlen(&p));
  printf("%d\n", strlen(&p + 1));
  printf("%d\n", strlen(&p[0] + 1));
答案是:
  6
  5
  非法访问
  非法访问
  x
  y
  5
解析:
1. 答案:6
p是字符数组的首元素地址,
而把p传给strlen函数,也就是把字符数组首元素地址传给strlen,
所以strlen函数可以从字符'a'开始向后读取字符,一直读到'\0',所以答案为6
2.答案:5
p是char*类型的指针,"步长"为1,所以p+1就是数组第二个元素的地址也就是字符'b'的地址,所以从字符'b'开始向后读取直到'\0'
3.答案:非法访问,同1.3的第三题
4.答案:非法访问,同1.3的第四题,只不过这里指向的还是第一个元素,因为走的步长为0
5.答案:随机值x
注意:请与1.3的第5题区分开来,在后面我们看一下"内存图"
6.答案:随机值y
在后面我们看一下"内存图"
7.答案:5
&p[0]+1,数组第二个元素的地址,同第二题

从这里我们可以看出&p指向的地方的元素是未知的,
所以strlen(&p)和strlen(&p+1)求出的分别是随机值x和随机值y,
分别对应蓝色箭头和紫色箭头,
其中随机值x和随机值y无必然联系,
也就是说如果p内存在'\0',则x和y无任何关系,
如果p内不存在'\0',则x和y满足:x=y+6
注意:
这里所说的'\0',
因为'\0'的ASCII码值为0,而字符在内存中是以ASCII码值的形式存在的,
所以说只要p内存在0即表示存在'\0'

2.二维数组

首先:我们先说一下两个很好的关于二维数组理解方法

1.二维数组是一维数组,只不过二维数组的元素是一维数组,而一维数组的元素是int/char/double…类型

2.在同类型的情况下,对指针解引用就是得到指针所指向的目标

//二维数组
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  printf("%d\n", sizeof(a[0][0]));
  printf("%d\n", sizeof(a[0]));
  printf("%d\n", sizeof(a[0] + 1));
  printf("%d\n", sizeof(*(a[0] + 1)));
  printf("%d\n", sizeof(a + 1));
  printf("%d\n", sizeof(*(a + 1)));
  printf("%d\n", sizeof(&a[0] + 1));
  printf("%d\n", sizeof(*(&a[0] + 1)));
  printf("%d\n", sizeof(*a));
  printf("%d\n", sizeof(a[3]));
答案:
  48
  4
  16
  4或8
  4
  4或8
  16
  4或8
  16
  16
  16
解析:
1.答案:48
a是整个二维数组的地址,sizeof(a)就是求整个二维数组的大小
3*4*4=48
2.答案:4
a[0][0]:就是二维数组第一行的第一个元素,是int类型,大小为4字节
3.答案:16
a[0]:就是二维数组首元素的地址,而二维数组的首元素是一个一维数组,
所以a[0]就是这个一维数组的地址,所以sizeof(a[0])就是求这个一维数组的大小,即16
4.答案:4或8
a[0]是第一个一维数组的首元素的地址,
a[0]+1就是该一维数组第二个元素的地址,
是地址,大小就是4或者8个字节
5.答案;4
*(a[0]+1)就是第一个一维数组的第二个元素,为int类型,大小为4个字节
6.答案:4或8
a是二维数组首元素的地址,
a+1就是二维数组第二个元素的地址,就是第二个一维数组的地址
是地址,大小就是4或者8个字节
7.答案;16
a+1是第二个一维数组的地址,*(a+1)就是第二个一维数组,
sizeof(数组名)就是求整个数组的大小,
也就是说sizeof(*(a+1))就是求第二个一维数组的大小,也就是16
8.答案:4或者8
法一:内存理解:
本题后面给大家画了"内存图",其中&a[0]+1和a[0]+1所指向空间的起止位置都已经给大家标出来了,所以每个均有两个箭头,
&a[0]+1是指向了第二个一维数组的数组指针,其"步长"为4*4=16byte
法二:概念理解
前面说过:a[0]等价于*(a+0),所以&a[0]+1就等价于&*(a+0)+1,
也就等价于(a+0)+1 ,也就等价于a+1
其实&a[0]+1  等价于a+1  无论a是一维数组还是二维数组!!!!!!!!!!
总之,&a[0]+1是指针,指针式地址,地址就是4或8个字节
9.答案:16
由第八题概念法得:其实*(&a[0]+1)就是*(a+1),也就是a[1]
10.答案:16
其实*a就是*(a+0)就是a[0]
11.答案:16
a[i]是第i个一维数组的地址,sizeof(a[i])就是求第i个一维数组的大小,即16
注意:尽管a[3]并不存在(因为a是三行四列的二维数组,没有第四行),
但是sizeof(表达式),其中表达式并不参与运算,
也就是说表达式只负责告诉sizeof:(我是什么类型的数据,你只需要根据我的数据类型来计算字节数即可)
我们可以看下面的一个代码,它能够帮助你有更深刻的理解

第8题的图片

第11题的补充

void exam009()
{
  //sizeof()内部的表达式是不算的
  short s = 5;
  int a = 4;
  printf("%d\n", sizeof(s = a + 6));//2
  //说明了:这里不会因为a+6是int类型就将short改为int类型!!
  printf("%d\n", s);//5,也就说明了:并未进行sizeof()内部的表达式
}
总结:
1.sizeof()内部的表达式是不算的,
也就是说表达式只负责告诉sizeof:(我是什么类型的数据,你只需要根据我的数据类型来计算字节数即可)
2.其实&a[0]+1  等价于a+1  无论a是一维数组还是二维数组!!!!!!!!!!
3.重申一遍
> 1.二维数组是一维数组,只不过二维数组的元素是一维数组,而一维数组的元素是int/char/double.......类型
> 2.在同类型的情况下,对指针解引用就是得到指针所指向的目标

2.指针经典笔试题详解

1.

考点:

1.内存图

2.指针类型决定步长

void exam010()
{
  int a[5] = { 1, 2, 3, 4, 5 };
  int* ptr = (int*)(&a + 1);
  printf("%d,%d", *(a + 1), *(ptr - 1));
}

答案是:2,5
> &a是数组指针类型,即int(*)[5],步长为4*5=20byte,
> 所以&a+1就指向了数组末尾的位置,
> 而强制类型转换为int*类型后,步长变为4,所以指向了最后一个元素的起始位置,所以*(ptr-1)就是最后一个元素

2.

考点:

指针类型决定了指针加减运算的步长

struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节,%p是打印地址
void exam011()
{
  printf("%p\n", p + 0x1);
  printf("%p\n", (unsigned long)p + 0x1);
  printf("%p\n", (unsigned int*)p + 0x1);
}
答案是:
0x100014
0x100001
0x100004
第一行:p是struct Test*类型的指针,又因为Test结构体的大小是20个字节,
所以步长为20,转为16进制是14
第二行:p强制类型转换为(unsigned long)类型,
unsigned long就是整型,整型加1就相当于1+1,所以答案就是0x100001
第三行:p强制类型转换为(unsigned int*)类型,步长为4,所以加4

3.

考点:

指针类型决定了指针的加减整数运算的步长

大小端存也要大小端取(具体大小端的知识可以看我的另一篇博客,里面深度剖析了数据在内存中的存储方式,当然也包括了非常详细的大小端问题的说明

https://blog.csdn.net/Wzs040810/article/details/130900893?spm=1001.2014.3001.5501

void exam012()
{
  int a[4] = { 1, 2, 3, 4 };
  int* ptr1 = (int*)(&a + 1);
  int* ptr2 = (int*)((int)a + 1);
  printf("%x,%x", ptr1[-1], *ptr2);
}

从中我们可以看出ptr2指向的数据取出来后是02 00 00 00,
所以将其转为16进制就是最终答案,
因为int* ptr2 = (int*)((int)a + 1)中我们先将a强制类型转换为了int类型,
所以加1操作就是将地址加一,也就是将地址加一个字节,
而int类型占4个字节,所以前移四分之一,指向了图中所示位置.

4.

考点:

逗号表达式

二维数组与指针

void exam013()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  int* p;
  p = a[0];
  printf("%d", p[0]);
}
答案:1
注意:这里的二维数组不是
0 1
2 3
4 5
而是
1 3
5 0
0 0
因为逗号表达式整体的最终取值为逗号表达式的最后一项,不过每个表达式都会执行.
例如
int main()
{
  int b = 9;
  int a = (0, b = 20, 6 - 3);
  printf("%d %d", a, b);
  return 0;
}
//最终a的值为3
//b的值为20
而p就是第一个一维数组,p[0]就是第一个一维数组的第一个元素,也就是1

5.

考点:

内存图

指针的类型决定加减运算的步长

void exam014()
{
  int a[5][5];
  int(*p)[4];
  p = a;
  printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
}

答案:FFFFFFFFFFFFFFFC,-4
其中FFFFFFFFFFFFFFFC是-4的补码的16进制表示形式
解析:
p[4][2]  == *(*(p+4)+2)
由图可以看出具体的过程,
p=a这一句的含义是:
a是二维数组首元素的地址,也就是第一个一维数组的地址,
也就是说a是一个数组指针,其类型为int(*)[5],
而p的类型是int(*)[4],尽管二者类型不同,但是a最终还是将第一个一维数组的地址传给了p
而p的类型不变,a的类型不变
p的步长为4*4=16byte
a的步长为5*4=20byte,

6.

考点:

二维数组

内存图

void exam015()
{
  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int* ptr1 = (int*)(&aa + 1);
  int* ptr2 = (int*)(*(aa + 1));
  printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
}

答案是:10,5
注意:1.*(aa+1)等价于aa[1]
&aa是整个二维数组的地址,所以&aa+1后就指向了整个二维数组的末尾
2.定义ptr1和ptr2之前已经进行了强制类型转换,
将&aa+1和*(&aa+1)均转换为int*类型了,
所以后来进行指针的加减运算时步长为4byte

7.

考点:

内存图

二级指针

指针数组

void exam016()
{
  char* a[] = { "work","at","alibaba" };
  char** pa = a;
  pa++;
  printf("%s\n", *pa);
}

答案是:at,从图中就可以看出来,注意:printf("%s")打印时,
传入字符串首元素的地址即可,下面这一题就会用到这个知识点

8.

考点

内存图

多级指针

void exam017()
{
  char* c[] = { "ENTER","NEW","POINT","FIRST" };
  char** cp[] = { c + 3,c + 2,c + 1,c };
  char*** cpp = cp;
  printf("%s\n", **++cpp);
  printf("%s\n", *-- * ++cpp + 3);
  printf("%s\n", *cpp[-2] + 3);
  printf("%s\n", cpp[-1][-1] + 1);
}

注意:所有的最外面的加减的常数在最后一步进行!!!!!!!!
可以简化代码
printf("%s\n", *cpp[-2] + 3);//**(cpp-2)+3
printf("%s\n", cpp[-1][-1] + 1);//*(*(cpp-1)-1)+1

c 以上就是征服C语言指针系列(1),希望能对大家有所帮助

相关文章
|
1月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
49 0
|
1月前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
18 2
|
1月前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
1月前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
1月前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
|
编译器 C语言
【c语言】指针就该这么学(2)
本文详细介绍了指针与数组的关系,包括指针访问数组、一维数组传参、二级指针、指针数组和数组指针等内容。通过具体代码示例,解释了数组名作为首元素地址的用法,以及如何使用指针数组模拟二维数组和传递二维数组。文章还强调了数组指针与指针数组的区别,并通过调试窗口展示了不同类型指针的差异。最后,总结了指针在数组操作中的重要性和应用场景。
19 0
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
35 3
|
14天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
29 6
|
1月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
39 10