隔了好一段时间没有更新新手编程系列,实在开发任务很忙。我最近在开发的就是水印王,安卓和ios版本都在开发,其实商业软件用到的技术,很多都是C编写的。比如安卓你起初可以用Java来编写,用Eclipse或者Android Studio这样的开发工具,手机上可以用AIDE,但是如果你做高难度的项目,比如图片、图像处理、视频编码解码等,那么就需要用到C了。C是高手必须要学会的,水印王给视频加水印,给图片加水印都用到了C。
其实技术的海洋里,你很难成为一个大神,因为真的太难了。很多初学者问我怎么成为一名黑客,其实我可以告诉你:你百分之九十九不可能成为黑客。因为要成为一名黑客,真的需要学习太多东西,需要炼狱般的磨练。就只是计算机语言,都有几千种,各种操作系统,又是极其复杂,没有专业的理论基础,根本不可能成为我认为是黑客的那种黑客。当然了,简单的*号盗**,或者网站SQL注入或者搞肉鸡挂木马这种,我不认为这是黑客,因为这东西几分钟就学会。要成为大神, C是绕不过去的坎,学不会,永远无法成为大神。
如果你狠下心把我以前写的文章都认真看了,都操作了,都上网学习了。我想你现在可以来学习学习指针了,因为如果你没有对C语言有足够的认识,你很难了解指针是什么东西。
在以前的文章中,我写的一些程序中都使用了指针,因为实在方便。但是我没有说明那个东西是什么,怎么用。今天这篇就是讲讲指针。
而现在我们就要学习C语言里面最难的部分:指针。
最简单的程序:
#include<stdio.h>
int main
{
char *helloWorld="hello world";
printf("==print:%s",helloWorld);
return 0;
}
这里就有指针了。helloWorld是char类型的指针变量,指针前面都有一个*,在电脑上就是按住Shift+8。
上面的代码运行后,结果是什么?
结果是:==print:hello world
我们知道%s就是打印字符串的,字符串是什么东西?如果你不懂,可以翻看前面一章。helloWorld这个指针变量指向了字符串"hello world"的存储地址,这句话很重要了。
于是新手同学就要问了,指针是什么东西?
指针就是指向某个存储地址。
很抽象的一个概念,我们用比较形象的方式解释这个概念,好让大家理解指针。
逛超市:
我们都逛过超市,在进入超市之前需要把自己的东西放到存储柜里面去,超市不允许你带一些零食等东西进去。我们按一下存储柜,一张纸条就出来了,同时一个空的存储小柜的门也自动打开,你把东西放进去。你如果留心观察,这个小柜上有可能有一个编号,我们假设是A16,就是A组柜子第16个。然后你关上门,同时你把小纸条(上面有二维码)放入自己口袋后,就进超市购物去了。

当你购物回来出了超市门口,你到存储柜去取自己的东西,怎么取?把有二维码的下纸条贴近识别机,听到“滴”的一下,A16这个小就自动打开了。

指针是什么?指针就是这个小纸条。A16这个编号就是存储地址,在计算机里是一个数字。你放进去的东西,就是计算机里存储在某个内存空间的数据。
好了,我们这知道了,原来地址和指针是这么一个关系。指针指向了某个地址,它不代表是内存空间里面的数据。如果你还不懂,多去图书馆找书,你就懂了。
char *helloWorld="hello world"。
char表示这个存储空间放的是char类型的数据,而*helloWorld表明helloWorld是一个指向char类型的指针变量。helloWorld指向了字符串"hello world"的存储的首地址。对!指针指向的是首地址,因为字符串"hello world"在计算机里是连着一片地址存储的,就是连续的地址才能存好几个字母。
如果我们想知道helloWorld这个指针所指向的地址是多少,怎么办?代码可以修改如下:
printf("==print:%d",helloWorld);
你打印出来,就是一个整数,其实就是修改了打印的内容而已。
既然我上面已经说了,指针是指向某个地址,并且是首地址,那么是不是知道了首地址,我就可以访问在这个首地址后面的数据?答案是可以的。这就是指针非常牛的地方,很多外挂软件都使用C语言写,原因是可以操作内存,修改数据。比如我们知道了数据存储的首地址,那么就很容易知道它后面的内容。我们打印一下helloWorld保存的首地址对应的字符,代码如下:
printf("==print:%c",*helloWorld);
打印的结果是:==print:h。
那我想打印出第二个字符e怎么办?指针的强悍之处就是这里了。代码稍微修改一下,用下面一行即可:
printf("==print:%c",*(helloWorld+1));
上面的内容,对你理解指针这个抽象的概念很有帮助。因为只有知道了原理,才能走更远。除了字符串指针变量,还有其他整型,浮点型等等。
int a,
int *p;
p=&a;
上面就是声明一个整型变量a,然后申明一个指向整型的指针变量p,第三行p指向a的地址。&表示地址。
好了,指针的用处太多,我们举一个例子,也是很经典的交换数据函数。
我在C4Droid已经运行好,代码如下:
#include<stdio.h>
void swap(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void swapit(int *a,int *b)
temp=*a;
*a=*b;
*b=temp;
}
int main{
int a=5,b=10;
swap(a,b);
printf("1.a=%d,b=%d\n",a,b);
swapit(&a,&b);
printf("2.a=%d,b=%d",a,b);

两个函数,第一个函数swap企图换a与b的值,但是没有成功。我们仔细分析下这个函数:
输入进来a和b,它们其实是寄存器上的数据,并不是地址,a等于5,b等于10,所以这函数运行到最后,虽然在swap函数里面,a=10了,b也等于5了,但是运行完这个函数后a和b的值并没有改变。
这里有个非常容易让新手头疼的内容,就是作用域的问题。在main函数中,我们通过swap(a,b)调用swap函数,而swap的函数体输入的参数是swap(int a,int b)。以为main函数的a和b就等于swap(int a,int b)的a和b。其实不对,swap(int a,int b)可以改改,其实如下的话更好理解了。
void swap(int aa,int bb)
temp=aa;
aa=bb;
bb=temp;
}
它跟上面的swap(int a,int b)是一样的。函数的输入参数,你可以随便取名字,只要符合c语言规则。
我们用void swap(int aa,int bb)来理解,main函数中调用swap(a,b),其实首先经过把a赋值给aa,也就是swap(a,b)其实是先来一个 swap(int aa=a,int bb=b)。这样aa的值等于a,bb的值等于b,这个函数传的就是一个值而已。跟main函数中的a,b再没有任何关系。所以main函数的a,b不会有任何改变。
而下面这个函数,就不一样了。
它在main函数是这么调用的swapit(&a,&b),看看有什么不一样?文章的开头部分我说&表示地址,所以这里传的就是a和b的地址了。因为swapit的传入参数就是指向某个地址的指针。很多编程高手掉坑里,原因是不理解int *a 和*a的区别。int *a三个抱团在一起,前面那个表示类型,它们三在一起的时候是申明变量,而*a是取值,把a指向的地址取值。
那么函数体我们看看:
int temp; 这里先声明一个整型变量。
temp=*a; 把指针a指向的值赋值给temp,temp现在就等于5了。
*a=*b; 指针a所指向的地址的数据(值)被赋值为指针b所指向的地址的值,就是10。那么现在a所指向的地址的值就是10了,不再是5了。
*b=temp;这个就是把b所指向的地址的值赋值为temp,temp现在是5,所以*b=5,即使b所指向的地址存储的值就是5。
看到了,swapit其实针对的操作是地址以及地址上对应的数值。
如果你看不懂,没关系,慢慢琢磨吧。指针是非常难的,这个还是比较简单的了。有更难的,比如 char **p,这个是表示什么呢?
c语言最难的就是指针,还有一些书专门讨论指针的,就指针能写出一本书来。所以我这篇虽然算入门,不过也是指针的精髓了。
上面的代码运行结果:

作者:谋哥,水印王创始人。略懂技术,产品,运营,公号vjiazhi,有空就写各种原创文章,欢迎大家关注相互学习。