C语言基础(一)

参看: 《C程序设计语言》第二版

上面的参考书籍是主要的学习手段,下面只是针对一些特定的问题进行论述,这些特定的问题,书中可能没有提到。

一个对象的类型决定着该对象可取值的集合以及可以对该对象施行的运算。


问题1:我们知道基本的数据类型有四种char,int,float,double。 类型修饰符也有四种short, long, signed, unsigned。 类型修饰符和基本数据类型的组合并不是都是有效的,其中修饰符是可以并存的,前提是这种表示是有意义的,比如”unsigned long int”,还有,修饰符或者基本类型定义的顺序是无关的,比如“unsigned long int”和“long int unsigned ”是等同的,这些组合详细可以参考《C程序设计语言》第二版的第二章。现在的问题是char类型能否表示所有的标准的ASCII码表的值?

答:基本的数据类型都有默认的类型修饰符,但是到底是哪个类型修饰符是依赖机器的,char类型就是个例子。signed char的取值范围是-128~127, unsigned char 的取值范围是0~255。标准的ASCII码表只使用了7位,它的取值范围是0~127。从上面的分析可以得知char类型能表示所有的ASCII码标的值。

补充:const的修饰符是后来加上的,对于这个修饰符我们也会有一个问题。


问题2:指针类型的变量定义不同于基本类型变量的定义。基本类型变量的定义基于两部分,前半部分是基本类型、类型修饰符和存储类型(auto,static等 ,后面关于这个还有几个问题),第二部分是变量名。指针类型变量的定义是分为三个部分,第一部分和基本类型变量的定义的前半部分是相同的,第二部分是符号”“,第三部分是变量名。比如,我们定义一个整型指针类型的变量”int p;”。我们的问题是const char * p; char const * p; char * const p; 三个表示方式有什么差别?

答:要解决这个问题,我们需要清楚三件事情,基本类型的前半部分是否有顺序的问题?第二件事情是修饰符语义的表达范围?第三件事情 、*p 和 p 有什么区别?
基本类型的前半部分是不依赖顺序的,但是我们有一些编写习惯的问题,比如我们往往只会写”const int a;”,而不是“int const a;” 。
修饰符的语义表达范围涉及到刚刚我们定义的三部分,修饰符只能修饰之后的部分,比如说,如果const 在第一部分,那么const能修饰第二部分和第三部分,如果const 在第二部分和第三部分之间,那么const只能修饰第三部分。
*p和p是有区别的。 “*”是表示间接引用运算符,它不是类型修饰符,所以我把它放在了第二部分,严格意义上来说,第二部分和第三部分是不能有任何其他的修饰符的,但是后来出现了const,const的语义是用来保证变量空间值的不可更改性。*p和p代表的不同的意思,*p代指间接引用空间,p本身代表指针变量的空间。
从上面的论述我们很容易得出下面的三个结论:
1. const char *p 和 char const * p是等价的。
2. const char *p 表示const修饰 *p空间,所以意思是*p空间的值不能被修改。
3. char * const p表示const修饰p空间,所以意思是p空间的值不能被修改。

验证const char *p;

/*************************************************************************
    > File Name: main.c
    > Author: mhsheng
    > Mail:981065720@qq.com 
    > Created Time: Wed 16 Nov 2016 06:07:52 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
    char c[]    = "abcde";
    const char * pc = c;

    c[0]    = 'y';
    pc[0]   = 'x';

    exit(0);
}
针对上面的代码,如果使用gcc main.c我们会得到如下的错误:
main.c: In functionmain’:
main.c:18:2: error: assignment of read-only location ‘*pc’
  pc[0] = 'x';
  ^

验证char * const p;

/*************************************************************************
    > File Name: main.c
    > Author: mhsheng
    > Mail:981065720@qq.com 
    > Created Time: Wed 16 Nov 2016 06:07:52 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
    char        c[] = "abcde";
    char        d[] = "abcde";
    char * const    pc  = c;

    pc = d;

    exit(0);
}
针对上面的代码,如果使用gcc main.c我们会得到如下的错误:
main.c: In functionmain’:
main.c:18:2: error: assignment of read-only variable ‘pc’
  pc = d;
  ^

问题3: const在C语言中有什么用处?

答:const是后来才加入C语言标准中的,从某个方面来说它是后妈生的孩子,因为是后妈生的,所以这个孩子会很调皮(简单地说就是它的使用语义场景并不是都是定义好的),对于调皮的孩子我们的处理方式是,只关心一些正常的CASE使用,不关心一些开发中不会用到的场景,比如说我想把一个const指针强制转换成一个非const的指针,我认为这是非法使用,const严格意义上说不是变量修饰符,它是用来限定不同通过该变量来修改变量所指向的内存空间的值
在C语言中,有三种用法:
1. 修饰变量。
2.修饰函数参数。
3.修饰函数返回值。
在C++语言中,多了一种用法:
4.修饰成员函数,限定在成员函数中不可修改非静态成员变量的值。

依据我刚才对const的语义的理解,const修饰的int变量,不能作为数组的常量表达式。比如:

const int LEN = 10;
int a[LEN] = {0};

个人认为这是非法的,但是在C++中,这种行为确实是可行的,虽然C++上说了这种方式的N种好处,但是个人还是不推荐使用,从某种意义上来说LEN就是一个常量,但是依据我对const的理解,LEN其实还是一个变量,而数组的定义是需要常量表达式的,所以个人认为这是不科学的。产生这种分歧的根本原因是,const是后妈生的。


问题4:类型转换的规则是个非常复杂的过程,主要的原因是变量类型的所能表示的值集合空间是不一样的,有些值集合事有包含关系,可是有些集合只是有交叉。那么为什么会有类型转换的需求呢?

答:C语言中的多目操作符要求操作的对象类型必须保持一致,这样操作符产生的结果才会确定下来。简单的说为了防止二义性。如果没有类型转换,我们就无法知道一个整型数和一个浮点型想加,最终的结果是一个浮点型的还是一个整型的?
我们的转换使用从小的集合转到大的集合,从有符号转到无符号,从整型转到浮点型。这就是基本的转换方式,但是具体到特定情况,就会变得很复杂,如果是负值从小的类型转换到大的类型,高位是采用“符号扩展”,还是采用“0值填充”呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值