| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1095 人关注过本帖
标题:C的个人学习经验[给初学者的建议,牛们请绕道]
取消只看楼主 加入收藏
Windy0Winll
Rank: 2
来 自:走了
等 级:等待验证会员
帖 子:71
专家分:90
注 册:2010-8-26
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:2 
C的个人学习经验[给初学者的建议,牛们请绕道]
来论坛也有一段时间了,现在我的课程也比较多,以后可能也很少有时间再来论坛了。
其实我学c语言的时间也不长,并且也成了老菜鸟了。想想当时还是个超级新手的时候,那个痛苦啊。。。说实话,c语言是挺难学。我也说说c语言的学习经验。
  个人比较偏向于底层,所以在很多基本概念上掌握得比较扎实。不赞成完全不经思考就把问题发到论坛上来要答案,初学的时候写代码有语法错误我想每个人都是这样的,这个时候到是可以问问别人或老师,也可以仔细的看看书,发到论坛里问也不错。当水平有一定的提高了,不再像以前那么什么都不懂,这个时候有问题要自己解决。写过C代码的人有几个没有遇到过段异常?给自己的代码找错是个很好的锻炼机会,要在这些个机会慢慢的积累经验,记下一般有哪些情况产生段错误尽量避免以后再犯同样的错误。其实给代码排错是很要编程技巧的,比如说断言的运用。如果你懂了语法了,一遇到这种错误就问人,那以后真正编程的时候一遇到错误就措手无策。平常写写比较常用的代码,把它保存到某个文件夹里,用的时候直接复制就好了。下面给出我以前学习的两个函数,是用来显示数据怎样在内存中存储的:
程序代码:
#define TEST 1


void
show_char(const void *p)
{
   
    const char ch = *(const char *) p;
    unsigned char mask = 0x80U;
   
    do  {
        putchar(  (ch &  mask) ? '1' : '0'  );
        if     (  (mask&0x11U)   )   putchar( ' ' );//每4位1个空格
        } while(  (mask >>= 1) >0   ) ;
    putchar( ' ' );
   
}

void
show_(const void *p,unsigned int size,const char *to_show)
{
           
    #if TEST==1
    #define _STEP (-1)
    const char *stop  = (const char*)p -1,
               *start = stop + size  ;
    #else
    #define _STEP  1
    const char *start = (const char*)p,
               *stop  =  start + size ;
    #endif
    unsigned int i = 0;
   
    puts(  (to_show)?(to_show):(" ")  );
    do  {
        show_char( start );
        putchar(  (++i & 3)?(' '):('\n')  );//每8位2个空格,每32位换行
        } while(  (start+=_STEP) != stop  );

}
不要看这两个函数很简单,到用处还比较大。我用它来学过内存对齐,可变参函数的形参是如何传递的。我想很多人都知道右移>>运算符,它在操作符号数和无符号数是不一样的,用这两个函数可以很直观的看出来。我记得以前在写math.h里面的一些函数时,这2个函数给了我很大的帮助。当你觉得水平再一次提高的时候,可以经常到论坛里和别人交流,学习学习别人的好的技巧等,还能交到不少朋友.当你成为老鸟的时候或着大牛的时候,觉得不要蔑视新手.您想想您自己是怎么过来的,只不过走在别人的前面,用时间沉淀下来的经验比人多些罢了,真的,没有其它什么了.菜鸟只要有毅力,至少成为一般的牛只是时间的问题.

刚学C的时候,我一直觉得写图形程序很神圣,要很高的水平才能涉足,总是想什么时候能写个俄罗斯方快,或着5子棋等.我记得我的第一个图形程序是俄罗斯方块,花了我好几天的时间去学习TC的那个图形库,边写边查每个函数的使用说明,可能用了1个星期的时间才把它完成.虽然基本功能都实现了,但现在觉的那个程序好幼稚.感觉写那个图形程序是有写收获,但不大.后来有个朋友要我帮他写个5子棋,有了第一次的经验,这个程序只写了1天,实现了悔棋的功能,那个时候我链表还不怎么懂,用数组很麻烦的实现了这个功能.这以后,我也没再写过图形程序.写图形函数并不难,但是很费时间,收获也不太大.写图形程序还不如花点时间来扎实自己的基本工.

真正让我觉得有所提高的是在实现 一个128位数的程序.从想写这个程序到完成可能花了1个星期.我用的是一个结构,
程序代码:
typedef struct int128{
        unsigned char status;//状态
        union {
              unsigned long v32[2*N+1]; //32位形式用来计算
              unsigned long long v64[N];//64位形式用来存取
              }val;
        }int128;
  
当时我是用的 求反加1 的方式来表示负数,那样很容易就能实现了各种位运算,加,减,乘.就是除法和求模不好实现.到目前我还是对我的那个除法(求模和除法是用同一个函数实现的)实现不满意.如果大家谁有比较好的实现方法,可以把思路贴上来.
总之,我觉得写图形函数,还不如写下面这些函数:设计一个64位浮点数(1位符号,8位指数,55位尾数或者自己规定)的四则运算及 与体统的double(或long long)之间的转换.我想这样一个程序并不比一个图形程序简单吧!!
大家有好的方法可以帖出代码功其他人学习学习。


大家学习愉快!!!

[ 本帖最后由 Windy0Winll 于 2010-9-15 17:20 编辑 ]
搜索更多相关主题的帖子: 经验 绕道 学习 
2010-09-15 17:17
Windy0Winll
Rank: 2
来 自:走了
等 级:等待验证会员
帖 子:71
专家分:90
注 册:2010-8-26
收藏
得分:0 
我帮您解释一下:
char *c[] = {//这里,[]运算符的优先级要比*的高,所以这里 可以这样写char*(c[]),也就是说,c[]可以看出c是一个数组,有4个元素; 然后把c[]看成一个整体,我们有C来表示,这样变成了 char *C,
  "enter",//c[0]                  //这样每个C就是一个字符指针了.
  "new",//c[1]
  "point",//c[2]
  "first"//c[3]
};


char **cp[] = {c+3,c+2,c+1,c};
同上,我们可以这样写, char * (* (cp[]) ),cp是一个数组,并且每个数组的元素是一个指针.现在我们用PC来代替(*cp[]),是不是变成了char *PC,这样PC也是指向一个字符的指针.
cp:数组
  内存中的数据 ... | cp[0] | cp[1] | cp[2] | cp[3] | ...cp表示的是数组,每个元素指向 另一个数组c
                                         
               ... | c[3]  |  c[2] |  c[1] |  c[0] | ... c也是一个数组,每个元素指向 一个字符串的首地,在内存中的顺序是c[0],c[1],c[2],c[3]前面那个顺序只是我打不出斜箭头
                                         
                 "first"     "point"   "new"  "enter"      

char ***cpp = cp;
这一句把cp[0]的地址(数组cp的首地址赋值给cpp).

printf("%s",**++cpp); 首先,++cpp;这个时候cpp指向的是cp[1],*++cpp表示的是引用了++cpp的对象cp[1],这个时候可以看成这样:++cpp,printf("%s",*cp[1]);而cp[1]指向的是c[2],
   把*cp[1]用c[2]来代替,变成了++cpp,printf("%s",c[2]);上面,我们看出c[2]是指向字符串"point"的,故输出point.
printf("%s",*--*++cpp+3);按照优先级我给加上括号,  (*(--( *(++cpp) ))) +3;++cpp现在是指向的是cp[2](上面已经指向了c[1]),故把*(++cpp)用cp[2]来代替,变成了
(*(--( cp[2] ))) +3;cp[2]指向的是c[2](这里你把c[2]理解成c+2.然后在减少1,变成了c+1,即c[1]);然后在自减1,所以--cp[2]指向的是c[2]前面个那元素c[1];用c[1]代替,变成了*c[1],
*c[1]是指向字符串"enter"首地址,指向第一个字符'e'的地址,在这个地址+3,现在是指向了后面那个'e';然后把这个地址传给printf函数,故打印的是er.

...后面的我不解释了,解释起来太麻烦了.

悄悄地来。。。 然后悄悄地走。。。。。。
2010-09-15 19:04
Windy0Winll
Rank: 2
来 自:走了
等 级:等待验证会员
帖 子:71
专家分:90
注 册:2010-8-26
收藏
得分:0 
回复 2楼 飞剑嗔
只要理解下面几点:

1. 数组都会指针来解释,数组只是写起来比较简便.如arr[n]将被解释为 *(arr+n);所以前面还可以写成n[arr],解释为 *(n+arr);
2. 如果p是指针的话,那么*p是对p所指向对象的引用.如int i, *p=&i;那么p所指向的对象是i,这样*p和i的完全等价的,所有能有i的地方,全部可以换成*p;
3. 对于多级指针,其实就只用了上面两点.只是指来指去的不好理解.多自己写写这样的代码就能很快理解了的.

[ 本帖最后由 Windy0Winll 于 2010-9-15 19:14 编辑 ]

悄悄地来。。。 然后悄悄地走。。。。。。
2010-09-15 19:13
快速回复:C的个人学习经验[给初学者的建议,牛们请绕道]
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018517 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved