在c里面fscanf会遇到空格就停止。而且着里面如果你的参数是%s的话还需要注意,字符串读取会默认一直到这一行的末尾或者是空格而结束。着里面fscanf有几个高级的功能,类似于正则表达式的,比如
1、 * 亦可用于格式中, (即 %*d 和 %*s) 加了星号 (*) 表示跳过此数据不读入. (也就是不把此数据读入参数中)
2、{a|b|c}表示a,b,c中选一,[d],表示可以有d也可以没有d。
3、width表示读取宽度。
4、{h | l | I64 |
L}:参数的size,通常h表示单字节size,I表示2字节 size,L表示4字节size(double例外),l64表示8字节size。
5、type :这就很多了,就是%s,%d之类。
6、%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)。%[aB'] 匹配a、B、'中一员,贪婪性
%[^a] 匹配非a的任意字符,贪婪性。这里的%应该是集合的意思吧!
对于像1,fasdfasdf;d,66,8 这样的应该这样读取
fscanf(fp,"%d,%[^;];%c,%d,%d",&num,(char *)(&s),&c,&num2,&num3);
c字符串赋值
char s[]="dkasjsda";这个其实是在栈上声明空间,所以可以进行对数组的修改。而char *s2="dasdasasd";其实是声明了一个指针,其指向了静态存储区的一个字符串常量,不能改变其内容,否则会抛出segmentation fault的错误。
你也可以这样赋值 char s3[]={'d','f','d','d','e','e','r','\0'}。和char s[]="dkasjsda"效果是一样的。sizeof(s3)是8而sizeof(s2)是4。
s3的类型是char[8],s2的类型是char* 。
但你声明了一个数组时,你就不能在另外的语句里面再对他进行赋值了。比如char s[22];s="dasasd";是错的。只能一个元素一个元素的赋值,至于为什么会这样我也不知道。
const的用法
可以节省空间,避免不必要的内存分配。 例如:
#define PI 3.14159 //常量宏
const doulbe Pi=3.14159;
//此时并未将Pi放入ROM中 ......
double i=Pi; //此时为Pi分配内存,以后不再分配!
double I=PI; //编译期间进行宏替换,分配内存
double j=Pi; //没有内存分配
double J=PI; //再进行宏替换,又一次分配内存!
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是
象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也
很高。
修饰常指针
const int *A;
//const修饰指向的对象,A可变,A指向的对象不可变
int const *A;
//const修饰指向的对象,A可变,A指向的对象不可变
int *const A; //const修饰指针A,
A不可变,A指向的对象可变
const int *const A;//指针A和A指向的对象都不可变
gcc编译器下:
c里面的变量分为三种,具有外部连接性质的,内部连接性质的还有不具有连接性质的。比如我在一个c文件a.c里面定义了一个const int a=9;那么我可以在另一个b.c文件中在函数外写int b;(也可以写const int b,也可以写extern int b)。这里的b的指仍然是9,奇怪为什么不一定要用extern呢?而你也不能在b.c里面改变它的值,会抛出段错误。如果在a.c中有一个static int b=7;那么在b.c中就再也引用不到了,因为static变量只具有内部连接性,只能在a.c中被访问。而你在a.c里面如果有一个int add(int a,int b){return a+b;}那么在b.c中竟然可以直接调用,也不需要extern。这就是连接。那我们要头文件有什么用呢?我们好像没有用到过头文件现在……
头文件作用:(1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。 (2)头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。
其实没有头文件我们照样可以写出程序,但是这里的头文件就像是暴露给用户看的借口或者说是文档一样,是一个辅助性的东西。但是又是编程的一部分。
在c语言里,对象必须有且只有一个定义,但是它可以有多个extern声明。定义与声明的区别,声明所说明的并非是对象自身,而是描述其他地方的创建的对象。定义相当于是特殊的声明,它为对象分配内存。
数组与指针,你看我定义一个数组时候,char s[100],这里其实并没有在空间里申请一个变量保存s的地址,然后s的内容是一个地址指向了字符序列。这里其实在编译之后s就没有了,字符序列的地址已经确定了。你s[2]的时候进行的只是地址的操作,而不是先取s的指向的地址,再偏移,再取内容,这样太麻烦。因为s和地址直接绑定了,直接偏移就可以了。而指针不一样,那是动态的,你用char *s="12312";s[2],其实是先取s的指向的地址,再偏移,再取内容。试想如果你在一个文件里char s[]="1231231",然后在另一个文件里extern char *s;s[2]会发生什么?因为s的地址(不是s存的地址,是s本身的地址)的是s所固定绑定的地址。但是它会把原来的顺序的asc码当作是地址再来进行偏移,这个显然是荒谬的。记住extern不申请额外的空间,这里都是extern在搞怪。但是如果你char s[]="12123";char *s2=s是可以的。
关于指针和数组我还要讲一些,数组名是不可以修改其值的,是不可修改的左值,因为它在编译时就确定了。而指针是可以改变指向的。作为函数参数的数组(在一个函数调用中)始终会被编译器修改为指向数组第一个元素的指针。没有办法把数组本身传递给函数,这个命题似乎有点怪。什么叫数组本身。
c语言中的多维数组其实是数组的数组。注意在数组给函数当参数的时候,形式参数总会是指针的形式。比如 char c[8][10]会改写成char*c[10]。指针数组char *c[15]会改成char**c。数组指针char(*c)[64]不变,char**c不变。在c语言中,没有办法向函数传递一个普通的多维数组。这是因为我们需要知道每一维的长度,以便为地址运算提供正确的单位长度。在c语言中,我们没有办法在实参和形参之间交流这种数据。因此你必须提供出了最左边一维以外的所有维的长度。这样就把实参限制在除左边一维外所有维都匹配的数组。
在c里面,指针赋值的时候有这么一个约定。两个操作数都是指向有限定符或是无限定符的相容类型的指针,左边的指针所指向的类型必须有右边指针所指向类型的全部限定符。
比如char * cp;const char * cpp;cpp=cp;这个就是对的。因为const char 和 char是相容的,本质都是char。而cpp包含了cp,所以可以。而cp=cpp就是不对的。
而如果char **a1;const char **a2;那么彼此则不能赋值。因为const char*和char *其实是不相容的,因为类型是不一样的,一个是指向const char 的指针一个是指向char 的指针。而如果是char **a1;char * const a2;就可以a2=a1;
const和*的组合通常只是用在数组形式的参数中模拟传值调用。
如果有一个语句是malloc(strlen(str))那么可以肯定那是错误的,而malloc(strlen(str)+1)才是对的。
一旦一个指针进行解除引用操作时所引用的内存地址超出了虚拟内存的地址空间,操作系统会中止这个进程。
break语句是跳出的最近的那层循环或是switch语句。
几乎c所有的函数都是默认用extern限定。但是这个其实是一个缺陷,软件对象在大多数情况下应该缺省采用有限可见性,如果要声明是全局的,应采用显示的声明。在c语言中,对信息的可见性的选择是很有限的。
[]的优先级要高于*,int *ap[]意思是ap是个指向int指针的数组。
函数()高于*,所以函数指针得这么定义,int(*p)()
赋值符=具有右结合性,+具有左结合性。
printf("%d\n",sizeof 'A')的值不是1,而是4,也就是int的长度值。为什么呢?因为char如果在表达式中,那么会自动隐式转换为int,而sizeof就是一个表达式,所以char会转换成int。记住,参数传递也是一个表达式。
为什么printf能够传进去不同的类型呢?因为不论传进去的是哪一个类型,函数从堆栈取出来的总是int类型的。printf的函数的原型是printf(const char * format,...);所以任何参数传进去都会导致参数提升。
隐式转换是语言的一种临时手段,把所有的操作数都转换为统一的长度简化了代码的生成。这样,压到堆栈中的参数都是同一长度的,所以运行时系统只需要知道参数的数目而不需要知道参数的个数。
函数原型的重要:如果我在一个文件sub.c里面定义了一个函数,banana(float d,char i){......},在main
.c中直接调用banana(10.0,3),则我printf("float=%f,char =%x \n",d,i);时会输出float=0,char=0,为什么会这样。因为在main.c文件里没有banana的函数原型,所以在传递参数的时候,float会变成double类型的进行压栈,而banana取的时候又是根据float取的,这样又会影响char的位置的读取,所以会造成错误。注意如果banana改为banana(char i,float d){......},则char是取得对的,而float则是取的错的。
解决的方法就是在main.c里面加上一句,extern void banana(float,char)。
分享到:
相关推荐
【超市管理系统C语言归纳】 本篇内容主要涵盖了使用C语言实现的一个简单的超市管理系统的设计与实现。这个系统由西安邮电大学理学院应用物理学专业的学生王松在2014年进行的高级语言课程设计中完成,指导教师为王...
c语言经典算法之归纳算法。翻硬币。 编译软件:DEV C++5.
C语言归纳算法,翻硬币,奇偶数 有N个硬币(N为偶数)正面朝上排成一排,每次将N-1个硬币翻过来放在原位置,不断地重复上述过程,直到最后全部硬币翻成反面朝上为止。设计程序让计算机把翻币的最简过程以及翻币次数...
C语言基本语法归纳
《C语言实现的归纳算法》 在编程领域,归纳算法是一种重要的问题解决方法,它通过逐步构建解决方案,从基础情况开始,然后递归地应用到更复杂的情况。本实验主要探讨了如何使用C语言实现归纳算法来解决特定的翻转...
C语言基本语法归纳 ppt
《C语言学习归纳总结及相关实验报告》 C语言,一种强大的、通用的编程语言,以其简洁、高效和灵活的特点在软件开发领域占据了重要的地位。它既是初学者入门编程的良好起点,也是专业程序员不可或缺的工具。这份资料...
"Dhua C语言算法归纳"很可能是对C语言中各种常见算法的整理和总结,旨在帮助学习者更好地理解和掌握这些算法。这里,我们将深入探讨C语言中的核心算法知识。 一、排序算法 1. 冒泡排序:一种简单的排序方法,通过...
本文主要归纳了C语言中常见的算法,分为基本算法、非数值计算的经典算法以及数值计算的经典算法。 一、基本算法 1. **交换**:在C语言中,交换两个变量的值通常需要一个辅助变量。例如,给定两个整数a和b,通过一...
### C语言基本语法归纳 C语言作为一种广泛应用的编程语言,其基本语法构成了程序设计的基础。本文将基于给定的信息——“C语言基本语法归纳”,详细阐述C语言中的关键概念、语法规则及其应用实例。 #### 1. C语言...
【C语言程序设计】谭浩强版的C语言程序设计是针对初学者的经典教程,它基于第三版进行了归纳总结,包含高清PPT和丰富的程序示例及运行结果,旨在帮助学习者深入理解C语言的基本概念和应用。C语言是国际上广泛采用的...
C语言基本语法归纳 本文档对C语言的基本语法进行了归纳,并提供了实例介绍。C语言概况、C程序的结构、数据类型、运算符与表达式、顺序程序设计、选择结构程序设计、循环控制、数组、函数、指针等知识点都进行了详细...
以下是对《2018广东专插本C语言考点归纳-帕思.pdf》内容的知识点进行详细说明: 1. 常量: - 数字常量包括普通数字(整数和小数)、指数形式表示的数字、长整型和单精度浮点型。例如,3235L代表长整型,而32.5F...
C语言基础 C语言是一种工业语言,广泛应用于操作系统、嵌入式系统、驱动程序、图形引擎、图像处理、声音效果等领域。学习C语言可以提高开发效率和开发乐趣,但是在日常应用中很少直接使用C语言,学习C语言主要是...
【C语言小结归纳】 C语言是一种强大的编程语言,尤其适合初学者学习。在C语言中,函数是程序的基本组成部分,下面将详细讲解C语言中关于函数、参数以及局部变量的一些关键知识点。 **函数参数的特性** 1. **形参...
C语言是一种广泛使用的计算机编程语言,它在算法实现方面有着非常重要的地位。算法是解决问题的一系列定义明确的计算步骤。在C语言中,算法的实现依赖于清晰的逻辑思维和严密的程序结构。 一、基本算法 基本算法是...
### C语言算法归纳知识点 #### 一、递归法转换整数为字符 递归法是一种常见的编程技术,尤其适用于解决具有自相似性的问题。在本例中,递归法被用来将一个整数转换成对应的字符串形式。 ```c void convert(int n)...