c语言难点综合
上学期c语言后半期老师没怎么教,自己又不大学,学得比较菜。但基于打基础考虑和后续的与数据结构相关的链表、数据库相关的指针、c++里的类似于结构体的类与对象等都有着一衣带水的关系,所以只好看了一遍遍的课本,把一些重要的知识点综合总结出来。高能预警!!!
一、函数部分
- 函数分为无参函数与有参函数。
函数在声明时可以只写参数类型而不写参数名,如float add(float,float);示例代码:
include
int main(){
int c;
int add(int ,int );
c=add(2,6);
printf(“%d\n”,c);
return 0;
}
int add(int x,int y){
int z;
z=x+y;
return (z);
}递归函数是“自己调用自己”的函数,无论是采用直接或间接调用方式。间接递归意味着函数调用另一个函数(然后可能又调用第三个函数等),最后又调用第一个函数。因为函数不可以一直不停地调用自己,所以递归函数一定具备结束条件。示例代码(二分法搜索):
long *binarySearch( long val, long array[ ], int n ){
int m = n/2;
if ( n <= 0 ) return NULL;
if ( val == array[m] ) return array + m;
if ( val < array[m] ) return binarySearch( val, array, m );
else return binarySearch( val, array+m+1, n-m-1 );}形参中的数组可以不用写明大小,直接留空如:float average(float array[],int n);对于二维数组,可以写成array[][10]的形式。
- 全局变量通常首字母大写
- 数组可以利用函数名或者单个值当做函数实参进行传递。前者如:float(a);、后者可以是a[i];
变量存储方式和生存期
- 按照变量的作用域(从空间)的角度来观察,变量可以分为全局变量和局部变量。二按照变量值存在的时间(即生存期)来观察,故分为静态存储方式和动态存储方式。
- 内存中的工用户使用的存储空间的情况。这个存储空间可以分为3部分:
(1)程序区;
(2)静态存储区;
(3)动态存储区。 - 动态存储区中存放一下数据:
1、函数形式参数。在调用函数时给形参分配存储空间。
2、函数中定义的没有关键字static声明的变量,即自动变量。
3、函数调用时的现场保护和返回地址。 - 静态局部变量与自动变量不同,自动变量属于动态存储类别,分配在动态存储区空间,在函数调用结束后会自动释放。而静态局部变量不会自动释放,还会保存当前的数值。一般静态局部变量和静态函数,可以放在程序的开头,以提高程序的可靠性。
- 至于寄存器变量,寄存在CPU当中,存储速度远远高于对内存的存取速度。关键字为register。
- extern可以对变量做“外部变量声明”,表示把改外部变量扩展到此位置。也可以对另外一个文件模块中的变量进行声明调用。如果不想被其他文件调用,可以使用static进行声明。
二、运算符:
这些运算符并非仅用于c语言,编程语言之间都有着共通性。这里只对一些特殊运算符进行分析。
左移运算符,左移,而右边空出的位补0(c++中有其他用法)。例如:10100110,逻辑左移后为:01001100。右移运算符则与左移相反,进行右移时,左边空出的位补0。示例代码:
int i = 1; //把i赋值为1,二进制为0001
i =i<<1; //将i左移一位 printf("%d",i); //输出结果为2. i =i>>1; //将i右移一位
printf(“%d”,i); //输出结果又换回1.三元运算符 例如:
return( z=x>y?x:y);//进行判断,将大者返回
运算符的优先级可以在这个老兄的博文里面查阅:http://blog.csdn.net/huangblog/article/details/8271791
三、指针:
- 进行指针间转换时一定要注意好,传过来如果是2个整形变量的地址,则得到的是2个整形变量,不能用指针变量去交接。
指针引用数组时,可以这样遍历输出:
int a[3];
int i,*p;
for(i=0;i<3;i++)scanf("%d",&a[i]);
for(p=a;p<(a+3);p++)
printf("%d",*p);
也可以这样:
int a[3];
int i,*p;
p=a;
for(i=0;i<3;i++)
scanf("%d",p++);
for(p=a,i=0;i<3;i++,p++)
printf("%d",*p);
要注意的是,下面的那一种方法,先让p指向a数组的首地址后,经过scanf的3次赋值,最后会转到第三个地址,需要重新让p=a,指向首地址,才能重新遍历打印。
- (星号(p++)与(星号)(++p)的作用是不同的,前者先取*p的值,然后再+1;后者相反。(星号)(++p)相当于a[++i]。
0行1列的元素的地址可以用a[0]+1来表示。(星号)(a[i]+j)(星号)((星号)(a+i)+j)等同于a[i]a[j]。地址上会逐个加8个字节。
int a[2][2]={ 1,2,3,4};
int i,*p;
for(p=a[0];p<a[0]+2;p++){ if({ p-a[0])%4==0) printf("\n");
printf("%d",*p);}
定义p为指向具有4个元素的以为数组的指针,可以是
float (*p)[4];
6.定义字符串指针
char *string;
*string="I love China";
//等同于
char *string1="I love China";
7.字符串间的复制,可以直接用地址进行逐个复制
char a[]="I love China";
for(i=0;*(a+i)!='\0';i++)
*(b+i)=*(a+i);
*(b+i)='\0';//在有效字符之后添加\0
for(i=0;b[i]!='\0';i++)
printf("%c",b[i]);
也可以,用2个指针变量按顺序指向不同的元素进行复制。
char a[]="I love China",b[12],*p1,*p2;
p1=a;p2=b;
for(;*p1!='\0';p1++,p2++)
*p2=*p1;
*p2='\0';//在有效字符之后添加\0
for(i=0;b[i]!='\0';i++)
printf("%c",b[i]);
8.指向函数
int i;
int max(int ,int);
int (*p)(int ,int);
if (n==1)
p=max;
int max(int x,int y){
return( z=x>y?x:y);}
全局变量分配到内存中的静态存储区,非静态局部变量分配到栈(stack)存储区。使用malloc函数可以将一些临时用的数据放到堆里面(这与c++的new何其酷似)进行动态分配,带回的是void指针。函数原型为
void malloc(unsigned int size);/开辟size(n字节)的临时分配区*/
calloc函数,其得到的空间很大,可以容纳一个数组。
void calloc(unsigned n,unsigned size);/n是元素个数, 每个的长度就是size*/
free函数是用来释放掉calloc分配的动态内存的,使这一部分空间能重新被其他变量使用。应该对应的是最近一次调用calloc或者malloc函数时得到的函数返回值。如free(p);
- realloc函数,可以对calloc或者malloc函数已经分配的动态空间的大小进行重新分配。如:realloc(p,50);
- void指针类型是指向空类型的,也就是不确定的类型,与其他类型的指针对接时,系统自动跟随着改变其类型。
指向结构体的指针,示例代码:
struct Student{ long name;}
struct Student stu_1;
struct Student p;
p=&stu_1;
strcpy(stu_1.name,”耗子”);
printf(“%ld\n”,stu_1.name);
printf(“%ld\n”,(p).name);指向结构体数组的指针,示例代码:(与c++通用的是,指向结构体数组用的->而不是.)
struct Student{ long name;char sex;}
int main(){
struct Student stu[4]={ { “耗子”,’男’},{ “小张”,’男’},{ “小观”,’男’},{ “小李”,’男’}};
//其他人不言而喻,自己琢磨
struct Student *p;
for(p=stu;pname,p->sex); 野指针:野指针是未指向合法内存的指针。
多级指针
char *p1; //普通的二级指针
char (p2)[5]; //指针,指向char[5]数组的指针
char p3[5]; //数组,以char 为元素的指针数组链表与指针的基佬关系
①链表有一个头指针变量,head,它存放指向下一个元素的地址。最后一个元素,即表尾,它的地址部分放一个NULL。
②链表中每一个元素称为结点,结点分为:用户所需数据与下一个结点地址。
建立简单的静态链表include
struct Student
{int num;
float score;
struct Student *next;
}
int main()
{ struct Student a,b,c,head,p;
a.num=10101;a.score=89.5;
b.num=10102;a.score=90.5;
b.num=10104;a.score=92.5;
head=&a;
a.next=&b;//节点互绑
b.next=&c;
c.next=NULL;
p=head;
do{ printf("%ld%5.1lf\n",p->num,p->score);
p=p->next;
}while(p!NULL);
return 0;
}
建立简单动态链表
struct Student *head;
struct Student *p;
p = (struct Student *)malloc(sizeof(struct Student));
head = (struct Student *)malloc(sizeof(struct Student));
if (NULL == head)
{
printf("Memory create error!\n");
return 1;
}
四、文件:
- fopen函数打开数据文件:fopen(文件名,使用文件方式);fclose函数关闭如:fclose(文件指针)。
通常用一个指针指向文件。如:
FILE*fp;
fp=fopen(“book.txt”,”r”);//使文件指针fp与文件连接调用一个文件,且在找不到文件的时候自动关闭所有文件。
FILE *fp;
if((fp=fopen(“E:/book.txt”,”w”))==NULL){
printf(“文件打开错误!\n”);
exit(0); }
fclose(fp);向文件读写一个字符串
fgets(str,n,fp);//向文件读入一个长度未n-1的字符串
以二进制形式向向文件读写入一组数据
格式为:fread(buffer,size,count,fp);与fwrite(buffer,size,count,fp);
buffer是传送的数据;size是大小;count是写入数据项个数,一般写为1;
fp是文件指针。for(i=0;i<M;i++){
fwrite(&book[i],sizeof(struct classmate),1,fp); fclose(fp); }位置标记:fseek函数。
- ferror(fp)功能是检测出错反馈信息。
附件:一些奇妙的功能
- c的3个数据流:stdin(标准输入流),stdout(标准输出流),stderr(标准出错输出流)。
- typedef (变量类型名)(变量名称):指定某个新的名称的变量类型与前者作用相同。
- 逗号运算从右往左
- printf的输出的先后顺序为从左往右
系统时间的调用
time_t t;
struct tm * lt;
time (&t);//获取Unix时间戳。
lt = localtime (&t);//转为时间结构。
printf ( "%d/%d/%d %d:%d:%d\n",lt->tm_year+1900,
lt->tm_mon,lt->tm_mday, lt->tm_hour,
lt->tm_min, lt->tm_sec);//输出结果
还没有评论,来说两句吧...