底子太薄,看东西太过于马虎,到现在感觉自己不会的东西太多,也没有相对来说精通的东西。
老话说的很对,以往那些觉得以后用不上可以跳过的东西在关键时候都会跳出来给你当头一棒!固然,即使社会如此之动荡,人心如此之浮躁。踏踏实实学点东西,弄明白点东西,这才是根本。
1. C语言数据类型
1 #define SECOND_YEAR_TIME 365*24*60*60*30UL
2 #include"stdio.h"
3 #include"math.h"
4 int main()
5 {
6 printf("Total second is:%ld\n",SECOND_YEAR_TIME);
7 //int x= ((sizeof(int))*8);
8 printf("the max number of int is:%f\n",pow(2,32));
9 printf("the length of int is:%d\n",sizeof(int));
10 printf("the length of char is:%d\n",sizeof(char));
11 printf("the length of long int is:%d\n",sizeof(long));
12 printf("the length of float is:%d\n",sizeof(float));
13 printf("the length of double is:%d\n",sizeof(double));
14 printf("the length of short int is:%d\n",sizeof(int));
15 printf("the length of long double is:%d\n",sizeof(long double));
16 printf("the length of unsigned int is:%d\n",sizeof(unsigned int));
17 return 0;
18 }
今天仔细看看C,竟然连这些最基本的东西都无法分辨清楚。可悲的实践能力,可笑的这么些年。
以上结果为64位机下数据类型所占位数。
2. 在宏中define函数
#define MIN(A,B) A<=B?A:B
#include"stdio.h"
int main()
{
int a=45, b=43,x=0;
x=MIN(a,b);
printf("the min number is: %d",x);
}
这样能相对于在代码体中直接定义函数在编译时产生更优的性能结果,在嵌入式C中经常使用。
3. static int 与 const int
#include"stdio.h"
int main()
{
static int xx=3;
int sum=0;
for(;;)
{
sum=xx++;
if(sum>100)
{
break;
}
}
printf("The final number occur is: %d\n",sum);
printf("The value of xx after the loop is %d\n",xx);
}
#include"stdio.h"
int main()
{
const int xx=3;
int sum=0;
for(;;)
{
sum+=xx;
if(sum>100)
{
break;
}
}
printf("The final number occur is: %d\n",sum);
printf("The value of xx after the loop is %d\n",xx);
}
在C 语言中,关键字static 有三个明显的作用: 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访 问,但不能被模块外其它函数访问。它是一个本地的全局变量。 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是 ,这个函数被限制在声明它的模块的本地范围内使用。
从上面两段代码可以发现,static仅仅是在内存中保留了局部变量或者函数运行后的值,并不做销毁,这样可以方便传送给其他函数。
const则是严格指明变量的值不发生任何变化。 break则是使得程序跳出循环体,其对if语句并不起任何作用;另外break在switch语句中是必不可少的部分,如果缺少,则进入死循环。
4. 变量及指针变量的定义
#include"stdio.h"
int main()
{
int a; //定义一个整数
int *a; // 定义一个指向整数的指针
int **a; //定义一个指向指针的指针,并且这个指针指向一个整数
int a[10]; //定义一个包含十个元素的整形数组
int *a[10]; // 定义一个包含十个指针元素的数组,每个指针指向一个整形值
int (*a)[10] //定义一个有十个整形数组值的指针
int (*a)(int) //定义一个指向函数的指针,该函数至少一个整形参数且返回一个整数
int (*a[10])(int) //定义一个由十个指针的数组,该指针指向一个函数
}
5. const用法进阶
#include"stdio.h"
int main()
{
const int a=0; // 正确
int const b;
b =0; // 错误
int a=100,b=1000,*p,*t;
const int (*p=a);
int const (*t);
p+=8; // 正确,指针可以修改,但是指向的整数是不可以修改的
*t=3; // 错误
int* const p; // 常量指针,指向的整数可以修改,但是指针不可修改
int const * a const; // 整数不可以修改,同时指针也不可修改
}
6. voliaile
定义为volatile 的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
1>告诉compiler不能做任何优化。
2>用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能重复使用放在cache或寄存器中的备份。
7. int 与usigned int
#include<stdio.h>
#include"string.h"
int main()
{
int k=-1;
printf("%d,%u",k,k);
}
下图为程序运行结果与2^32次方计算结果。
8. 逻辑运算值对式子的影响
#include<stdio.h>
#include"string.h"
int main()
{
int a=5,b=6,c=7,d=8,m=2,n=2;
int x=(m=a>b)&&(n=c>d);
printf("逻辑表达式的值为:%d\n",x);
printf("程序运行后n的值为:%d\n",n);
printf("程序运行后m的值为:%d\n",m);
}
程序运行结果为:
因为运算符&&是一种短路运算符,前面的一个条件(m=a>b)为假,所以不会去执行后面的判断条件,因而后面语句根本没有执行,故n=2,而m=0.
9. 二维数组的指针
#include<stdio.h>
int main()
{
int a[][3]={10,20,30,40,50,60};
// 1行2列的地址:a[1]+2,*(a+1)+2,&a[1][2]
// 1行2列的值: *(a[1]+2),*(*(a+1)+2),a[1][2]
printf("the first number is: %d",*(*(a+1)+2));
}
a[1]代表第二行的首地址,+2代表右移两位。每一行代表一个班,整个数据表代表一个排,排长每次检查一个班,即从a-》a+1,跳过的元素为一个班的数量;而班长每次检查的元素数量仅为一个班的元素,即(a+1)+2代表这个班中的第三个元素。
10. 位操作
以下代码利用位操作实现对a的第三位置1,以及清0操作。
#include<stdio.h>
#define BIT3 (0x01a<<3) // 0x前缀代表十六进制;0前缀代表八进制;没有前缀代表十进制
int main()
{
static int a=120; // 二进制为:01100100
printf("BIT3的值为:%d\n",BIT3);
a |=BIT3;
printf("a的bit3设置为1后的值为:%d\n",a);
a &=~BIT3;
printf("a的bit3清除后的值为:%d\n",a);
}
11. break 和 continue
在while循环,do...while循环和for循环中,可以用break语句跳出循环,用continue语句结束本次循环。
而对用goto语句和if语句构成的循环,不能用break和continue语句进行控制。
break用于跳出循环,continue用于结束本次循环,并非终止整个循环。
12.冒泡排序
#include<stdio.h>
int main()
{
int a[10],temp;
int i,j,k,l;
printf("请输入十个需要排序的数:\n");
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
for(j=0;j<10;j++)
{
for(k=0;k<j;k++)
{
if(a[j]<a[k])
{
temp=a[k];
a[k]=a[j];
a[j]=temp;
}
}
}
printf("冒泡排序后的顺序为:\n");
for(l=0;l<10;l++)
{
printf("%d\n",a[l]);
}
}
13.字符串的读取和输出(C中)
#include"stdio.h"
#include"string.h"
int main()
{
char b[100];
gets(b);
printf("输入的字符数组为:\n");
puts(b);
}
14. C和C++中除数为0
C语言:不报错,运行时程序异常。
#include"stdio.h"
int main()
{
int a=100,b=0;
int c=a/b;
printf("输出的除法结果为:%d\n",c);
}
C++语言:同样不报错,运行程序异常。
15. strcat\strcpy\strncpy的用法
strcat的数组1定义的长度必须足够大,以便能容纳链接后的新字符串,否则会出现问题----实验中不断输出链接后的语句,并非正常输出一句后停止。
#include"stdio.h"
#include"string.h"
int main()
{
char str1[30]={"People's *"};// 长度为30的时候会报错,40或更大则正常输出
char str2[15]={"Mao *"};
printf("%s\n",strcat(str1,str2));
}
strcpy(str1,str2) 同样也是将str2的内容复制到str1中,且1的数组大小必须足够大。
strncpy(str1,str2,n)将str2中最前面的n个字符复制到str1中,取代str1中原有的最前面n个字符;复制的字符数不应该多与str1中原有的字符数。
16. strcmp\strlen\strlwr\strupr的用法
printf("%d\n",strcmp(str1,str2));
strcmp: 如果str1=str2,则函数值为0; 如果str1>str2,则返回值为一个正数; 如果str1<str2,则返回值为一个负数。
比较的规律:英文字典中位置靠后的为大,例如computer>compare; 小写字母比大写字母大,例如:DOG<dog;空格的作用:str 1<str1;
中文字符:也是按照ascii码值来进行比较;
数字: 直接比较大小,大于返回1,小于返回-1.
strlen: 函数值为字符串实际长度,不包含'\0',但是包含空格。
printf("%d\n",strlen(str1));
strlwr\strupr则是直接将字符串变为全部小写或者全部大写:
printf("%s\n",strlwr(str1));
printf("%s\n",strupr(str1));
17.统计单词的个数代码
#include"stdio.h"
#include"string.h"
int main()
{
char a[100];
int i,num=0,word=0;
printf("请输入一段文字:\n");
gets(a);
printf("输入的字符段为:%s\n",a);
printf("输入的字符段长度为:%d\n",strlen(a));
for(i=0;a[i]!='\0';i++)
{
if(a[i]==' ') //未出现新单词的情形
{
word=0;
}
else if(word==0) //前一字符为空格,即新单词出现
{
word=1;
num++;
}
}
printf("本段文字中的单词数目为:%d\n",num);
return 0;
}
18. 找出三个字符串中的最大者
#include"stdio.h"
#include"string.h"
int main()
{
char a[20], a1[3][20];
int i;
printf("请输入三个字符串:\n");
for(i=0;i<3;i++)
{
gets(a1[i]);
}
if(strcmp(a1[0],a1[1])>0)
{
strcpy(a,a1[0]);
}
else
{
strcpy(a,a1[1]);
}
if(strcmp(a,a1[2])<0)
{
strcpy(a,a1[2]);
}
printf("输入的字符串最大的为:%s\n",a);
return 0;
}
CMD中的C语言编译、链接方法 & 上述程序运行结果:
gcc:
gcc -c test.c -o test.o
gcc test.o -o test.exe
vc:
cl (/c /TC /O1 /MD) test.c
link test.obj
19.选择排序法(调试技巧:C语言需要在开始处声明程序变量,否则会报莫名其妙的错误,C++才能在任意处声明变量。)
对于10个数字而言,先将10个数字中的最小数与a[0]对换,再将a[1]到a[9]中最小的数与a[1]对换.......
#include"stdio.h"
int main()
{
int a[5],i,j,k,m,temp=0; //c编译器的原因,此语句必须放在最前面
printf("请输入五个数字,以回车键结束。\n");
for(i=0;i<5;i++)
{
scanf("%d\n",&a[i]);
}
for(j=0;j<5;j++)
for(k=j+1;k<5;k++)
{
if(a[j]>a[k])
{
temp=a[j];
a[j]=a[k];
a[k]=temp;
}
}
for(m=0;m<5;m++)
printf("选择排序之后的结果为:%d\n",a[m]);
}
20. 局部变量&全局变量
局部变量:
main()函数中定义的变量m,n也只能在主函数中有效,而非因为在主函数中定义而对整个文件或程序有效;主函数也不能使用其他函数中定义的变量。
不同程序中可以使用相同名字的变量;
形式参数也属于局部变量;
全局变量:函数内定义的是局部变量,函数外定义的是全局变量。作用域从定义位置到文件结束。C程序设计全局变量首字母大写(习惯)。
非必要时不要使用全局变量,原因如下:
全局变量的全部执行过程中都占用存储单元,而非需要时开辟;
它使得函数的通用性降低,因为在移植时需要考虑外部变量对于函数的影响;
过多的全局变量降低了程序的清晰性;
全局变量与局部变量重名的时候,在局部变量的作用范围内,外部变量将被屏蔽。
21. 变量的存储类别
从变量的生存周期来区分,可以分为静态存储方式&动态存储方式。静态是指程序运行期间由系统分配固定的存储空间的方式,动态则是指程序运行期间根据需要进行分配存储空间的方式。(分别对应全局变量 & 局部变量、函数形式参数、函数调用时的现场保护和返回地址)
C语言中,变量和函数的基本属性是:数据类型 & 数据的存储类别(auto\static\register\extern)。
auto: 局部变量,包括形参,函数中定义的变量。都动态的分配存储空间,程序调用结束即自动释放;
static: 静态局部变量。有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即所占用存储单元不释放,在下一次函数调用时直接使用上次调用结束时的值。(如果不讲静态局部变量赋初值,则编译时自动赋初值为0或者空字符)
以下程序反映了static的保留作用,编译程序结果如下。
#include"stdio.h"
int main()
{
int fun(int);
int a=2,i;
for(i=0;i<3;i++)
printf("%d",fun(a));
return 0;
}
int fun(int a)
{
int b=0;
static int c=3;
b=b+1;
c=c+1;
return(a+b+c);
}
register:一般情况下,包括静态存储和动态存储方式的值都是放在内存中的。但如果有一些变量使用频繁,因为存取变量值需要花费不少的时间,因此C语言运行将局部变量的值放到CPU的寄存器中,需要时直接从寄存器中取出,而不需要去内存中,从而可以提高执行效率。示例如下:
#include"stdio.h"
int main()
{
long fac(long);
long i,n;
scanf("%ld",&n);
for(i=1;i<=n;i++)
printf("%ld!=%ld\n",i,fac(i));
}
long fac(long n)
{
register long i,f=1;
for(i=1;i<=n;i++)
f=f*i;
return f;
}
只有局部自动变量和形式参数能作为寄存器变量,其他如全局变量不行,函数调用结束释放寄存器。
局部静态变量不能定义为寄存器变量。
extern:在函数外部定义的全局变量,作用域为定义处--》程序结尾。如果在定义点之前想引用该外部变量,则在引用前用关键字extern对该变量做”外部变量声明“即可。例如:
int max(int , int)
extern A,B; //在此处进行声明即可
printf("%d\n",max(A,B));
int A=13,B=-8;
main函数以上定义的全局变量,是可以被整个工程所调用的,需要在外部用extern关键字声明。
相反,static所定义的全局变量,仅限于本文件引用,而不能被其他文件引用。
22. 内部函数 & 外部函数
内部函数,与全局变量一样,在前添加关键字static即可,仅适用于本文件引用,从而不担心重名问题。
外部函数,添加extern关键字。
23. 预处理命令
宏:
C语言提供的预处理功能主要包括:宏定义、文件包含、条件编译。
宏名一般采用大写字母表示,宏定义可以引用已经定义的宏名,从而进行层层置换。宏定义只做字符替换,并不分配内存空间。带参数的宏定义并不止简单的字符替换,还要进行参数替换。
文件包含:
头文件不用.h结尾,而改为.c或者没有后缀名结尾都是可以的,.h只是能更好的表示此文件的性质。
<>是到系统存放C库函数头文件的目录中寻找,这称为标准方式;” “号包含方式则优先到用户当前目录中寻找,找不到再按标准方式寻找。如果不在当前目录中,则应该给出路径,例如:
#include "C:\Martin\user_data\files1.h"
include的文件在预编译后与调用文件已经成为一个文件,因而此时需要注意文件中变量的作用域并未改变。
条件编译:
为何使用条件编译,而不是if语句。----采用条件编译可以减少被编译的语句,从而减少目标程序的长度,减少运行时间。特别是当编译条件较多时,目标程序长度可以大大减少。
24. 指 针
25. 结构体 & 共用体
”.“运算符在所有运算符中优先级最高,并且可以像普通变量一样进行各种运算,亦可以引用结构体变量成员的地址。
指向结构体类型数据的指针变量,首先指向的是第一个元素的起始地址,,执行p++之后增加的值为结构体数组的一个元素所占的字节数(对于利用数组存储多个对象的结构信息而言)。
26. 链表
如果不提供头指针,则整个链表都无法访问。
#include"stdio.h"
#define NULL 0
struct student
{
long num;
float score;
struct student *next;
};
int main()
{
struct student a,b,c,*head,*p;
a.num=10101; a.score=89.5;
b.num=10103; b.score=90;
c.num=10107; c.score=85;
head=&a; a.next=&b;
b.next=&c; c.next=NULL;
p=head;
do
{
printf("%ld %5.1f\n",p->num,p->score);
p=p->next;
}
while(p!=NULL);
}
malloc: void *malloc(unsigned int size); --->在内存的动态存储区中分配一个长度为size的连续空间,弱未能成功执行,则返回空指针NULL。
calloc: void *calloc(unsigned n, unsigned size); --->在动态内存中分配n个长度为size的连续空间,成功则返回分配起始地址的指针,否则NULL。
free: void free(void *p); --->释放由P指向的内存区域,无返回值。
27. sizeof和strlen
sizeof计算实际所占内存大小,包含'\0';strlen计算字符串的长度,以‘\0’结尾,不包括‘\0’。
#include "stdio.h"
#include"string.h"
int main()
{
char a[]={'0','1','2','3','\0'};
char b[]={'0','1','2','3','\0','2','5','8','7'};
printf("%d\n",sizeof(a));
printf("%d\n",strlen(a));
printf("%d\n",sizeof(b));
printf("%d\n",strlen(b));
}
输出结果为:
28. 如何判定一个整数有几位
#include "stdio.h"
int main()
{
int a,n=0;
printf("请输入一个数:");
scanf("%d",&a);
while(a!=0)
{
n++;
a=a/10;
}
printf("该数字的位数为:%d\n",n);
}
29. 静态链表
所有节点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为静态链表。
队列为线性表,仅能在队尾进行插入,队首进行删除操作;链表为非线性结构,每个元素都包含了值以及另外一个指针,是一种常用的存储结构;栈则为仅允许在一端进行操作的特殊线性表。
linux内核所包括的五个子系统: 进程调度、内存管理、虚拟文件系统、网络接口和进程间通讯。
建立链表的函数如下所示:
#include"stdio.h"
#include"malloc.h"
#define NULL 0
#define LEN sizeof(strct student)
struct student
{
long num;
float score;
struct students *next;
};
int n;
struct student *creat(void)
{
struct studnet *head;
struct student *p1,*p2;
n=0;
p1=p2=(struct student *)malloc(LEN);
scanf("%ld,%f",&p1->num,&p1->score);
head=NULL;
while(p1->num!=0)
{
n=n+1;
if(n==1)
head=p1;
else p2->next=p1;
p2=p1;
p1=(struct student*)malloc(LEN);
scanf("%ld,%f",&p1->num,&p1->score);
}
p2->next=NULL;
return(head);
}
链表的插入函数:
struct student *insert(struct student *head,struct student *stud)
{
struct student *p0,*p1,*p2;
p1=head;
p0=stud;
if(head=NULL)
{
head=p0; p0->next=NULL;
}
else
{
while((p0->num>p1->num)&&(p1->next!=NULL))
{
p2=p1;
p1=p1->next;
}
if(p0->num<=p1->num)
{
if(head==p1)
head=p0;
else
p2->next=p0;
p0->next=p1;
}
else
{
p1->next=p0;
p0->next=NULL;
}
n=n+1;
return(head);
}
}
链表元素的删除函数:
struct student *del(struct student *head,long num)
{
struct student *p1,*p2;
if(head==NULL)
printf("\nlist id null! \n");
goto end;
p1=head;
while(num!=p1->num&&p1>next!==NLL)
{
p2=p1;
p1=p1->next;
}
if(num==p1->num)
{
if(p1==head)
head=p1->next;
else
p2->next=p1->next;
printf("delete:%ld\n",num);
n=n-1;
}
else
printf("%ld not been found! \n",num);
end;
return(head);
}
30.程序的存储空间问题
一般认为在c中分为这几个存储区:
1栈 - 有编译器自动分配释放
2堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
3全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束释放。
4另外还有一个专门放常量的地方。 - 程序结束释放
在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的 "adgfdf "这样的字符串存放在常量区。
比如:
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc ";栈
char *p2; 栈
char *p3 = "123456 "; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456 "); 123456\0放在常量区,编译器可能会将它与p3所指向的 "12345
31. strlen & sizeof & 转义字符
#include"iostream"
#include"string"
using namespace std;
int main()
{
char aa[]="absc\n\\\t\0\b\a\r\0";
cout<<"sizeof的值为:"<<sizeof(aa)<<endl;
cout<<"strlen的值为:"<<strlen(aa)<<endl;
return 0;
}
可以看出:sizeof计算的是整个数组的长度,包括系统为字符串自动所添加的'\0',也计算在内。 如果制定了数组的大小,则以指定大小为准。
strlen计算的是实际的有效字符长度,以'\0'作为计算的结尾,即使后面还有字符,也不计算在内。