关于C语言数据类型的十个问题
2018-01-23 21:38
204 查看
在学习c的数据类型是,有很多疑惑和问题,在这里提一些问题并注上自己的理解和看法。
1、
什么是结构,怎么定义结构?
通俗的讲就是打包封装,把一些有共同特征的变量封装在内部,并通过一定方法修改内部变量。
定义结构变量的一般格式为:
struct 结构名
{
类型
变量名;
类型
变量名;
...
} 结构变量;
例如,struct
stuff
{
char job[20];
int age;
float height;
};
struct stuff Huqinwei;
就是完整的一次定义。structstuff是结构体数据类型名,相当于int。{}表示在大括号中的内容也称为“成员列表”或“域表”,成员列表中的数据类型可以是基本变量类型和数组类型,或者是一个结构体类型。
2、什么是指针的类型?
什么是指针所指向的类型?
我们只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。然后把指针声明语句中的指针名字和名字左边的指针声明符 *去掉,剩下的就是指针所指向的类型。比如:
(1)int *ptr;
指针的类型是int *
指针所指向的类型是int
(2)char *ptr;
指针的类型是char *
指针所指向的的类型是char
(3)int **ptr;
指针的类型是 int **
指针所指向的的类型是 int *
(4)int (*ptr)[3];
指针的类型是 int(*)[3]
指针所指向的的类型是 int()[3]
(5)int *(*ptr)[4];
指针的类型是 int *(*)[4]
指针所指向的的类型是 int *()[4]
3、什么是入栈、出栈,什么是栈区?
栈的结构是“先进后出“的,就像堆积木一样,第一根放在最底层的地面上,然后一根一根往上堆。前一个放上去的总是被后一个放上去的压在底下。那我当我再想里面放一根的时候,总不能放中间或者放底下吧。所以要往上面加东西的时候,就得放在最上面。
以上就是进栈的原理,怎么出栈呢,很简单,直接从”积木”的最顶端取下来就行了。
接下来讲程序,由上面的分析我们可以知道一个道理,对于栈的操作,栈顶的元素很重要(也就是积木最上面的那根)。为什么呢。无论是出栈还是进栈,都跟那哥们有直接的联系。你想啊,如果要是有元素要进栈的话,那么它就不能当“老顶”了,那老顶之位就要交给压在它上头那位了;如果出栈呢,它也不能当老顶了,老顶之位就要交到原来压在它底下的那个。
所以一般的栈都将栈顶的那个元素所在的位置(内存地址–数组类型的,或者指针—节点类型的)视为栈的栈顶~!通过它来对栈进出进行操作。
而栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
4、联合体和结构体的区别
联合体是一种构造数据类型,其用途为:使几个不同类型的变量共占一段内存(相互覆盖)
结构体是一种构造数据类型,其用途为:把不同类型的数据组合成一个整体(自定义数据类型)
结构体变量所占内存长度是各成员占的内存长度的总和。
联合体变量所占内存长度是各最长的成员占的内存长度。
联合体每次只能存放多个变量中的一种。
联合体变量中起作用的成员是最后一次存放的成员,
在存入新的成员后原有的成员失去了作用!
5、什么是volatile?
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。所以volatile应该解释为“直接存取原始内存地址”,“易变的”这种解释简直有点误导人。
6、局部变量的作用域
1
int main()
2
{
3
int i=2,j=3,k;
4
k=i+j;
5
{
6
int k=8;
7
printf(“%d\n”,k);
8
}
9
printf(“%d\n”,k);
10
}
在上面的代码中,第四行的k值为五,它的作用域为3-9行。第六行的k的值为8,它的作用域为6-7行。但是在6、7时,值为8的k,用我的理解是拥有更高的等级,所以第7行打印出来的k值为8。
7、定义和声明的区别
定义就是编译器创造一个对象,然后给这个对象一个名字和一个地址,并将这个名字和地址绑定。总的来说,定义就是创造性质的,从无到有。比如:int i;定义一个i变量并给一个地址。
而声明就是说明性质的。比如externint i;就是说明要引用外部变量i到该处。即此变量(函数)是在别处定义的,要在此处引用。
8、typedef和#define的区别
#define是宏,没有参加编译,在预处理的时候就被替换掉了。typedef是编译阶段的一部分。它的意义是单一的。typedef参加编译和链接,是重命名,可以为枚举结构体等重新命名,提高代码整洁。
总体来说#define是死的,它只会替换,而typedef是活的,它参与到编译中。
9、static对不同变量的作用
用static修饰局部变量时,在第一次调用时进行赋值、计算。在之后的调用中(第二次、第三次)只会在上次计算的值后进行计算,而不会再次赋值。
用static修饰全局变量时,会减小其作用域。比如没有static时,变量可在多个文件中使用,但用static修饰时,就变味了只对本源文件可见。
10、extern的用法
在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问)。为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明:
extern 函数原型;
这样,在源文件B里也可以调用那个函数了。
注意这里的用词区别:在A里是定义,在B里是声明。一个函数只能(也必须)在一个源文件里被定义,但是可以在其它多个源文件里被声明。定义引起存储分配,是真正产生那个实体。而声明并不引起存储分配。打一个粗俗的比方:在源文件B里声明后,好比在B里开了一扇窗,让它可以看到A里的那个函数。
1、
什么是结构,怎么定义结构?
通俗的讲就是打包封装,把一些有共同特征的变量封装在内部,并通过一定方法修改内部变量。
定义结构变量的一般格式为:
struct 结构名
{
类型
变量名;
类型
变量名;
...
} 结构变量;
例如,struct
stuff
{
char job[20];
int age;
float height;
};
struct stuff Huqinwei;
就是完整的一次定义。structstuff是结构体数据类型名,相当于int。{}表示在大括号中的内容也称为“成员列表”或“域表”,成员列表中的数据类型可以是基本变量类型和数组类型,或者是一个结构体类型。
2、什么是指针的类型?
什么是指针所指向的类型?
我们只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。然后把指针声明语句中的指针名字和名字左边的指针声明符 *去掉,剩下的就是指针所指向的类型。比如:
(1)int *ptr;
指针的类型是int *
指针所指向的类型是int
(2)char *ptr;
指针的类型是char *
指针所指向的的类型是char
(3)int **ptr;
指针的类型是 int **
指针所指向的的类型是 int *
(4)int (*ptr)[3];
指针的类型是 int(*)[3]
指针所指向的的类型是 int()[3]
(5)int *(*ptr)[4];
指针的类型是 int *(*)[4]
指针所指向的的类型是 int *()[4]
3、什么是入栈、出栈,什么是栈区?
栈的结构是“先进后出“的,就像堆积木一样,第一根放在最底层的地面上,然后一根一根往上堆。前一个放上去的总是被后一个放上去的压在底下。那我当我再想里面放一根的时候,总不能放中间或者放底下吧。所以要往上面加东西的时候,就得放在最上面。
以上就是进栈的原理,怎么出栈呢,很简单,直接从”积木”的最顶端取下来就行了。
接下来讲程序,由上面的分析我们可以知道一个道理,对于栈的操作,栈顶的元素很重要(也就是积木最上面的那根)。为什么呢。无论是出栈还是进栈,都跟那哥们有直接的联系。你想啊,如果要是有元素要进栈的话,那么它就不能当“老顶”了,那老顶之位就要交给压在它上头那位了;如果出栈呢,它也不能当老顶了,老顶之位就要交到原来压在它底下的那个。
所以一般的栈都将栈顶的那个元素所在的位置(内存地址–数组类型的,或者指针—节点类型的)视为栈的栈顶~!通过它来对栈进出进行操作。
而栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
4、联合体和结构体的区别
联合体是一种构造数据类型,其用途为:使几个不同类型的变量共占一段内存(相互覆盖)
结构体是一种构造数据类型,其用途为:把不同类型的数据组合成一个整体(自定义数据类型)
结构体变量所占内存长度是各成员占的内存长度的总和。
联合体变量所占内存长度是各最长的成员占的内存长度。
联合体每次只能存放多个变量中的一种。
联合体变量中起作用的成员是最后一次存放的成员,
在存入新的成员后原有的成员失去了作用!
5、什么是volatile?
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。所以volatile应该解释为“直接存取原始内存地址”,“易变的”这种解释简直有点误导人。
6、局部变量的作用域
1
int main()
2
{
3
int i=2,j=3,k;
4
k=i+j;
5
{
6
int k=8;
7
printf(“%d\n”,k);
8
}
9
printf(“%d\n”,k);
10
}
在上面的代码中,第四行的k值为五,它的作用域为3-9行。第六行的k的值为8,它的作用域为6-7行。但是在6、7时,值为8的k,用我的理解是拥有更高的等级,所以第7行打印出来的k值为8。
7、定义和声明的区别
定义就是编译器创造一个对象,然后给这个对象一个名字和一个地址,并将这个名字和地址绑定。总的来说,定义就是创造性质的,从无到有。比如:int i;定义一个i变量并给一个地址。
而声明就是说明性质的。比如externint i;就是说明要引用外部变量i到该处。即此变量(函数)是在别处定义的,要在此处引用。
8、typedef和#define的区别
#define是宏,没有参加编译,在预处理的时候就被替换掉了。typedef是编译阶段的一部分。它的意义是单一的。typedef参加编译和链接,是重命名,可以为枚举结构体等重新命名,提高代码整洁。
总体来说#define是死的,它只会替换,而typedef是活的,它参与到编译中。
9、static对不同变量的作用
用static修饰局部变量时,在第一次调用时进行赋值、计算。在之后的调用中(第二次、第三次)只会在上次计算的值后进行计算,而不会再次赋值。
用static修饰全局变量时,会减小其作用域。比如没有static时,变量可在多个文件中使用,但用static修饰时,就变味了只对本源文件可见。
10、extern的用法
在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问)。为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明:
extern 函数原型;
这样,在源文件B里也可以调用那个函数了。
注意这里的用词区别:在A里是定义,在B里是声明。一个函数只能(也必须)在一个源文件里被定义,但是可以在其它多个源文件里被声明。定义引起存储分配,是真正产生那个实体。而声明并不引起存储分配。打一个粗俗的比方:在源文件B里声明后,好比在B里开了一扇窗,让它可以看到A里的那个函数。
相关文章推荐
- 关于2147217913 从 char 数据类型到 datetime 数据类型的转换导致 datetime 值越界 的问题解决方法
- 关于数据表类型(Table Type)的问题
- 关于MysQL中写入日期类型数据失败的问题
- 关于Silverlight对匿名类型数据绑定的问题及其解决方法
- 学点 C 语言(16): 数据类型 - 关于常量的前缀、后缀
- 关于数据仓库的十个最长问的问题
- 关于2147217913 从 char 数据类型到 datetime 数据类型的转换导致 datetime 值越界 的问题解决方法
- (转)关于数据类型转换的有趣问题
- ms sql到mysql的移植:关于数据类型移植的一些问题
- 关于Silverlight对匿名类型数据绑定的问题及其解决方法
- C# winform关于datagridview中的列的数据类型转换问题
- 关于数据仓库的十个最长问的问题
- 关于jquery中ajax数据返回类型问题
- 关于boost中数据类型转化问题
- 关于C#数据类型之间转换的问题!
- 关于C语言类型问题
- 在学习.net中的小问题,关于oledb 的日期数据类型
- 关于codeigniter的xmlrpc的类在进行数据交换时的类型问题
- 关于数据仓库的十个最长问的问题
- 关于C#数据类型之间转换的问题