C 语言疑难杂症 [转:http://blog.chinaunix.net/uid-20688544-id-1894880.html]
|
运行结构是:
4
1
80
8
96
问题出在 char j; 这里,单独查看,可以看到 char类型占用一个 byte,但是为什么放都结构体里面的时候,它就占用了 4 个byte 呢?难道结构体有对自己的元素类型占用空间做了强制规定吗?
在dev-c++ 里面,调试了一下:
500)this.width=500;" border="0" src="http://blogimg.chinaunix.net/blog/upfile2/080426204138.jpg">
看到的结构体里面,竟然没有 j 这个元素,取而代之的是 i=97'a' 这又怎么解释呢?
—。—#
//-----------------------------------------
找到这篇文章,哈哈,我想红色字就是我要的答案了:
intarray[3]={35,56,37};
int*pa=array;
通过指针pa访问数组array的三个单元的方法是:
*pa;//访问了第0号单元
*(pa+1);//访问了第1号单元
*(pa+2);//访问了第2号单元
从格式上看倒是与通过指针访问结构成员的不正规方法的格式一样。
所有的C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。但在存放结构对象的各个成员时,在某种编译环境下,可能会需要字对齐或双字对齐或者是别的什么对齐,需要在相邻两个成员之间加若干个"填充字节",这就导致各个成员之间可能会有若干个字节的空隙。
所以,例中,即使*pstr访问到了结构对象ss的第一个成员变量a,也不能保证*(pstr+1)就一定能访问到结构成员b。因为成员a和成员b之间可能会有若干填充字节,说不定*(pstr+1)就正好访问到了这些填充字节呢。这也证明了指针的灵活性。要是你的目的就是想看看各个结构成员之间到底有没有填充字节,嘿,这倒是个不错的方法。
//-----------------------------------------
当全局变量跟局部变量有冲突时,局部变量会把全局变量隐藏掉。据说可以用加 :: 的方式来强制访问全局变量,但是我加了这个符号根本就编译不过去,应该是C++ 才有的吧?
getch(); |
超简单的代码,可是,运行后 i=6,j=16
怎么回事呢??
什么是标准预定义宏?
ANSIC标准定义了以下6种可供C语言使用的预定义宏:
----------------------------------------------------------------------------
宏 名 作 用
----------------------------------------------------------------------------
__LINE__ 在源代码中插入当前源代码行号
__FILE__ 在源代码中插入当前源代码文件名
__DATE__ 在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕
__TIME__ 在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕
__STDC__ 当要求程序严格遵循ANSIC标准时该标识符被赋值为1。
----------------------------------------------------------------------------
标识符__LINE__和__FILE__通常用来调试程序;标识符__DATE__和__TIME__通常用来在编译后的程序中加入一个时间标志,以区分程序的不同版本;当要求程序严格遵循ANSIC标准时,标识符__STDC__就会被赋值为1;当用C++编译程序编译时,标识符__cplusplus就会被定义。
|
连接运算符“##”和字符串化运算符"#"有什么作用?[仔细理解]
连接运算符“##”可以把两个独立的字符串连接成一个字符串。在C的宏中,经常用到“##”运算符,请看下例:
#include
#define SORT(X) sort_function ## X
void main(vOid);
void main(vOid)
{
char *array;
int elements,element_size;
SORT(3) (array,elements,element_size);
}
在该例中,宏SORT利用“##”运算符把字符串sort_function和经参数x传递过来的字符串连接起来,这意味着语句 SORT(3)(array,elemnts,element_size) 将被预处理程序转换为语句:
sort_function3(array,elements,element_size);
从宏SORT的用法中你可以看出,如果在运行时才能确定要调用哪个函数,你可以利用“##”运算符动态地构造要调用的函数的名称。
int main() } |
符串化运算符"#"运算符能将宏的参数转换为带双引号的字符串,请看下例:
define DEBUG_VALUE(v) printf(#v"is equal to %d. \n", v)
你可以在程序中用 DEBUG_VALUE 宏检查变量的值,请看下例:
int x=20;
DEBUG_VALUE(x);
上述语句将在屏幕上打印"x is equal to 20"。这个例子说明,宏所使用的“#”运算符是一种非常方便的调试工具。
} |
怎样删去字符串尾部的空格?
C语言没有提供可删去字符串尾部空格的标准库函数,但是,编写这样的一个函数是很方便的。请看下例:
|
在上例中,rtrim()是用户编写的一个函数,它可以删去字符串尾部的空格。函数rtrim()从字符串中位于null字符前的那个字符开始往回检查每个字符,当遇到第一个不是空格的字符时,就将该字符后面的字符替换为null字符。因为在C语言中null字符是字符串的结束标志,所以函数rtrim()的作用实际上就是删去字符串尾部的所有空格。
怎样删去字符串头部的空格?
C语言没有提供可删去字符串头部空格的标准库函数,但是,编写这样的一个函数是很方便的。请看下例:
… } |
在上例中,删去字符串头部空格的工作是由用户编写的ltrim()函数完成的,该函数调用了6.2的例子中的rtrim()函数和标准C库函数strrev()。ltrim()函数首先调用strrev()函数将字符串颠倒一次,然后调用rtrim()函数删去字符串尾部的空格,最后调用strrev()函数将字符串再颠倒一次,其结果实际上就是删去原字符串头部的空格。
怎样打印字符串的一部分?
使用printf()函数打印字符串的任意部分,请看下例:
} |
在上例中,第一次调用printf()函数时,通过指定参数"%11.11s",迫使printf()函数只打印11个字符的长度,因为源字符串的长度大于11个字符,所以在打印时源字符串将被截掉一部分,只有头11个字符被打印出来。第二次调用printf()函数时,它将源字符串的最后13个字符打印出来,其实现过程为:
(1)用strlen()函数计算出source_str字符串的长度,即strlen(source_str)。
(2)将source_str的长度减去13(13是将要打印的字符数),得出source_str中剩余字符数,且pstrlen(source_str)-13。
(3)将strlen(source_str)-13和source_str的地址相加,得出指向source_str中倒数第13个字符的地址的指针;即source_str+(strlen(source_str)-13)。这个指针就是printf()函数的第二个参数。
(4)通过指定参数“%13.13s”,迫使printf()函数只打印13个字符的长度,其结果实际上就是打印源字符串的最后13个字符。
用malloc()函数更好还是用calloc()函数更好?
函数malloc()和calloc()都可以用来分配动态内存空间,但两者稍有区别。malloc()函数有一个参数,即要分配的内存空间的大小:
void *malloc(size_t size);
calloc()函数有两个参数,分别为元素的数目和每个元素的大小,两个参数的乘积就是要分配的空间的大小:
void *calloc(size_t numElements,size_t sizeOfElement);
如果调用成功,函数malloc()和calloc()都将返回所分配的内存空间的首地址。
malloc()函数和calloc()函数的主要区别是前者不能初始化所分配的内存空间,而后者能。如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之,如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常运行,但经过一段时间后(内存空间已被重新分配)可能会出现问题。
calloc()函数会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为零;如果你是为指针类型的元素分配内存,那么这些元素通常(但无法保证)会被初始化为空指针;如果你是为实数类型的元素分配内存,那么这些元素可能(只在某些计算机中)会被初始化为浮点型的零。
malloc()函数和calloc()函数的另一点区别是calloc()函数会返回一个由某种对象组成的数组,但malloc()函数只返回一个对象。为了明确是为一个数组分配内存空间,有些程序员会选用calloc()函数。但是,除了是否初始化所分配的内存空间这一点之外,绝大多数程序员认为以下两种函数调用方式没有区别:
calloc( numElements,sizeOfElement );
malloc( numElements * sizeOfElement );
需要解释的一点是,理论上(按照ANSIC标准)指针的算术运算只能在一个指定的数组中进行,但是在实践中,即使C编译程序或翻译器遵循这种规定,许多C程序还是冲破了这种限制。因此,尽管malloc()函数并不能返回一个数组,它所分配的内存空间仍然能供一个数组使用(对realloc()函数来说同样如此,尽管它也不能返回一个数组)。总之,当你在calloc()函数和malloc()函数之间作选择时,你只需考虑是否要初始化所分配的内存空间,而不用考虑函数是否能返回一个数组。
NULL和NUL有什么不同?
NULL是在头文件中专门为空指针定义的一个宏。NUL是ASCII字符集中第一个字符的名称,它对应于一个零值。C语言中没有NUL这样的预定义宏。注意:在ASCII字符集中,数字0对应于十进制值80,不要把数字0和'\0'(NUL)的值混同起来。
NULL可以被定义为(void *)0,而NUL可以被定义为'\0'。NULL和NUL都可以被简单地定义为0,这时它们是等价的,可以互换使用,但这是一种不可取的方式。为了使程序读起来更清晰,维护起来更容易,你在程序中应该明确地将NULL定义为指针类型,而将NUL定义为字符类型。
在程序退出main()函数之后,还有可能执行一部分代码吗?
可以,但这要借助C库函数atexit()。利用atexit()函数可以在程序终止前完成一些“清理”工作——如果将指向一组函数的指针传递给atexit()函数,那么在程序退出main()函数后(此时程序还未终止)就能自动调用这组函数。在使用atexit()函数时你要注意这样两点:
第一: 由atexit()函数指定的要在程序终止前执行的函数要用关键字void说明,并且不能带参数;
第二: 由atexit()函数指定的函数在入栈时的顺序和调用atexit()函数的顺序相反,即它们在执行时遵循后进先出(LIFO)的原则。
now, eixt this program... |
数组作为函数的常数时,可以通过sizeof运算符得到函数数组的大小吗?
不可以。当把数组作为函数的参数时,你无法在程序运行时通过数组参数本身告诉函数该数组的大小,因为函数的数组参数相当于指向该数组第一个元素的指针。这意味着把数组传递给函数的效率非常高,也意味着程序员必须通过某种机制告诉函数数组参数的大小。为了告诉函数数组参数的大小,人们通常采用以下两种方法:
第一种方法是将数组和表示数组大小的值一起传递给函数,例如memcpy()函数就是这样做的:
memcpy( dest,source,length );
第二种方法是引入某种规则来结束一个数组,例如在C语言中字符串总是以ASCII字符NUL('\0')结束,而一个指针数组总是以空指针结束。请看下述函数,它的参数是一个以空指针结束的字符指针数组,这个空指针告诉该函数什么时候停止工作:
void printMany( char *strings[] )
{
int i = 0;
while( strings[i] != NULL )
{
puts(strings[i]);
++i;
}
}
正象9.5中所说的那样,C程序员经常用指针来代替数组下标,因此大多数C程序员通常会将上述函数编写得更隐蔽一些:
void printMany( char *strings[] )
{
while( *strings )
{
puts(*strings++);
}
}
尽管你不能改变一个数组名的值,但是strings是一个数组参数,相当于一个指针,因此可以对它进行自增运算,并且可以在调用puts()函数时对strings进行自增运算 [注意辨别这种情况:对“int array[10] 数组的array不能进行自加运算”]。
array_name和&array_name有什么不同?
前者是指向数组中第一个元素的指针,后者是指向整个数组的指针。注意: 笔者建议读者读到这里时暂时放下本书,写一下指向一个含MAX个元素的字符数组的指针变量的说明。希望你不要敷衍了事,因为只有这样你才能真正了解C语言表示复杂指针的句法的奥秘。下文将介绍如何获得指向整个数组的指针。
数组是一种类型,它有三个要素,即基本类型(数组元素的类型),大小(当数组被说明为不完整类型时除外),数组的值(整个数组的值)。你可以用一个指针指向整个数组的值:
char a[MAX]; /*array of MAX characters*/
char *p = a;
char *pa = &a;
在运行了上述这段代码后,你就会发现p和pa的打印结果是一个相同的值,即p和pa指向同一个地址。但是,p和pa指向的对象是不同的。
上述定义和以下定义是相同的,它们的含义都是“ap是一个含MAX个字符指针的数组”: char *ap[MAX].
以下这种定义并不能获得一个指向整个数组的值的指针:char *(ap[MAX]).
怎样判断一个字符是数字、字母或其它类别的符号?
在头文件ctype.h中定义了一批函数,它们可用来判断一个字符属于哪一类别。下面列出了这些函数:
---------------------------------------------------------------------------------------
函数 字符类别 返回非零值的字符
---------------------------------------------------------------------------------------
isdigit() 十进制数 0--9
isxdigit() 十六进制数 0--9,a—f,或A--F
isalnum() 字母数字符号 0--9,a--Z,或A--Z
isalpha() 字母 a—z或A--Z
islower() 小写字母 a—z
isupper() 大写字母 A--Z
isspace() 空白符 空格符,水平制表符,垂直制表符,换行符,换页符,或回车符
isgraph() 非空白字符 任何打印出来不是空白的字符(ASCII码从21到7E)
isprint() 可打印字符 所有非空白字符,加上空格符
ispunct() 标点符 除字母数字符号以外的所有非空白字符
iscntrl() 控制字符 除可打印字符外的所有字符(ASCII码从00到1F,加上7F)
----------------------------------------------------------------------------------------
与前文提到过的使用标准库函数的好处相似,调用上述这些宏而不是自己编写测试字符类别的程序也有三点好处。首先,这些宏运算速度快,因为它们的实现方式通常都是利用位屏蔽技术来检查一个表,所以即使是进行一项相当复杂的检查,也比真正去比较字符的值要快得多。其次,这些宏都是正确的。如果你自己编写一个测试程序,你很容易犯逻辑上或输入上的错误,例如引入了一个错误的字符(或漏掉了一个正确的字符)。第三,这些宏是可移植的。信不信由你,并非所有的人都使用同样的含PC扩充字符的ASCII字符集。也许今天你还不太在意,但是,当你发现你的下一台计算机使用的是Unicode字符集而不是ASCII字符集,你就会庆幸自己原来没有按照字符集中的字符值来编写程序。
其他字符转换函数:
isascii(测试字符是否为ASCII 码字符)
int isascii(int c);
检查参数c是否为ASCII码字符,也就是判断c的范围是否在0到127之间。若参数c为ASCII码字符,则返回TRUE,否则返回NULL(0)。
toascii(将整型数转换成合法的ASCII 码字符)
int toascii(int c);
toascii()会将参数c转换成7位的unsigned char值,第八位则会被清除,此字符即会被转成ASCII码字符。将转换成功的ASCII码字符值返回。
tolower(将大写字母转换成小写字母)
int tolower(int c);
若参数c为大写字母则将该对应的小写字母返回。返回转换后的小写字母,若不须转换则将参数c值返回。
toupper(将小写字母转换成大写字母)
int toupper(int c);
若参数c为小写字母则将该对映的大写字母返回。返回转换后的大写字母,若不须转换则将参数c值返回。
#include<stdio.h> |
C 语言疑难杂症 [转:http://blog.chinaunix.net/uid-20688544-id-1894880.html]的更多相关文章
- 原博客地址http://blog.chinaunix.net/uid/20656672.html弃用
原博客地址http://blog.chinaunix.net/uid/20656672.html弃用
- 原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(10年前数百篇oracle/teradata性能优化、故障处理案例)
原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(数百篇oracle/teradata性能优化.故障处理原创文章) 858871 top 500 ...
- http://blog.chinaunix.net/uid-20577907-id-3519578.html
http://blog.chinaunix.net/uid-20577907-id-3519578.html
- http://blog.chinaunix.net/uid-9845710-id-1996675.html snmpd配置
http://blog.chinaunix.net/uid-9845710-id-1996675.html http://lihuipeng.blog.51cto.com/3064864/643960 ...
- http://m.blog.csdn.net/article/details?id=8237698
http://m.blog.csdn.net/article/details?id=8237698
- http://m.blog.csdn.net/article/details?id=49132747
http://m.blog.csdn.net/article/details?id=49132747
- http://m.blog.csdn.net/article/details?id=2630620
http://m.blog.csdn.net/article/details?id=2630620
- C语言 字符串处理函数 转自 http://blog.chinaunix.net/uid-25885064-id-3175049.html
C字符串处理函数 2012-04-13 18:14:16 分类: C/C++ void *memccpy (void *dest, const void *src, int c, size_t n) ...
- JavaSript模块规范 - AMD规范与CMD规范介绍 (转载lovenyf.blog.chinaunix.net)
JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发? 模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题 ...
随机推荐
- 一道hive面试题(窗口函数)
表student中的数据格式如下: name month degree s1 201801 As1 201802 As1 201803 Cs1 201804 As1 201805 As1 201806 ...
- 【 C 】高级字符串查找之 strspn 和 strcspn 的思考
我的CSDN博客 strspn 这个库函数是真的很难理解,看了很多中文描述,反正都是不知所云,给出一系列的例子,结果也是让我瞠目结舌,荒唐.荒谬.荒诞! 特此记录理解过程,最后竟然是百度百科让我明白了 ...
- Machine Learning——吴恩达机器学习笔记(酷
[1] ML Introduction a. supervised learning & unsupervised learning 监督学习:从给定的训练数据集中学习出一个函数(模型参数), ...
- 20145226夏艺华 《Java程序设计》第9周学习总结
教材学习内容总结 学习目标 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义泛型和自定义枚举 会使用标准注解 第16章 整合数据库 16.1 JDBC入门 (一)JDB ...
- jQuery Validate (登录页面相关验证)
$(function() { var submit = false; var superHtml = []; /** * 匹配企业帐号,以字母开头,长度在6-20之间,只能包含字符.数字和下划线. * ...
- [css 实践篇]CSS中的尺寸单位
绝对单位 px: Pixel 像素 pt: Points 磅 pc: Picas 派卡 in: Inches 英寸 mm: Millimeter 毫米 cm: Centimeter 厘米 q: Qua ...
- jenkins+jacoco+ant自动化代码和应用服务代码分离场景获取远程服务的覆盖率
前提 自动化代码和应用服务代码分离.jenkins和tomcat服务器分离 思想 1.在tomcat启动javaagent监听. 2.运用其他job_B已部署的应用服务代码 3.拉取自动化代码,开始测 ...
- 搜索引擎ElasticSearch系列(四): ElasticSearch2.4.4 sql插件安装
一:ElasticSearch sql插件简介 With this plugin you can query elasticsearch using familiar SQL syntax. You ...
- 百度云 win10 125%界面模糊 解决
右击图标 ->兼容性->更改高DPI设置 -> 替代高DPI缩放行为.打√
- 内网集群准同步shell脚本
在公司的内网中配置集群同步,可能是代理问题,ntpd和chrony都没有用,所以只好写shell脚本解决 前提条件集群中各台机器已经配置好了免密登录 一.免密登录配置 1. 用 root 用户登录.每 ...