C与指针——指针(一)

指针基础简述

6.1内存和地址

单个字节包含了存储一个字符所需要的位数,每个字节包含8位。
存储无符号值的范围:0 ~ 28-1(255)
存储有符号值的范围:-27(-128) ~ 27-1(127)

由四个字节存储的字,每个字包含4*8=32位
存储无符号值的范围:0 ~ 232-1(4294967295)
存储有符号值的范围:-231(-2147483648) ~ 231-1(2147483648)

高级语言通过名字而非地址来访问内存的位置;硬件仍然通过地址访问内存位置。

6.2 值、类型、指针变量与间接访问

不能简单地通过检查一个值的位来判断它的类型。
变量被声明为指针并不会改变这些表达式的求值方式,一个变量的值就是分配给这个变量的内存位置所存储的数值。
通过一个指针访问它所指向的地址的过程称为间接访问解引用指针(*)
间接访问操作只能作用于指针类型表达式。

因为对一个NULL指针使用解引用操作是非法的。因此在对指针进行解引用之前,首先确保它并非NULL指针。
为测试一个指针变量是否为NULL,可将它与零值进行比较。

间接访问操作符所需要的操作数是右值,但此操作符所产生的结果是左值。
指针变量可因其是变量而作为左值使用。对指针变量进行间接访问表示我们应该访问指针所指向的位置。

int a;
int *d=&a;//定义指针变量d并指向a

*d=10-*d;
//右侧对d所指向位置所存储的值(a的值)进行操作再将其赋给左侧d所指向的位置
d=10-*d;
//非法,表示把一个整型数量(10-d*)存储于一个指针变量(d)中。
    
*&a=25;//把值25赋值给变量a。&操作符产生变量a的地址(指针常量)
//*操作符访问其操作数(a的地址)所表示的地址
 
 p=&a;//把a的地址赋给指针变量p,指针变量p的值是变量a的地址,p指向a
*p=1;//将整数1赋给指针变量p当前所指向的变量,即a=1;

&—— 取地址运算符。&a是变量a的地址。
*—— 指针运算符(间接访问运算符),*p代表指针变量p指向的对象。

若偶尔需通过地址访问内存中某个的特定位置时(即用整型字面值的形式,左值为指针常量,右值为整型常量),可通过强制类型转换转换成适当的类型。

6.3 指针表达式

前缀自增++操作符优先级高于*,结合性都是从右向左。

表达式*cp++可作为左值和右值存在。(先执行++)
1.++操作符产生cp的一份拷贝
2.然后++操作符增加cp的值
3.最后,在cp的拷贝上执行间接访问操作。
表达式++*cp右值存在,左值非法。(先执行间接访问操作)
1.首先执行间接访问操作
2.cp所指向位置的值增加1
3.表达式的结果是这个增值后的值的一份拷贝
后缀自增(减)的优先级高于前缀自增(减)。
while((string=*strings++)!=NULL)
1.它把strings当前所指向的指针复制到变量string中
2.它增加strings的值,使它指向下一个值
3.它测试string是否为NULL

插播assert知识点:

断言assert是一个宏,该宏在<assert.h>中,,当使用assert时候,给他个参数,即一个判读为真的表达式。预处理器产生测试该断言的代码,如果断言不为真,则发出一个错误信息告诉断言是什么以及它失败一会,程序会终止。
我们一般可以用在判断某件操作是否成功上。
程序一般分为Debug版本和Release版本,Debug版本用于内部调试,Release版本发行给用户使用。
断言assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况。
assert不是一个仓促拼凑起来的宏,为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。所以assert不是函数,而是宏。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。
以下是使用断言的几个原则:
1)使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
2)使用断言对函数的参数进行确认。

在对指针执行间接访问前,指针必须进行初始化:使它指向现有的内存或给它分配动态内存。

编程练习

1.

请编写一个程序,它在一个字符串中进行搜索,查找所有在一个给定字符集合中出现的字符。这个函数的原型应该如下:

char *find_char(char const *source,char const *chars);

它的基本想法是查找source字符串中匹配chars字符串中任何字符的第1个字符,函数然后返回一个指向source中第1个匹配所找到的位置的指针。如果source中的所有字符均不匹配chars中的任何字符,函数就返回一个NULL指针。如果任何一个参数为NULL,或任何一个参数所指向的字符串为空,函数也返回一个NULL指针。
举个例子,假定source指向ABCDEF。如果chars指向XYZ、JURY或QQQQ,函数就返回一个NULL指针。如果chars指向XRCQEF,函数就返回一个指向source中C字符的指针。参数所指向的字符串是绝不会被修改的。
碰巧,C函数库中存在一个名为strpbrk的函数,它的功能几乎和这个你要编写的函数一模一样。但这个程序的目的是让你自己练习操纵指针,所以:
a.你不应该使用任何用于操纵字符串的库函数(如strcpy,strcmp,index等)。
b.函数中的任何地方都不应该使用下标引用。

分析: 这个函数是一个以指向两个字符型常量的指针变量作为形参且返回值为指针的函数。这个题目中的“函数返回一个指向source中第一个匹配所找到位置的指针”,这一句话也值得好好思考一下。题目中提到的strpbrk,是在源字符串(s1)中找出最先含有搜索字符串(s2)中任一字符的位置并返回,若找不到则返回空指针。头文件为#include

程序如下:

//方法一
#include 

char *find_char(char const *source,char const *chars);
//这里是指针变量作为函数参数,即将一个变量的地址传送到另一个函数中 
//用字符指针变量作形参和实参且函数返回指针值 
int main()
{
	char const  *s="ABCDEF"; 
	char const  *c="XRCQEF";
	char *t;

	printf("source=%s\nchars=%s\n",s,c);
    t=find_char(s,c);
	printf("Matched return value:%s",t);
	return 0;
}

char *find_char(char const *source,char const *chars)
{
    char *p;//设p为指向source中第一个匹配所找到位置的指针 
    if(source != NULL && chars != NULL){
        for(;*source != '\0';source++){
            for(p = chars; *p != '\0';p++)
                if(*p == *source)
                    return p;
        }
    }
    return NULL;
}

//方法二
#include

char *find_char(char const *source,char const *chars);
int main(){
	char m[]="ABCDEF";
	char n[]="XRCQEF";
	char *t;
	char const *s=m; //使指针变量s指向m数组首元素
	char const *c=n; //使指针变量c指向n数组首元素
    printf("source=%s\nchars=%s\n",s,c);
	t=find_char(s,c);
	printf("Matched return value:%s",t);
	return 0;
} 

char *find_char(char const *source,char const *chars)
{
    char *ps = source;
    char *pc = NULL;
    if(source == NULL || chars == NULL)
        return NULL;
    while(*ps != '\0'){
        pc = chars;
        while(*pc != '\0'){
            if(*pc == *ps)
                return pc;
            pc++;
        }
        ps++;
    }
    return NULL;
}

//方法三
char *find_char(char const *source,char const *chars)
{
    int size = 0;
    if(source != NULL && chars != NULL){
        for(;*chars++ != '\0';size++)
            ;
        for(;*source != '\0';source++){
            for(chars-=size; *chars != '\0';chars++)
                if(*chars == *source)
                    return chars;
        }
    }
    return NULL;
}

运行结果:
C与指针——指针(一)_第1张图片
注: 在运行时,纠结过返回的指针所指的究竟是source中还是chars中的字符串首地址,最后反复读题,根据题上所言的“指向source中的指针”可见,返回的指针不在source中,而应该是指向source中的,所以最后返回的指针所指的应该是chars中的字符串首地址。

虽然美名其曰是重新温习,但实际清楚的知道自己是来填坑的。之前有多浪,现在需要填的坑就有多深,尤其是在进行指针这一板块的内容时,深切体会到了大一的时候C语言老师语重心长提醒我们关于指针的知识点一定要重复多遍才能真正掌握的良苦用心。
关于指针的知识点,个人感觉,谭浩强的《C程序设计》中的讲解更为详细些,细节方面适合我这种小白阅读;而在《C和指针》中,只简单看完相关知识点,不参考其他的书籍,则在直接编程练习的过程中,做到一帆风顺是不容易的。
综上,这一章节的编程练习题,两本书混合食用效果更佳~

现在看着日历仿若是在看病危通知书
暑假自己定的计划终究也为证明人类的本质作了贡献
还有两天……(Death smiles)
好多人都说生活的迷人之处在于阴差阳错
可我不,我偏就是想要如愿以偿

你可能感兴趣的:(C与指针——指针(一))