二、C语言笔记归纳总结2基础篇(指针与字符串)

本文详细讲解了指针的基础概念,包括指针与const的关系、指针运算、类型转换,以及动态内存分配和释放。重点介绍了malloc和free函数的用法及实例,同时涵盖了字符串操作、指针类型和数组操作。

1.指针的使用

指针与const:指针本身和所指的变量都可能const

注:C语言中const关键字的用法,参考这位大牛的解释:
http://blog.csdn.net/xingjiarong/article/details/47282255
保护数组值:

1.因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值
2.为了保护数组不被函数破坏,可以设置参数为const
即 int sum(const int a[ ],int length);

2.指针的运算

1. sizeof(char)=1,sizeof(int)=4
给一个指针加1表示要让指针指向下一个变量
int a[10];
int *p=a;
*(p+1)->a[1]
即 *(p+n)<->a[n]

如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义

2. 这些算术运算可以对指针做:

给指针加、减一个整数(+,+=,-,-=)
递增递减(++、–)
两个指针相减

3. *p++

取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
*的优先级虽然高,但是没有++高
常用于数组类的连续空间操作
在某些CPU上,这可以直接被翻译成一条汇编指令

4. 指针的比较(它们在内存中地址大小的比较)
数组中的单元的地址肯定是线性递增的
5.
0地址

内存中有0地址,但是0地址通常是个不能随便碰的地址
所以指针不应该具有0值
因此可以用0地址来表示特殊的事情

返回的指针是无效的
指针没有被真正初始化(先初始化为0)

NULL是一个预定定义的符号,表示0地址

因为有的编译器不愿意你用0来表示0地址

3.指针的类型

无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
但是指向不同类型的指针(如char *p=&ac[0];int *p=&ai[0];)是不能直接互相赋值的
这是为了避免用错指针

4.指针的类型转换(初学者慎用)

void*表示不知道指向什么东西的指针

计算时与char*相同(但不相通)

指针也可以转换类型

int *p=&i;//通过p去看i,i是int
void*q=(void*)p;//通过q去看i,i当作void
这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量

不再当它是int,认为是个void

指针作用总结

1.需要传入较大数据时用作参数
2.传入数组后对数组做操作
3.函数返回不止一个结果

需要用函数来修改不止一个变量

4.动态申请的内存…

5.动态内存分配

malloc函数

函数的原型为
void *malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间(大小是以字节为单位的),其参数是一个无符号整形数,返回值是一个指向所分配连续存储区域的起始地址的指针(返回的结果是void *,需要类型转化为自己需要的类型),如
(int *)malloc(n*sizeof(int)
还有一点必须强调,若函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针,所以在调用函数时应该检测返回值是否为NULL,并执行相应的操作。

下例是一个动态分配的程序:
main()
{
int count,*array;
//count是一个计数器,array是一个整形指针,也可以理解为指向一个整形数组的首地址
if((array(int *)malloc(10*sizeof(int)))==NULL)
//为数组array申请10个整型(int)大小空间
{
printf("不能成功分配内存空间");
exit(1);
}
for(count=0;count<10;count++)
array[count]=count;
for(count=0;count<10;count++)
printf("%2d",array[count]);
}
上例中动态分配了10个整形存储区域,然后进行赋值并打印,例中if((array(int*)malloc(10*sizeof(int)))==NULL)语句可以分为以下几个部分:

1.分配10个整形的连续存储空间,并返回一个指向其起始地址的整形指针。
2.把此整形指针地址赋值给array
3.检测返回值是否为NULL

free函数

是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值(把申请来的空间还给系统,申请过的空间都要还)

其参数p必须是先前调用的malloc函数或calloc函数(另一个动态分配内存区域的函数)时返回的指针。给free函数传递其他的值很可能造成死机或其他灾难性的后果。(只能还申请来的空间的首地址)
注意:这里重要的是指针的值,而不是用来申请动态内存的指针本身。例如:
int *p1,*p2;
p1=malloc(10*sizeof(int));
p2=p1;
……
free(p2);//或者free(p1)
p2 = NULL;
malloc返回值赋给p1,又把p1的值赋给p2,所以此时p1,p2都可以作为free函数的参数,malloc函数对于存储区域进行分配。free函数释放已经不用的内存区域。所以有这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。
注:free函数只是将参数指针指向的内存归还给操作系统,并不会把参数指针置NULL,为了以后访问到被操作系统重新分配后的错误数据,所以在调用free之后,通常需要手动将指针置NULL。
free(p2)后指针仍然指向原来的堆地址,即你仍然可以继续使用,但很危险,因为操作系统已经认为这块内存可以使用,他会毫不考虑的将他分配给其他程序,于是你下次使用的时候可能就已经被别的程序改掉了,这种情况就叫“野指针”,所以最好free()了以后再置空
p2 = NULL;
即本程序已经放弃再使用他。

example1

1char *p;
2while (1)
3 {
4p = malloc(1);
5 *p = 0;
6}
A. 最终程序会因为没有没有空间了而退出
B. 最终程序会因为向0地址写入而退出
C. 程序会一直运行下去
D. 程序不能被编译
解析:
A. 这确实是引起程序终止的原因,但不是直接原因。
C. 肯定是无法永远运行下去啦。
D. 这段代码是合法的,所以可以编译。
B. 程序一直分配内存,肯定会引起内存耗尽。而malloc在分配内存失败时并不会终止程序,而是返回NULL指针。而第5行代码试图向NULL指针位置写入数据,这会引起程序终止(通常操作系统会因为“段错误”而终止程序)。
所以 B 才是引起程序退出的直接原因。

example2

int a[] = {1,2,3,4,5,};
int *p = a;
int *q = &a[5];
printf("%d", q-p);
当sizeof(int)为4时,以下说法正确的是:
A.因为第三行的错误不能编译
B.因为第三行的错误运行时崩溃
C.输出5
D.输出20
选择C
解析:在这里插入图片描述
由此可知两地址之差为20,且当sizeof(int)为4时,即p-q=20/4=5,所以输出int型值为5(即p与q之间可以放5个int型)
附:%p是打印地址的!!!(上面只是为了更直观,方便计算!)在这里插入图片描述1C=16+12=28 ,p-q=28-8=20,输出int型值为5(即p与q之间可以放5个int型)

6.字符串操作

putchar

int putchar(int c);
向标准输出写一个字符
返回写了几个字符,EOF(-1)表示写失败

getchar

int getchar(void);
从标准输入读入一个字符
返回类型是int是为了返回EOF(-1)

EOF

...
int ch;
while((ch = getchar()) != EOF)
putchar(ch);

printf("EOF\n");
...

问:为什么getchar()不是输入一个字符呢?
答:因为程序和键盘显示器之间存在另外一个程序shell
键盘输入的数据在按下shift之前会先存在 shell 给的缓冲区里(行编辑工作),用户输入是让shell填缓冲区,然后 shell 处理过后显示给你。(输出原理同输入)getchar()与scanf只是在shell 缓冲区里读东西。

不同操作系统下输入EOF按键不同

Windows–>Ctrl-Z
Unix–>Ctrl-D

字符串数组

char **a

a是一个指针,指向另一个指针,那个指针指向一个字符(串)

char a[ ][10 ]//有很多组a[0],a[1]...每组最多有10个字符
char *a[ ] //每组都比较小,a[0]指向外面写有字符的某处,a[1]指向...
注:上面两种形式是不一样的

程序参数

int main(int argc,char const *argv[ ])
argv[0]是命令本身

当使用Unix的符号连接时,反映符号链接的名字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃鱼从来不吐刺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值