[CSDN转载]致C语言初学者—指针注意项
在论坛里经常见到一些新人对指针提出一些问题,作为一个经历过许多错误后的新手,我想把自己的经历说出来,避免让后来人继续这样的错误。
在讲解指针之前,需要理解一下内存空间。内存是随机存取器,计算机上电后便利用内存进行运转。其有一定的容量,为了标识每个存储单元的位置,我们为内存设置了内存地址。内存的具体组织结构可以参考计算机组成原理。
指针是一种指向某种类型的特殊的型别。一般用*定义。如int *p,这样就定义了一个指向int类型的指针。指针用于指向某块内存空间,该内存空间里面存放了其所指向的内存地址。所以,在使用指针之前,必须明白这指针指向了什么内存空间,给指针赋值可以使用取地址符(&),如p = &a;每次需要访问指针所指向的内容时,便使用解引用符号*进行访问。如:printf(“%d”,*p);
上面简单介绍了下指针的定义,赋值等操作。下面介绍下一些新手容易迷糊的地方吧。
1. char *str1=”abcd”; char str2[]=”abcd”;的区别
C标准没有规定这两种定义字符串的方式的差别。但是,指针类型的字符串一般不允许修改。如:str1[0]=’c’;这样的语句会导致运行时错误。错误类型:不允许写入什么的。据说,在某些编译器中可以设置成可以修改的。
2.指针/数组作为参数进行传递
在C语言中,参数是使用值传递的。
int func(int a );当调用者调用该函数的时候将传递一个值给a,这个a只是你传递进去的参数的一个副本。而数组传递的时候,会退化为指针,其将数组的首地址复制给形参。看下面的一个例子。
1
2
3
4
5
6
7
8
9
10
11
|
void fun( char str[]) { printf ( "After transform:%d\n" , sizeof (str)); } int main(){ char strs[]= "abcdefg" ; printf ( "Before transform:%d\n" , sizeof (strs)); fun(strs); return 0; } |
输出:
Before transform:8
After transform:4
在传递之前,我们可以获得数组所占用的内存空间的大小;而传递后,我们只能获得一个指针的大小了。
许多初学C指针的同学想在函数内部修改作为参数传递进来的指针的值。看以下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
typedef struct Link_Node{ int Elem; struct Link_Node *next; }LinkNode,*PLinkList; void CreateList(LinkNode *header) { int i=0; header = (LinkNode *) malloc ( sizeof (LinkNode)); header->Elem = 10; header->next = NULL; } int main() { PLinkList head=NULL; CreateList(head); if (head!=NULL) printf ( "%d\n" ,head->Elem); free (head); return 0; } |
许多人疑惑为什么没有输出呢?请各位谨记:C语言使用值传递进行参数传递。这就是问题所在。在传递指针的时候,调用者传递了原指针所指向的内存地址给形参。也就是说,在传递参数的时候,系统定义了另外一个指针,也就是我们在此定义的header指针。我们把原指针的值传递给了header指针。所以header指向了本例中的null。然后我们去修改header所指向的值。当函数结束后,这个指针的生命周期也结束了。所以对main函数中的head没有任何修改。
下面我们再看一例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
void Trans( int * Arr, int nLength) { for ( int i=0;i<nLength;i++) Arr[i] += i+20; } int main() { int nArr[5]={0}; int i; printf ( "Before:\n" ); for (i=0;i<5;i++) printf ( "%d " ,nArr[i]); Trans(nArr,5); printf ( "\nAfter\n" ); for (i=0;i<5;i++) printf ( "%d " ,nArr[i]); return 0; } |
输出:
Before:
0 0 0 0 0
After
20 21 22 23 24
我们发现我们在函数里面修改了数组的值。结合上面的例子,有新同学开始迷糊了。为什么上面的例子不能修改,为什么下面的例子就能修改了?由于指针存储的是地址值,所以初学比较迷惑。函数传递的是指针变量的值---即该指针所指向的变量的地址。所以,我们可以修改其指向的变量的值,而不能修改指针本身的内容了。为了能够修改指针本身的内容,我们需要传递指针本身的地址。所以在上面那例中,需要传递head指针本身的地址。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void CreateList(LinkNode **header) { int i=0; (*header) = (LinkNode *) malloc ( sizeof (LinkNode)); (*header)->Elem = 10; (*header)->next = NULL; } int main() { PLinkList head=NULL; CreateList(&head); if (head!=NULL) printf ( "%d\n" ,head->Elem); free (head); return 0; } |
动态开辟数组
指针可以用来分配内存,作为数组来使用。
开辟一维数组:int *pArr = (int*)malloc(10*sizeof(int));释放空间:free(pArr);
开辟二维或者多维数组需要分级申请内存:int **pArr;
pArr = (int **)malloc(sizeof(int*)*3);
for(i=0;i<3;i++)
*(pArr+i) = (int *)malloc(sizeof(int)*5);
当然释放空间的时候也需要分级释放咯; for(i=0;i<3;i++) free(*(pArr+i));
函数指针和指针函数
在计算机内存中,所有的数据都有唯一的地址,当然可运行的程序也是有地址的。函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。定义形式为:函数类型 (*指针变量名)(形参列表);如:int (*func)(char a[],int nlength)。不过,我们经常会遇到这样的定义方式:typedef int (*func)(char a[],int nlength);其实使用typedef主要是为了定义函数指针方便,不需要每次都敲那么的代码。(其实懒也是技术驱动的一种动力啊!)我这里就简单的介绍点东西。在搞算法的时候,函数指针大有用处,可以用它实现很多beautiful算法。比如那些自动机等等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
typedef int (*func)( char a[], int nLength); int total( char a[], int nLength) { int nTotal = 0; for ( int i=0;i<nLength;++i) nTotal += a[i]; return nTotal; } int main() { char a[]= "abcde" ; int nLength = strlen (a); func fp; fp = total; printf ( "%d\n" ,fp(a,nLength)); return 0; } |
一个函数不仅可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。在这里,我就不多说什么了。仅提醒各位初学者一下:返回的地址必须不能是该函数的栈空间里的。那样待函数返回后,获得到的地址将是一个错误的地址。
以上代码在XP+VS2008下实验通过
[CSDN转载]致C语言初学者—指针注意项的更多相关文章
- C语言函数指针基础
本文写的非常详细,因为我想为初学者建立一个意识模型,来帮助他们理解函数指针的语法和基础.如果你不讨厌事无巨细,请尽情阅读吧. 函数指针虽然在语法上让人有些迷惑,但不失为一种有趣而强大的工具.本文将从C ...
- C语言中指针占据内存空间问题
以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...
- C语言中指针和数组
C语言数组与指针的那些事儿 在C语言中,要说到哪一部分最难搞,首当其冲就是指针,指针永远是个让人又爱又恨的东西,用好了可以事半功倍,用不好,就会有改不完的bug和通不完的宵.但是程序员一般都有一种迷之 ...
- C语言初学者代码中的常见错误与瑕疵(23)
见:C语言初学者代码中的常见错误与瑕疵(23)
- 浅谈c语言的指针
对于非计算机专业的同学,c语言的指针往往就是老师的一句“指针不考“就带过了.c语言的指针号称是c语言的灵魂,是c语言中最精妙的部分. 指针本质上也是变量,也就是一段内存,只是他的特殊之处是他存储的数据 ...
- 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)
问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...
- C语言初学者代码中的常见错误与瑕疵(5)
问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...
- C#委托与C语言函数指针及函数指针数组
C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用 ...
- C语言初学者代码中的常见错误与瑕疵(19)
见:C语言初学者代码中的常见错误与瑕疵(19)
随机推荐
- Flash Builder 调试器无法连接到正在运行的应用程序(57%)
Flash Builder 调试器无法连接到正在运行的应用程序(57%),可能原因: 1,flashplayer不是debug版. 2,调试器(用debug版flashplayer随便 ...
- X-Forwarded-For (IIS日志记录用户真实IP)
参考:http://www.jbxue.com/article/7521.html 当IIS放在反向代理后面时,日志中的客户端ip是反向代理服务器的ip,不是用户的真实IP地址. 本文为大家介绍使用X ...
- 现在还需要测试或者QA人员吗?
Facebook没有专门的测试人员,都是开发自己测:微软裁掉了测试部门,改由开发测:google有少量的测试人员,主要做测试自动化框架开发或者性能.安全等专项测试,测试用例还是开发人员自己设计自己跑( ...
- python 生成 xml文件 属性的顺序问题
需求很奇葩. 文档示例 <ITEM key="username" eng="User Name" chn="用户名" val=&quo ...
- poj -- 1042 Gone Fishing(枚举+贪心)
题意: John现有h个小时的空闲时间,他打算去钓鱼.钓鱼的地方共有n个湖,所有的湖沿着一条单向路顺序排列(John每在一个湖钓完鱼后,他只能走到下一个湖继续钓),John必须从1号湖开始钓起,但是他 ...
- Android长时间后台运行Service
项目需要在后台获取GPS经纬度.当用户对手机有一段时间没有操作后,屏幕(Screen)将从高亮(Bright)变为暗淡(Dim),如果再过段时间没操作, 屏幕(Screen)将又由暗淡(Di ...
- 我眼中的项目leader
个人觉得项目leader应该具备一下基础: 1.技术能力 2.领导能力 3.过滤产品不合理需求能力 4.项目周期把控能力
- 20151214study
An important quality of steel is its strength. (1)钢铁的最重要品质是其强度.She made a quick decision.她做了一个很快的决定. ...
- Mac Virtual System On Windows
Win8.1下利用虚拟机安装苹果操作系统 所需文件: 虚拟机:VMware -10.0.1,这个就是中文版的了. 虚拟机密钥生成器:vm10keygen,要对应虚拟机的版本. 虚拟机的插件: unlo ...
- js阻止提交表单(post)
在注册页面,我们经常要用到页面验证,验证到不符合要求的数据就阻止提交到服务器,如下 <script type="text/javascript"> function C ...