关闭

读朱兆祺攻破C语言之一----编程基本概念

标签: const全局变量局部变量大小端typedef
748人阅读 评论(0) 收藏 举报
分类:

下面文章来自朱兆祺编写的《攻破c语言笔试和机试难点》的pdf,加上部分自己验证程序。在此感谢这位牛人为我们详尽讲解了C语言细节和难点问题。

1、#include《 》和include“ ”区别?

     #include《》用来包含开发环境提供的库文件,而#include“ ”用来包含.c、.cpp文件所在目录下头文件。注:#include“”包含的路径大于#include《》,一般建议使用#include" "包含头文件。

 

2、switch(c)中c的类型

      c支持类型整型或者可以转换整型的数据(int,long),而浮点型(float、double)是不支持

3、const用途

     1、防止一个变量值被改变,可以使用const关键字。定义该const变量时,通常对其赋值初始化,因为以后不允许再去改变它。

      2、对于指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const或二者同时指定为const。

      3、在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值。

        4、对于类的成员函数,若指定其为const类型,则表明是常数函数,不能修改类成员变量

       5、对于类的成员函数,有时候必须指定其返回值为const类型,以使其返回值不为“左值”。 个人不明白

4、#ifndef  、#define、#endif

       头文件中的#ifndef  、#define、#endif的作用?作用:

        1、在uboot、linux内核文件中经常看到,这些条件预编译多用于对代码的编译控制,增加代码的可裁剪性,通过宏定义可以轻松对代码进行裁剪。

         2、防止头文件被重复定义 。实例说明:

#ifndef __UART_H_
#define __UART_H_

/*函数说明*/

#endif //__UART_H_

5、全局变量和局部变量

        全局变量和局部变量在内存中的是否有区别?

         区别:初始化的全局变量存放在DATA段,未初始化的全局变量存放在BSS段而局部变量存放在堆栈中。提示:局部变量太大可能导致栈溢出,所以建议较大的数据定义全局变量(存放在mian函数外)。

6、函数调用中形参和实参

         函数的参数分为形参和实参两种。

       1、形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。

       2、实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。

形参:在定义函数时,函数名后面括号中变量名称。

实参:在主调用函数调用一个函数时,函数名后面括号中的参数(可以是表达式、变量、数值等)。

下面实例说明一下:

/* 比较大小  */

int max(int x , int y)

{

int z;

z=x>y?x:y;

return (z);

}

/*主函数*/

void main(void)

{

int a,b,c;

scanf("%d,%d",&a,&b);

c=max(a,b);

printf("%d\n",c);

}

其中mian函数中a、b是实参,而max()函数中x、y是形参。函数调用过程中:a值传递给x,b值传递给y。

函数的形参和实参具有以下特点: 
1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。 
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。 
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误,并且形参和实参的类型应该相同或者兼容,如果是不同的类型应该按照不同类型数值的规则进行转换,例如实参是3.5,但是形参是整数,应该按照转换规则将3.5转换成整形3赋值给形参 
4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参,实参和形参在内存中分别占用不同的内存单元。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。除非是实参和形参是地址传递(数组、指针)。

 7、大小端存储

       计算机的 数据存储方式由大端存储和小端存储两种。

     1、小端模式:内存的低地址存数据的低位,内存的高地址存数据的高位。即低低高高。

      2、大端模式:内存的低地址存放数据的高位,内存的高地址存数据的低位。即第高高低。

下面验证pc机的存储模式(在pc机运行c-free)

#include <stdio.h>
int main(void)
{
	int a = 0x12345678;
	char *p = (char *)(&a);
	if (*p == 0x78) 
	{
		printf("xiao duan!\n");
		printf("sizeof(a)  = %#x\n",sizeof(a));
		/*输出数据存储的详情*/ 
		printf("p = %#x,*p = %#x\n",p,*p);
		printf("p+1 = %#x,*(p+1) = %#x\n",p+1,*(p+1));
		printf("p+2 = %#x,*(p+2) = %#x\n",p+2,*(p+2));
		printf("p+3 = %#x,*(p+3) = %#x\n",p+3,*(p+3));
	} 
	else if (*p == 0x12) 
	{
		printf("da duan!\n");
		printf("sizeof(p)  = %#x\n",sizeof(p));
		/*输出数据存储的详情*/ 
		printf("p = %#x,*p = %#x\n",p,*p);
		printf("p+1 = %#x,*(p+1) = %#x\n",p+1,*(p+1));
		printf("p+2 = %#x,*(p+2) = %#x\n",p+2,*(p+2));
		printf("p+3 = %#x,*(p+3) = %#x\n",p+3,*(p+3));
	} 
	else 
	{
		printf("other!\n");
	}
	return 0;
}

运行结果

由运行结果可知:


如果是大端存储模式,正好相反。低地址0x22FF74存储数据高位0x12,高地址0x22FF77存储数据低位0x78。

8、用typedef命令已有类型

typedef是C/C++的一个关键字,可以用来给数据类型或函数类型定义一个别名,在编程中应用十分的广泛,本文详细介绍一下这个关键字。

(在此过程中,typedef并未创造新的类型,只是对已有的类型重新命名而已)。

1. typedef作用于数据类型

用法:typedef type-declaration synonym;

这样我们就可以直接用synonym来声明变量,和用type-declaration效果是一样的。不仅可以简化比较复杂的类型声明,还可以定义一些有意义的类型别名,增加程序的可读性。微软在这一块做的特别好。

例1:

        tyepdef  int     INTEGER

        tyepdef  float   REAL

         定义: int  i;float a   等同   INTEGER   i; REAL  a;

例2:typedef  struct

          {

            int  month;

            int  day;

            int year;

          }DATE

         声明新类型DATE,它代表上面指定的结构体类型。(如果没有typedef ,则DATE是结构体型的变量)。这时使用DATE定义变量:  DATE birthday;

          DATE  *p;

 

 

例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>   
                               
typedef unsigned int UINT;   
typedef struct tagSize   
{   
    UINT width;   
    UINT height;   
}SIZE, *PSIZE;   
                               
int main(int argc, char **argv)   
{   
    SIZE size;   
    size.width = 100;   
    size.height = 200;   
    std::cout << "size.width = " << size.width    
        << ", size.height = " << size.height << std::endl;   
                               
    PSIZE psize = &size;   
    std::cout << "psize->width = " << psize->width    
        << ", psize->height = " << psize->height << std::endl;   
                               
    return 0;   
}

1.1 可以用一个已经被定义的别名来定义另一个别名。例如:

1
2
type unsigned int UINT;   
type UINT *PUINT;

1.2 一个别名可以被重复定义多次,但必须保证每次的类型都相同。例如:

1
2
3
4
5
6
7
// OK   
typedef char Test1;   
typedef char Test1;   
                           
// error C2371: 'Test2' : redefinition; different basic types   
typedef char Test2;   
typedef int Test2;

1.3 typedef定义的别名仅仅在它的作用域内起作用。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostrem>   
                     
int main(int argc, char **argv)   
{   
    // OK   
    {   
        typedef int Test;   
        Test test = 100;   
        std::cout << "test = " << test << std::endl;   
    }   
                     
    // OK   
    {   
        typedef double Test;   
        Test test = 10.8;   
        std::cout << "test = " << test << std::endl;   
    }   
   return 0;   
}

2. typedef 作用于函数

可以用typedef来定义函数的别名。一般有两种用法,一种是定义函数名,另一种是定义函数指针。

1.1 定义函数名的别名。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>   
             
typedef void Func1(void);   
typedef int Func2(intint);   
             
// void proc1(void);   
Func1 proc1;   
             
// int proc2(int a, int b)   
 Func2 proc2;   
             
int main(int argc, char **argv)   
{   
    proc1();   
    proc2(2, 4);   
    return 0;   
}   
             
void proc1(void)   
{   
    std::cout << "void proc1(void)" << std::endl;      
}   
             
int proc2(int a, int b)   
{   
    std::cout << "int proc2(int a, int b)" << std::endl;    
    return (a + b);   
}

1.2 定义函数指针的别名。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>   
        
typedef void (*pFunc1)(void);   
typedef int (*pFunc2)(intint);   
        
void proc1(void)   
{   
    std::cout << "void proc1(void)" << std::endl;      
}   
        
int proc2(int a, int b)   
{   
    std::cout << "int proc2(int a, int b)" << std::endl;   
    return 0;   
}   
        
int main(int argc, char **argv)   
{   
    pFunc1 p1;   
    p1 = &proc1;   
    (*p1)();   
        
    // error C2440: '=' : cannot convert from 'int (__cdecl *)(int,int)' to 'pFunc1'   
    // p1 = &proc2;   
        
    pFunc2 p2 = &proc2;   
    (*p2)(2, 3);   
        
    return 0;   
}

 

 

 

 

 

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:121263次
    • 积分:1753
    • 等级:
    • 排名:千里之外
    • 原创:51篇
    • 转载:40篇
    • 译文:0篇
    • 评论:7条