花了一上午的时间,要学的东西真是太多了。
1.1.2 预处理指令
#include <stdio.h> ----->预处理器用stdio.h的库函数头文件的内容替换此条语句
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20 ----->MAX_COLS,MAX_INPUT均为字面常量,所以不能出现于某些普通变量可以出现的地方
#define MAX_INPUT 1000 比如赋值符的左边
由预处理器解释.
int readColumnNumbers(int columns[],int max);
void rearrange(char *output,char const *input,int nColumns,int const columns[]);
--->*output,*input:指针,指定一个存储于计算机内存中的值的地址
const:表示函数将不会修改函数调用者所传递的这两个参数
把函数原型放在头文件中并使用#include指令包含它们,可以避免由于同一个声明的多份拷贝而导致的维护性问题.
1.1.3 main函数
main函数的函数体包括左花括号和与之相匹配的右花括号之间的任何内容
nColumns = readColumnNumbers(columns,MAX_COLS);
c语言中,数组参数是以引用形式进行传递的,也就是传址调用,而标量和常量则是按值传递的。在函数中
对标量参数的任何修改都会在函数返回时丢失,因此,被调用函数无法修改调用函数以传值形式给它的参数,而当被
调用函数修改数组参数的其中一个元素时,调用函数所传递的数组就会被实际修改
在C语言中,参数的传递是通过栈来实现的,栈资源的申请就是上面提到的c0s.obj的工作之一
while( gets ( input ) != NULL )
{
printf("Original input : %s\n",input);
rearrange(output,input,nColumns,columns);
printf("Rearrange line: %s\n",output);
}
要注意书写正确的注释,并且在你修改代码时要注意注释的更新。
gets函数从标准输入读取一行文本并把它存储于作为参数传递给他的数组中。以换行符结束,gets函数丢掉换行符,
并在该行的末尾存储一个NUL字节(一个NUL字节是指字节模式为全0的字节,类似'\0'这样的字符常量).然后gets函数
返回一个非NULL值,表示该行已被成功读取。当gets函数被调用但事实上不存在输入行时,它就返回NULL值,表示它
到达了输入的末尾.
<----------------------------------------------------------------------------------------------------
gets函数会无限读取不会判断上限,故容易出错,常用gets_s函数来代替gets函数
int a[3];
gets_s(a);
cin> > 1234;
提示错误
int a[3];
gets(a);
cin> > 1234;
不提示错误
NULL被大量定义在标准头文件中,0是一个整型常量,'\0'是一个字符常量,而NUL是一个字符常量的名字。这几个术
语都不可互换。
1、NULL用于表示什么也不指向,也就是空指针((void *)0)
2、0可以被用于任何地方,它是表示各种类型零值的符号并且编译器会挑出它
3、'\0'应该只被用于结束字符串
4、NUL没有被定义于C和C++,它不应该被使用除非你自己定义它,像:#define nul '\0'
----------------------------------------------------------------------------------------------------->
字符串就是一串以NUL字节结尾的字符,NUL是作为字符串终止符,它本身并不看作是字符串的一部分
字符串常量就是源程序中被双括号括起来的一串字符,
例如:"hello",在内存中占据6个字节的空间,按顺序分别是h、e、l、l、o和NUL
<---------------------------------------sizeof()-----------------------------------------------
1.定义:
sizeof():判断的是数据类型的长度,返回一个对象或者类型所占的内存字节数
返回值类型为size_t(typedef unsigned int size_t;).
(MSDN: The sizeof keyword gives the amount of storage, in bytes, associated with a variable
or a type (including aggregate types). This keyword returns a value of type size_t.)
2.语法:
1>sizeof(object); //sizeof(对象);
2>sizeof(type_name); //sizeof(类型);
3>sizeof object; //sizeof 对象;
所以:
int i;
sizeof(i); //ok
sizeof i; //ok
sizeof(int);//ok
sizeof int; //error
实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象的sizeof值
是一样的。这里,对象还可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果
类型来确定大小,一般不会对表达式进行计算,如:
char foo()
{
printf("foo() has been called.\n");
return 'a';
}
int main()
{
size_t sz = sizeof(foo());//foo()的返回值类型为char,所以sz=sizeof(char),foo()并不会被调用
printf("sizeof( foo() ) = %d\n", sz);
}
C99规定,函数、不能确定类型的表达式以及位域(bir-field)成员不能被计算sizeof值
3.指针变量的sizeof:
指针记录了另一个对象的地址,既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度,所以在
32位计算机中,一个指针变量的返回值必定是4(Byte),与指针所指的对象没有任何关系.
4.数组的sizeof:
数组的sizeof值等于数组所占用的内存字节数,如:
char a1[] = "abc";
int a2[3];
sizeof(a1); //结果为4,字符末尾还存在一个NULL终止符
sizeof(a2); //结果为3*4=12,(依赖于int)
用sizeof求数组元素个数:
int c1 = sizeof(a1) / sizeof(char); //总长度/单个元素的长度
int c2 = sizeof(a1) / sizeof(a1[0]); //总长度/第一个元素的长度
提问:
void foo3(char a3[3])
{
int c3 = sizeof( a3 ); // c3 ==?
}
void foo4(char a4[])
{
int c4 = sizeof( a4 ); // c4 ==?
}
注意: c3 != 3.这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,数组是传址调用的,调用者
只需将实参的地址传递过去,所以a3自然为指针类型(char *),故c3的值为4.
5.结构体的sizeof:
struct S1
{
char c;
int i;
}; ------------>sizeof(S1)=8;
(MSDN:When applied to a structure type or variable, sizeof returns the actual size, which may
include padding bytes inserted for alignment.) ------字节对齐,有助于加快计算机的取数速度,否则就得多
花指令周期了,为此,编译器默认会对结构体进行处理,让宽度为2的基本数据类型都位于能被2整除的地址上,让宽
度为4的基本数据类型都位于能被4整除的地址上,以次类推。
字节对齐一般满足三个准则:
1>结构体变量的首地址能够被其最宽基本数据类型成员的大小所整除;
2>结构体每个成员相对于结构体首地址的偏移量是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节
3>结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
有一个影响sizeof的重要参数pack,它是用来调整结构体对齐方式的
公式如下:
offsetof( item ) = min( n, sizeof( item ) )
再看示例:
#pragma pack(push) // 将当前pack设置压栈保存
#pragma pack(2) // 必须在结构体定义之前使用
struct S1
{
char c;
int i;
};
struct S3
{
char c1;
S1 s;
char c2;
};
#pragma pack(pop) // 恢复先前的pack设置
计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)等于6,能够被2整除,所
以整个S1的大小为6。
同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能被2整除,添加一个填充
字节,所以sizeof(S3)等于10。
空结构体(不含数据成员)的大小为1.
.位域--> 位域是指信息在存储时,并不需要占用一个完整的字节,而只需要占几个或一个二进制位,为了节省空间
并使处理简便,c语言又提供了一种数据结构,成为"位域"或"位段"。所谓"位域"就是把一个字节中的二进制
位划分为几个不同的区域,并说明每个区域的位数,每个域有一个域名,允许在程序中按域名进行操作。这
样就可以把几个不同的对象用一个字节的二进制位域来表示.
6.与strlen的区别:
stelen(char *)函数求的是字符串的实际长度,它求的方法是从开始到遇到第一个'\0',如果你只定义没有
给它赋值,这个结果值不定的,它会从首地址一直找下去,直到遇到'\0'停止。
对于指针:
char *ss = "0123456789";
sizeof(ss)结果为4-->ss值指向字符串常量的字符指针,sizeof获得的是一个指针的值所占的空间,应为长整型。
sizeof(*ss)结果1-->*ss是第一个字符,其实就是获得了字符串的第一位'0'所占的空间,是char类型的,占1位
strlen(ss)结果10-->字符串的长度,不包括'\0'。
7.其实理解sizeof只需要抓住一个要点:栈
程序存储分布有三个区域:栈、静态和动态。能够从代码直接操作的对象,包括任何类型的变量、指针,都
是在栈上的;动态和静态存储区是靠栈上的所有指针间接操作的。sizeof操作符计算的是对象在栈上的投影体积;
选自:http://baike.baidu.com/view/1078660.htm
---------------------------------------------------------------------------------------------------->