C语言深度学习——第一天
首先声明一下,在我们写的程序中,会使用到一个头文件# include <head.h>
因为,在linux系统编程的时候,会用到很多头文件,为此,我用一个头文件全部包含在一起,头文件内容如下:
# ifndef _OK_ # define _OK_ # include <stdio.h> # include <string.h> # include <errno.h> # include <stdlib.h> # include <time.h> # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # include <sys/types.h> # include <dirent.h> # include <pwd.h> # include <grp.h> # include <pthread.h> # include <semaphore.h> # include <signal.h> # include <linux/ipc.h> # include <sys/socket.h> # include <netinet/in.h> # include <arpa/inet.h> # include <sys/wait.h> # include <netdb.h> #define LOG(...) {char _bf[1024];snprintf(_bf,sizeof(_bf),__VA_ARGS__);\ fprintf(stderr,"%s",_bf);syslog(LOG_ERR,"%s",_bf);} #endif
编辑好了之后,放到/usr/include/下即可。
1. 使用__FILE__,__FUCTION__,__LINE__等宏能自动定位到程序执行到哪一个函数的哪一行,作为一个经典的调试方法,很容易被人忽略,也很重要。如下:
#include <stdio.h> void test() { printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__); } void test_1() { printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__); test(); } int main() { printf("1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n",1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10); printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__); test_1(); return 0; }
打印:
2. 对于malloc动态内存分配,现在只是给出一个实例,让大家有一个感性的认识,要知道malloc主要用来动态开辟内存空间的,一般malloc都是和free配对的。以后会专门讲解的。下面的一个实例是动态开辟一个一维数组,比较简单。
# include <stdio.h> # include <stdlib.h> void input(int *array,int len) { int i; printf("input %d numbers ",len); for(i=0; i<len; i++) { setbuf(stdin,NULL); scanf("%d",array+i); } } int main() { int n=0,i=0; int *a, array[n]; printf("input characters "); scanf("%d",&n); a = (int *)malloc(n*sizeof(int)); input(a,n); printf("the characters you input are "); for(i=0; i<n; i++) printf("%d ",a[i]); printf("\n"); printf("a = %p,array = %p\n",a,array); free(a); a = NULL; return 0; }
程序要注意几点:
- 在C99标准中,准许使用下面的做法,但是不推荐
int n = 0;
scanf(“%d”,&n);
int ch[n] ;
- 在两次连着输入的时候,注意清除键盘缓存,在linux下可以用setbuf(),在Windows下可以用fflush()等,关于清除缓存,以后会专门讲解。
- 再次强调,malloc一定要和free配对使用,如果申请的空间不释放,一次两次也许不会有什么错误,申请多了就会发生内存泄漏,系统崩溃等严重问题,所以不要抱有侥幸心理。释放之后,a就是一个野指针了,一般而言,要将其赋为空,这是一个很好的习惯,希望大家坚持。
3. 大家看看下面的程序的输出结果是什么?
# include <stdio.h> int main() { int a[5]={0x10111213,0x20212223,0x30313233,0x40414243,0x50515253}; printf("a[5]={0x10111213,0x20212223,0x30313233,0x40414243,0x50515253}"); printf("\na = %p\n&a = %p\n",a,&a); printf("a+1 = %p\n&a+1 = %p\n",a+1,&a+1); printf("&a[0] = %p\n&a[0]+1 = %p\n",&a[0],&a[0]+1); printf("\nsizeof(a) = %d\nsizeof(&a) = %d\n",sizeof(a),sizeof(&a)); printf("sizeof(&a[0]) = %d\nsizeof(&a[5]) = %d\n",sizeof(&a[0]),sizeof(&a[5])); printf("sizeof(&a[10]) = %d\n sizeof(a[5]) = %d\n\n",sizeof(&a[10]),sizeof(a[5])); return 0; }
输入结果:
为什么会这样呢?大家都知道a是一个数组名,准确的讲,a是该数组首元素的地址,而&a是什么呢?&a是整个数组的地址。就像一栋房子一楼的门卫室,如果门卫室坐落在***地方,则这个***既是门卫室的地址,也是整栋大楼的地址,它们的值相等,但是表示的意思不一样,这就解释了为什么a和&a都等于0xbff7aadc,而sizeof(a)等于20,sizeof(&a)却等于4,因为&a是一个指针变量,32位机下的都是占4个字节,由此,我们可以推出对于一位数组buf[],我们想求出里面元素的个数可以使用sizeof(buf) / sizeof(buf[0])。
对于a+1和&a+1,a+1则是第二个元素即a[1]的地址,这里的1表示一个数组单元,0xbff7aadc+4=0xbff7aae0;&a+1则是a[4]的下一个地址,此时的1表示的整个数组单元, 0xbff7aadc+4*5=0xbff7aaf0。
大家会有疑问,我们数组是a[5],应该最大为a[4],怎么会有a[5],a[10]啊?为什么没有产生溢出?因为在整个数组中我们只是申请了5个单元,虽然这5个单元后面的空间我们无法访问,但是,这些空间还是实实在在存在的啊!所以还是有地址的!
4. 下面的程序是实现简单的求m到n之间的素数,大家看看吧!
# include <stdio.h> int prime(int n) { int i,j; for(i=2; i<=n; i++) if(n%i==0) break; if(i==n) return 1; else return 0; } int main() { int i,j,m,n; printf("Please input the Prime min and max limitation you want to calculate: "); scanf("%d,%d",&m,&n); printf("The Prime of %d to %d limitation are ",m,n); for(i=m; i<=n; i++) if(prime(i)) printf("%d ",i); printf("\n"); return 0; }
打印:
5. 大家说说,浮点数能进行自增和自减运算吗?答案是肯定的,不信?我们做个实例测试一下。
# include <head.h> int main(int argc, const char *argv[]) { float i = 1.0; double j = 2.0; printf("i=1.0,++i = %f,j-- = %f\n",++i,j--); return 0; }
打印: