C语言的那些事

变量的存数类型:

1:静态变量:凡是在代码任何快之外声明的变量总是存储在静态内存内,也就是不属于堆栈的内存。

对于这类变量。你无法对它们制指定存储类型。

2:存储于堆栈中,称为自动变量。当程序执行到声明自动变量的代码时,自动变量才被创建。

当程序的执行流离开该代码时,这些自动变量将被自行销毁。

3:寄存器变量:关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器,而不是

内存中,这类变量称为寄存器变量。

通过一个指针访问它所指向的地址的过程称为间接访问或者解引用指针。这个用于执行间接的操作符是单目操作符*。

如:d的值是100,当我们对D使用间接访问操作符时,它表示访问内存地址100,并查看那里的值。因此:*d的市里面存储

的内容,

d是一个指向整型的指针,对它进行引用操作符将产生一个整型值。类似,对float *进行间接访问将产生一个float型的值。

关于野指针和空指针:

下面的代码是很明显的错误:

int *a;

...

*a=12;

这个声明创建了一个名叫a的指针变量,后面那条赋值语句把12存储在a所指向的内存位置。

警告:

但是究竟a指向哪里呢?我们声明了这个变量,但是从来未对其进行初始化,所以我们没有办法预测12这个直讲存储于什么地方。

从这一点看,指针变量和其它变量并没有什么区别。如果变量是静态的。他会被初始化为0.但是如果变量是自动的,它根本不会被初始化。

空指针:

#include"stdio.h"

int main()

{

printf("%d\n",NULL);//0

}

标准定义了NULL指针,它作为一个特殊的指针变量,表示不指向任何东西。要是一个指针变量为NULL,你可以给它赋一个零值。为了测试

一个指针变量是否为NULL,你可以将它与零值进行比较。之所以选择零这个值是因为一种源代码约定。就机器内部而言,NULL指针的实际值可能

与此不同。在这种情况下,编译器将负责零值与内部值之间的转换。

NULL指针的概念是非常有用的,因为它给了你一种用法,表示某个特定的指针目前并为之向任何东西。比如:一个用于在某个数组中查找特定值的函数,

可能返回一个指向查找到的数组元素的指针。如果该数组不包含指定条件的值,函数就返回一个NULL指针,这个技巧允许返回值传达两个不同片段的信息。

首先,有没有找到元素?其次,如果找到,它是哪个元素呢?

尽管这个技巧在C程序中,极为常用。但是他违背了软件工程的原则,用一个单一的值表示两种不同的意思是件很危险的事情,因为将来很容易无法

弄清哪个才是它真正的用意。在大型的程序中,这个问题更加严重,因为你不可能在头脑中对整个设计一览无余,一种更为方便的策略是让函数返回两个独立的值。:

首先是个状态值,用于提示查找是否成功;其次是个指针,当状态值提示查找成功时,它所指向的就是要查找的元素。

对指针进行解引用操作可以获得它所指向的值。但是从定义上来看,NULL指针并为之向任何东西。因此,对于一个NULL指针进行解引用操作是非法的。

在对指针进行解引用之前,你必须确定它非NULL指针。

警告:如果对一个NULL指针进行间接访问会发生什么情况呢?这个视编译器而定。在有些机器上,它会访问内存位置零,便以其能够确保内存位置零

没有存储任何变量,但机器并未阻碍你访问这个位置,这种行为是非常不幸的,因为程序包含了一个错误,但是机器却隐匿了它的症状,这样就使得这个错误难以查找。

在其他机器上,对NULL指针进行间接访问将引发一个错误,并终止程序。宣布这个错误比隐藏这个错误要好得多,因为程序员更容易修正它。

提示:

如 果所有的指针变量(而不仅仅是位于静态中的指针变量)能够被初始化为NULL,那确实是件幸事,但事实并非如此。不论你的机器对解引用NULL指针这种行 为作何反应,对所有的指针变量进行显示的初始化就是最好的做法。如果你已经知道指针将被初始化为什么类型的地址,就把它初始化为该地址,否则就把他初始化 为NULL。风格良好的程序会在解引用之前对它进行检查。这种初始化策略可以节省大量的调试时间。

指针:

*&a=25;

这句代码的含义是:把值25赋值给变量a。

首先&操作符产生变量a的地址,它一个指针常量(注意:使用这个指针并不需要知道它的实际值),接着,*操作符访问其操作数所标示的地址。在这个表达式中,操作数是a的地址,所以值25就直接存储于a中。

另一大难点:

假定变量a存储于位置100,那么下面这条语句的作用是:

* 100=25;

它上去像是把25的值赋值给a,因为a是位置100所存储的变量。但是,这是错的。

这条语句上是非法的。因为字面值100的类型是整型,而间接访问操作只能作用于指针类型表达式。如果你确实想把25存储于位置100,你必须使用强制类型转换。

*(int *)100=25;

强制类型转换把值100从“整型”转换为”整型的指针”,,这样对它进行间接访问,就是合法的。如果a存储于位置100,那么这个条语句就是把值25存储于a。

//计算一个字符串的长度

#include"stdio.h"

#include"stdlib.h"

strlen(char *string)

{

int length=0;

/*

*依次访问字符串的内容,计数字符数,直到遇见NULL终止符。

*/

while(*string++!=‘\0‘)

{

length+=1;

}

return length;

}

2:关于字符串的输入和输出:

C语言中,没有字符串类型,用字符数组处理字符串。

字符数组定义:

char 数组名[常量表达式] [,[常量表达式]];

说明:一维字符数组,用于存储和处理一个字符串,二维字符数组,用于同时存储和处理多个字符串;

因为字符型与整型是通用的,可以用int来定义字符数组,但两者有区别,如:

char c[10];    /* 在内存中占10字节 */

int c[10];     /* 在内存中占40字节 */

输入输出方法:逐个字符输入输出:%c,整个字符串输入输出:%s

一:用scanf()输入字符串,printf()输出字符串:

逐个字符处理:

#include "stdio.h "

void main()

{    char   ch[5];

int i;

for(i=0;i<5;i++)

scanf(“%c”, &ch[i]);

for(i=0;i<5;i++)

printf(“%c”, ch[i]);

}

整个字符串处理:

#include "stdio.h "

void main()

{    char   ch[5];

scanf(“%s”,ch);

printf(“%s”, ch);

}

说明:

以字符串为单位处理时,直接使用数组名,无需&;

输入字符串时,字符个数要小于数组的长度,如输入5个字符,定义的字符数组至少应有6个元素;

输入字符串时,若遇空格或回车,输入结束,并自动在串后加上结束标志’\0’;

输出字符串时,遇到字符串结束标志’\0’,输出结束。

二:用字符串处理函数输入和输出

字符串标准函数的原型在头文件string.h中(使用字符串处理函数输入和输出时要在头文件上加入 #include<string.h>)

字符串输出函数puts

格式:puts(字符数组)

功能:向显示器输出字符串(输出完,自动换行,即用’\n’替换了’\0’)

说明:字符数组必须以‘\0’结束

字符串输入函数gets

格式:gets(字符数组)

功能:从键盘输入一以回车结束的字符串放入字符数组中,并自动加‘\0’

说明:输入串长度应小于字符数组维数,字符串中可以包含空格

例如:

#include<stdio.h>

#include<string.h>

void main()

{

char str[10];

int i;

printf("请输入字符串:\n");

gets(str);

printf("输入的字符串为:\n");

puts(str);

}

数组:

定义数组的大小必须使用整型常量或者整型常量表达式。C语言中不允许用变量下表形式对数组进行动态定义。例如:下面的数组定义语句:

Short score[100]; //正确的定义形式

而:

Short score[N];  //不正确的定义方式

是非法的,即使在数组定义的语句前面使用赋值语句给N进行了赋值,或者使用scanf()输入了N值,上面这条语句也是非法的。

关于使用scanf输入数据或许你还有好多疑问,下面是一个师哥(zy)对我的疑惑的讲解。

Zy:字符串的本质就是个char*。scanf输入字符串,就是往指定的位置,其实就是

I:但是ch[5]不是定义了一个存放五个字符的数组么,我输入的超过五个且少于十个程序就没有停止。

下面给你一个案例:

int a=99,b=99;
float c=9999,d=99.99;
scanf("%d %d %f %f",&a,&b,&c,&d);

Printf("%d %d %f %f\n",a,b,c,d);
当输入内容是:1.23 4.5 6.7,知道这四个变量值怎么变化吗?

由于实在不确定它的结果,在VC环境下调试下:

当我从键盘上依次输入:1.23 4.5 6.7(回车),

输出结果却是:1 99 9999.000000 99.989998

对于小数点后的输出结果:浮点型数据,小数点后有六位有效数字,它随操作系统而变化,不是确切的数,不是直接补零。

但是为什么第三个数能够进行确切的输出,小数点后面全是0,而第四个数为什么小数点后面的数是那些呢?

因为这个你输入的是9999,本身小数点后面没有输入,所以自然补零

由于float是系统默认为6位有效数字,float是单精度型
double是双精度型的,最高可以到16位。

由计算结果可以看出:

就a被改写了。后面类型不匹配,scanf被自动终止。
但是,现在的问题是,明显就那个1被读走了,敲的后面那段内容哪去了?

或者这样,这个56去哪了?

为什么当从键盘上依次输入 12(空格)34(空格)56(空格)之后,为什么程序不等让用户输入C,就直接输出执行结果?

刚刚这个,明显是一开始要两个数,敲了三个,多一个
而第二次要求输入c的时候,程序就没停,没让输入,直接过去了

但是,这是什么原因呢:


为scanf语句你只让输入两个数据a和b,但是你在键盘上输入的时候却直接输入了三个整数,实际上scanf(“%d”,&c);已经执行了,
输入:12 34 56就相当于直接把56传给C,这样的执行等同于将两行scanf语句一同执行,但是在编写程序的过程中,这种输入法是不

提倡的。

补充:


于scanf(“%d%d”,&a,&b);中的双引号中的格式符,如果在两个%d中间加上一个空格,那么在键盘上进行输入时,一定要严
格遵从scanf中的形式,如:12(空格)34,但是如果将scanf()这条语句修改为:scanf(“%d%d”,&a,&b);
那么在键盘上输入的时候在两个int类型的数字之间,你可以任意输入空格,回车,或者Tab毽作为两个数据之间的分隔符。所以提倡使用scanf语句时,
在双引号之间只有格式符。双引号里直接写代码,别写空格。

,scanf输入的所有东西,都是先写到内存里,然后往变量里放。虽然这三个auto型变量也是在内存中,这么说很奇怪。

scanf对应的那里叫做stdin标准输入流,你敲击的东西都被顺序放入了标准输入流里面。

scanf("%d%d",&a,&b);

先把你敲击的东西写入stdin,然后再从stdin里顺次把数据转换成按照指定的类型(第一个是%d),也就是输入的字符流12转换成int型的12,写入指定的位置(第一个%d对应的是&a)

输入流内容是12 34 56
输入格式指定顺次为%d%d,也就是说一上来就要整数
基于贪心法,1是整数,合法;12是整数,合法;12空格不合法
那么%d对应的是12,把字符流12转换成int型的12,写到变量a中

时间: 2024-10-10 01:26:32

C语言的那些事的相关文章

C语言那点事——如何从零学好C语言?

本文的核心,是在讨论如何真正的学好C语言,而不是讨论如何在C语言考试中拿高分.当然真正学好了C语言,拿高分也就不那么难了. C语言是很多大学生大一的一门必修课,尤其是理工科专业,这门课程更是重中之重.如何学好C语言呢?这里提几点我的看法. 打好基础 基础对于任何东西的学习都很重要,没有基础肯定不容易学好,遇到问题解决不了,然后发现欠缺了到很多基础,就会感觉无从下手.C语言国内采用较多的是谭浩强的<C程序设计>,我更推荐的是C语言创始人参与编写的<The C Programming Lan

【转】嵌入式C语言那点事(一)几个重要关键字

原文链接:http://blog.csdn.net/pirateleo/article/details/7529776 一.static 关键字static,修饰变量时: 1.限制该变量的作用域:比如静态全局变量,只能在该模块中使用(本c文件中). 2.决定该变量的存储位置:修饰为静态的变量,存储在静态数据区(非堆栈内).(同比,全局变量也都存放在静态数据区中.) 带初值和不带初值的静态变量:(以TI DSP 54XX为例) a.不带初值的静态变量,存储在.bss段中. b.带初值的静态变量,存

页面切换语言包使用session不用cookie

cookie的问题,ifame中的cookie不一致 在父页面设置的语言包cookie,在iframe中获取不到.为什么呢? 为什么语言包这个事跟cookie过不去,有什么特殊的? iframe的src请求的时候就得把这个cookie带到服务器上去,此时携带的是iframe自己的cookie,不是父页面事先通过交互后设置的cookie.所以会出现父页面语言正常,iframe不正常. 解决办法:用session替代.session丢失的时候采用浏览器的设置语言.交互设置session,sessio

【C语言探索之旅】 开宗明义及第一课:什么是编程?

内容简介 1.课程大纲 2.第一部分第一课:什么是编程? 3.第一部分第二课预告:工欲善其事,必先利其器 ? 课程大纲 不知道为什么,一直对C语言有一种很深厚的"情怀"(类似老罗对锤子手机的那种),说不出来. 也许因为C语言是很多前辈谆谆教诲说一定要学一下的一门编程语言:也许因为C语言是自己学习的专业"嵌入式系统"的首要语言:也许因为C语言自1972年诞生以来历经43年依然独领风骚,位列编程语言排行榜首位:也许因为"C语言之难,难于上青天",自己

MindManager解读:网络语言

最近总是阴天下雨,蓝瘦香菇···小编好像不知不觉中用了最近比较流行的网络语了,实属被"迫"呀.那边"洪荒之力"的余温还未散去,这边"蓝瘦香菇"又集体刷屏.你说无奈不无奈吧,近年来不少网络流行语成为社会语言,对社会的渗入越来越广,今天我们就跟着MindManager一起来看看关于网络语言的那些事! 网络语言简洁实用,具有新颖独特.巧妙幽默.叛逆性三个主要特征.网络语言的发生有其心理依据和社会原因,心理依据作为内在原因可从心理动力.社会心理和认知特征

编程语言随想

欢迎光临我的 [QQ空间](http://user.qzone.qq.com/570926881/blog/1477487825) 本人其实没有足够的资格谈论这个问题,其实真正用过的语言也就C/C++,PHP,JS.其他的很多语言也只停留在知道的阶段,当然用过的语言也不精通,只是想就这个一直堆积在自己心里的问题做一个总结,也算是给不枉这几年跟大家的讨论.以下观点仅仅是个人简介由于水平有限肯定有很多疏漏,望见谅,欢迎交流,也会不记名提到一些同学,没有任何恶意仅仅说明现象. ### 语言不是程序的全

构建工具的发展及Android Gradle快速上手

前话: 最近谷歌宣布官方不再维护Eclipse ADT了,之后将更加专注于Android Studio的功能和性能上的改进,早在2013年的Google IO大会上首次推出了Android Studio,当时刚出来的时候我就好奇的去下载体验了一下,想看一下新开发工具的优势在哪里,据官方介绍,最吸引我的一点就是使用Studio使用了Gradle编译系统,可以支持很灵活的定制需求,而我当时正在研究当成库使用的APK(就是现在的aar文件,不过当时还没有出身),刚好遇到了ADT编译系统的限制,所以当时

为什么一些古老的编程语言不会消亡?

编译自:http://readwrite.com/2014/09/02/programming-language-coding-lifetime 作者: Lauren Orsini 原创:LCTT https://linux.cn/article-4524-1.html 译者: runningwater 本文地址:https://linux.cn/article-4524-1.html 2014-12-25 10:22    评论: 4 分享: 6 我们钟爱我们已知的. 当今许多知名的编程语言已

如何实现并应用决策树算法?

本文对决策树算法进行简单的总结和梳理,并对著名的决策树算法ID3(Iterative Dichotomiser 迭代二分器)进行实现,实现采用Python语言,一句老梗,“人生苦短,我用Python”,Python确实能够省很多语言方面的事,从而可以让我们专注于问题和解决问题的逻辑. 根据不同的数据,我实现了三个版本的ID3算法,复杂度逐步提升: 1.纯标称值无缺失数据集 2.连续值和标称值混合且无缺失数据集 3.连续值和标称值混合,有缺失数据集 第一个算法参考了<机器学习实战>的大部分代码,