1、C/C++程序设计

C和C++关系

1、C++程序中调用C编译后的函数,为什么要加external “C”?

C++支持函数重载而C语言不支持函数重载,故函数被C++编译后和被C编译之后的名字不同;

引入external C用来解决函数名字匹配问题;

2、头文件ifdef/define/endif有什么用?

防止该头文件被重复引用

3、C和C++各自特点?

C是一种结构化语言,重点在于算法和数据结构。考虑如何通过一个过程(函数),对输入进行运算处理得到输出;
C++考虑如何构造一个对象模型,让模型能够契合与之对应的问题域,通过获取对象的状态信息得到输出或实现过程控制;

C/C++程序编译过程[1]

当我们进行编译的时候,要使用一系列的工具,我们称之为工具链,其中包括:
预处理器cpp
编译器gcc/g++
汇编器as
链接器ld


一个C/C++程序编译过程包括下面几个阶段:


预处理    预处理器cpp将对源文件中的宏进行展开。
编译     gcc将c文件编译成汇编文件。
汇编     汇编器as将汇编文件编译成机器码。
链接     链接器ld将目标文件和外部符号进行连接,得到一个可执行二进制文件。


下面以一个很简单的 hello.c 来探讨这个过程
 
#include <stdio.h>
#define BUFSIZE 1024


int main(int argc, char *argv[])
{
    char hello[BUFSIZE] = "Hello my friend!";
    printf("%s\n", hello);
    return 0;
}


### 预处理(预处理器 cpp)


[butbueatiful@xt myhello]$ gcc -E hello.c -o hello.i

[butbueatiful@xt myhello]$ cpp hello.c -o hello.i


我们用vi打开 hello.i 可以看到有如下内容:
......
int main(int argc, char *argv[])
{
    char hello[1024] = "Hello my friend!";
    printf("%s\n", hello);
    return 0;
}
......
我们可以看到,文件中宏定义 BUFSIZE 出现的位置被 1024 替换掉了,其它的内容保持不变。


### 编译器将 .i 文件编译成汇编文件


[butbueatiful@xt myhello]$ gcc -S hello.i # 得到汇编文件hello.s


### 汇编器将汇编文件编译成机器码(汇编器 as)
[butbueatiful@xt myhello]$ gcc -c hello.s -o hello.o

[butbueatiful@xt myhello]$ as hello.s -o hello.o


hello.o中为目标机器上的二进制文件


用 nm 查看文件中的符号:
[butbueatiful@xt myhello]$ nm -a hello.o
00000000 b .bss
00000000 n .comment
00000000 d .data
00000000 n .note.GNU-stack
00000000 t .text
00000000 a hello.c
00000000 T main
U puts
既然已经是二进制目标文件了,能不能执行呢?
[butbueatiful@xt myhello]$ chmod +x hello.o
[butbueatiful@xt myhello]$ ./hello.o
-bash: ./hello.o: cannot execute binary file
其实这时 puts 前面的 U 表示这个符号的地址还没有定下来,T表示这个符号属于代码段。ld连接的时候会为这些带U的符号确定地址。


### 链接(链接器 ld)
链接需要指定库的位置。通常程序中会有很多的外部符号,因此需要指定的位置就会很多。
不过,我们只需要调用 gcc 即可,ld会自己去找这些库的位置。
[butbueatiful@xt myhello]$ gcc hello.o -o hello # 得到可执行文件hello

预处理、const与sizeof

const与#define相比有什么不同

const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能产生意料不到的错误;
有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序中只能使用const常量而不使用宏常量,即const常量完全取代宏常量;

C++中const有什么作用

  1. 定义常量;
  2. 修饰函数形式参数;当输入参数为用户自定义类型和抽象数据类型时,应该将“值传递”改为“const &传递”,可以提高效率。
  3. const修饰函数的返回值;如给“指针传递”的函数返回值加const,则返回值不能被直接修改,且该返回值只能被赋值给加const修饰的同类型指针。
  4. const修饰类的成员函数;任何不会修改数据成员的函数都应用const修饰,这样,当不小心修改了数据成员或调用了非const成员函数时,编译器都会报错。int get(void)const;

sizeof和strlen之间的区别

  1. sizeof操作符的结果类型是size_t,在头文件中的typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小;
  2. sizeof是运算符,strlen是函数;
  3. sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以“\0”结尾的。sizeof还可以用函数做参数;
  4. 数组做sizeof的参数不退化,传递给strlen就退化为指针;
  5. 大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度;
  6. strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占内存的大小;
  7. sizeof后如果是类型必须加括号,如果是变量名可以不加括号。这是因为sizeof是个操作符而不是个函数;
  8. 当使用了一个结构类型或变量时,sizeof返回实际的大小。当时用以静态的空间数组时,sizeof返回全部数组的尺寸。sizeof操作符不能返回被动态分配的数组或外部的数组的尺寸;
  9. 数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。在C++中传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小。如果想在函数内知道数组大小,进入函数后用memcpy将数组复制出来,长度由另一个形参穿进去;
  10. 计算结构变量的大小就必须讨论数组对齐问题;
  11. sizeof操作符不能用于函数类型、不完全类型或位字段;

一个空类占多少空间?多重继承的空类?

class A
{};
class B
{};
class B :public A
{};
class C :public virtual B
{};
class D :public A, public B
{};
空类占空间1,多重继承的空类占空间1;虚继承涉及虚表(虚指针),占空间4;

内联函数和宏定义

内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中。而宏只是一个简单的替换。
内联函数要进行参数类型检查,这是内联函数跟宏相比的优势。
inline是指嵌入代码,就是在调用函数的地方不做跳转,而是把代码直接写到那里去。
inline一般用于以下情况:
  1. 一个函数不断被重复调用;
  2. 函数只有简单的几行,且函数内不包含for、while、switch;

指针与引用

指针和引用的差别

  1. 非空区别;引用不为空。
  2. 合法性区别;指针需测试,防止其为空,引用不需要测试合法性。
  3. 可修改区别;指针可以被重新赋值,引用指向初始化时被指定的对象,以后不能改变,但指向对象其内容可以改变。
  4. 应用区别;
以下情况应该使用指针:一是考虑到存在不指向任何对象的可能;二是需要能够在不同的时刻只想不同的对象;如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么应该用引用。

循环、递归与概率


STL模板与容器

STL有以下优点:

可以方便、容易地实现搜索数据或对数据排序等一系列算法;

调试程序时更加安全和方便;

STL一些概念定义:

模板类:正规名称叫泛型,一个类的模板叫做泛型类,而一个函数的模板叫泛型函数;

STL标准模板库:一些聪明人写的一些模板,现已成为每个人使用的标准C++语言中的一部分;

容器:可容纳一些数组的模板类,STL中有vector、set、map、multimap和deque等容器;

向量:基本数组模板;

游标(Iterator):这是一个奇特的东西,是一个指针,用来指向STL容器中的元素,也可以指向其他的元素;

面向对象

class和struct有什么区别

C语言的struct与C++的class区别:struct只是作为一种复杂数据类型定义,不能用于面向对象编程;
C++中的struct和class的区别:对于成员访问权限以及继承方式,class中默认的是private的,而struct中则是public的。class还可以用于表示模板类型,struct则不行;

编写类String的构造函数、析构函数和赋值函数

类String的原型:

class String
{
  public:
    //普通构造函数
    String(const char *str=NULL);
    //拷贝构造函数
    String(const String &other);
    //析构函数
    ~ String(void);
    //赋值函数
    String & operate=(const String &other);
  private:
    //用于保存字符串
    char *m_data;
};

构造函数

String::String(ocnst cahr *str)
{
    if(str==NULL)
    {
       m_data=new char[1];
       *m_data='\0';
    }
    else
    {
       int length=strlen(str);
       m_data=new char[length+1];
       strcpy(m_data,str);
    }
}

析构函数

String::~String(void)
{
    delete[] m_data;
}
拷贝构造函数

String::String(const String &other)
{
       int length=strlen(other.m_data);
       m_data=new char[length+1];
       strcpy(m_data,other.m_data);
}

赋值函数

String & String::operate=(const String &other)
{
    //检查自赋值
    if(this==&other)
      return *this;
    //释放原有的内存资源
    delete[] m_data;
    //分配新的内存资源,并复制内容
    int length=strlen(other.m_data);
    m_data=new char[length+1];
    strcpy(m_data,other.m_data);
    //返回本对象的引用
    return *this;
}

什么是多态

多态性可以简单概括为“一个接口,多种方法”;

重载和覆盖的区别

虚函数总是在派生类中被改写,这种改写被称为“override”(覆盖)。

   override是指派生类重写基类的虚函数,重写的函数必须有一致的参数表和返回值;

overload约定成俗译为“重载”,是指编写一个与已有函数同名但是参数表不同的函数;

友元

友元函数是一种定义在类外部的普通函数,但需要在类体内进行说明,为与该类的成员函数加以区别,在说明前加以关键字friend。友元不是成员函数,但是可以访问类中的私有成员,其作用在于提高程序的运行效率,但是它破坏了类的封装性和隐藏性,使得非成员函数可以访问累的私有成员。

友元可以使一个函数,成为友元函数;也可以是一个类,称为友元类;

写一程序,设计一个点类Point,求两个点之间的距离

class Point
{
  provate:
  float x,y;
  public:
  point(float a=0.0f,float b=0.0f):x(a,b){};
  friend float distance(Point &leftm,Point &right);
}

float diatance(Point &left,Point &right)
{
  return ((left.x-right.x)^2+(left.y-right.y)^2)^0.5;
}

描述模板类的友元重载,代码实现

#include<iostream>
using namespace std;
template <class T>
class Test;
template <class T>
ostream& operator<<(ostream& out, const Test<T> &obj);
template <class T>
class Test
{
private:
	int num;
public:
	Test(int n=0)
	{
		num = n;
	}
	Test(const Test<T> &copy)
	{
		num = copy.num;
	}
	friend ostream &poerator << <>(ostream &out, const Test<T> &obj);
};

template<class T>
ostream &operator<<(ostream &out, const Test<T> &obj)
{
	out << obj.num;
	return out;
}

int main()
{
	Test<int> t(2);
	cout << t << endl;
	return 0;
}

继承与接口


位运算与嵌入式编程


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
原名《Turbo C/C++ for Windows 集成实验与学习环境》,现在已全面支持最新操作系统VISTA,它是从事一线教学的大学教师根据C/C++ 初学者的特点,量身定制的一个简单易用的 C/C++程序设计学习与实验软件(支持TC2/TC3、GCC、VC6四种编译器,没有使用日期限制)。与软件配套的《 C/C++程序设计教程(配有同步实验、流程控制语句动画演示、提供教程所有程序实例、实验、作业的源代码(全部用VC6编译器调试通过))》融入了作者多年的教学和学习经验、编程建议、编程感悟,新增读书笔记功能有利用户 记录教程的重点、难点、学习心得体会,针对用户学习教程遇到的问题开通了疑难问题解答论坛等,同时,为了便于C语言学习,加入C语言学习指导、入门程序实例、典型源程序、典型的函数算法,课程设计指导、课程设计源程序、 Visual C++6.0英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的英文对照、二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案与分析等大量的学习资源。另外 “编程日记” 功能可以让你记录你的 C 语言学习历程, “资料管理” 功能让你大量的下载资料不再难找。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值