编程的基础知识点

          几年没写程式了,有些比较基础的地方有点模糊.写个笔记.

变量的声明定义:

1、在头文件的类外面定义。这样定义的变量可认为是对外公开的全局变量定义,因为一般别人引用你的头文件,是可以直接看到的,所以是公开的,在类外面就是全局的,只要你包含这个头文件,就会分配空间。
2、在头文件类里面定义。这是公开非全局。生命周期和类对象生命周期一致。
3、cpp函数外定义。这是非公开全局。非公开的意思是,一般来说两个子系统合作,是不会提供cpp文件的,只会提供头文件和lib库。
4、函数内定义,就是局部变量。

除了第4种,其他三种在别的地方都可以引用,只不过第3种要加external。

在哪里定义变量是有讲究的,如果全部定义全局变量,会有两个弊端:
1、浪费内存空间。因为只要你包含了它,不管你有没有用到,都会分配空间。
2、不安全,破坏封装性。全局变量很容易被读取。这也就是为什么会有private这个东西。

关于break,return,continue:

break是退出for while等循环一次退单层,return是退出包含循环的函数退出整个函数,continue是退出本次循环进行下次循环

因为break一次只能跳出一层循环,所以如果想从多层嵌套中迅速跳出有以下方法:
1、goto语句
while(condition1)
{
  while(condition2)
  {
    while(condition3)
      if(some disaster)
        goto quit;
  }
}
quit: 
   ;
2、设置一个状态标志:

bool flag = true;
for (int i = 0; i < datagridview.Rows.Count&&flag ; i++) 
                { 
                    for (int j = 0; j < datagridview.Columns.Count&&flag ; j++) 
                    { 
                        if (datagridview.Columns[j].Visible == true && !System.Convert.IsDBNull(datagridview[j, i].Value)) 
                        { 
                            string cellcontain = System.Convert.ToString(datagridview[j, i].Value).ToUpper(); 
                            int index = cellcontain.IndexOf(condition.ToUpper(), 0); 
                            if (index >= 0) 
                            { 
                                datagridview.CurrentCell = datagridview[j, i]; 
                                iscontinue = false; 
                               flag  = false;
                            } 
                        } 
                        else 
                            continue; 
                    } 
                }

3.作一个方法
用return就可以了。

关于static:

          用static修饰的成员是描述整个非静态类的,不管实例化多少个对象,在内存中只存在一份数据,所有
的对象都可以使用它。如果是静态类的成员,那么不用实例化,直接使用就好比如Math类.

关于new:

一/当非指针对象(或者说构造函数出了问题)用NEW新建对象会报错"尝试引用已删除的函数"

Union 是C/C++语言中的一种结构类型,用于定义可共享内存的数据变量的一种方式,初次使用Union联合体时可能会遇到以下问题:

 错误 C2280 Union : 尝试引用已删除的函数 

 警告 C4624 “Grade”: 已将析构函数隐式定义为“已删除”

不多说,上代码:

// TemplateExe1.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
#include <iostream>
#include "atlstr.h"
using namespace std;
union Grade {
    int number;
    CString mark;
    bool pass;
    
}uGrade;
int main()
{
    uGrade.number = 90;
    printf("%d",uGrade.number);
    getchar();
    
    return 0;
}
此错误的原因:CString 是一个类,有自己的构造函数,析构函数。

解决方案:CString 换成基本的数据类型:char 等

我们分析一下:

Union的一大特征在于,一个Union类中的所有数据共享同一段内存。
如果union类的成员包含自己的构造函数,析构函数,那么同一Union类的成员在初始化时,就有可能会执行不同的构造函数。
这是无法预料的。
所以,我们在定义Union类时要尽量避免成员变量是对象(含有自己的构造函数)。

二/摘抄一段:FAQ: C++中定义类的对象:用new和不用new有何区别? - 狂涛爱蕞 - 博客园:

#include <iostream>

using namespace std;

class A

{

private:

int n;

public:

    A(int m):n(m)//初始化列表,必须要使用列表初始化的几种情况 - Dobben - 博客园.主体意思就是初始化列表在构造函数之前动作.

    {

    }

    ~A(){}

};

int main()

{

     A a(1);  //栈中分配

    A b = A(1);  //栈中分配

    A* c = new A(1);  //堆中分配

  delete c;

    return 0;

}

第一种和第二种没什么区别,一个隐式调用,一个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,而栈中内存的分配和释放是由系统管理,而堆中内存的分配和释放必须由程序员手动释放,所以这就产生一个问题是把对象放在栈中还是放在堆中的问题,这个问题又和堆和栈本身的区别有关:

这里面有几个问题:

1.堆和栈最大可分配的内存的大小

2.堆和栈的内存管理方式

3.堆和栈的分配效率

首先针对第一个问题,一般来说对于一个进程栈的大小远远小于堆的大小,在linux中,你可以使用ulimit -s (单位kb)来查看一个进程栈的最大可分配大小,一般来说不超过8M,有的甚至不超过2M,不过这个可以设置,而对于堆你会发现,针对一个进程堆的最大可分配的大小在G的数量级上,不同系统可能不一样,比如32位系统最大不超过2G,而64为系统最大不超过4G,所以当你需要一个分配的大小的内存时,请用new,即用堆。

其次针对第二个问题,栈是系统数据结构,对于进程/线程是唯一的,它的分配与释放由操作系统来维护,不需要开发者来管理。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储单元会被自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,不同的操作系统对栈都有一定的限制。 堆上的内存分配,亦称动态内存分配。程序在运行的期间用malloc申请的内存,这部分内存由程序员自己负责管理,其生存期由开发者决定:在何时分配,分配多少,并在何时用free来释放该内存。这是唯一可以由开发者参与管理的内存。使用的好坏直接决定系统的性能和稳定。

由上可知,但我们需要的内存很少,你又能确定你到底需要多少内存时,请用栈。而当你需要在运行时才知道你到底需要多少内存时,请用堆。

最后针对第三个问题,栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率 比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在 堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会 分 到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

由上可知,能用栈则用栈。

举个简单的例子:
class Point
{
 private:
   int x;
   int y;
 public:
   void Set(int a,int b)
   { x=a; y=b; }
   void Print()
   { cout<<"("<<x<<","<<y<<")"<<endl; }
};

void main()
{
  Point p1;
  Point *p2=new Point();
  p1.Set(1,2);
  p2->Set(4,5);
  
  p1.Print();
  p2->Print();
  delete p2;
}
对象p1,p2的定义方式有何本质不同?用哪种方式比较好?
p1有系统创建并释放,你不要担心会出现内存泄露,但是生命期只有在本区域的大括号内,出了大括号就没用了。P2是指针,要自己释放,用不好很危险,用好了功能强大,因为他可以赋值给全局的变量,一下子从局部变量变成全局变量,还能把对象作为函数返回值。

关于全局变量:

#include <QCoreApplication>
#include "abc.h"
#include <QDebug>
QString message;//写在.cpp的函数外,或者.h文件的class外就是全局变量了.但是最好就用static全局变量,更安全稳妥.
int main(int argc, char *argv[])
{   
 QCoreApplication a(argc, argv);     
 qDebug()<<("hello world!");   
 return a.exec();
}
 

关于extern:

        extern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。只有当声明也是定义时,声明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为 extern:
extern double pi = 3.1416; // definition
虽然使用了 extern ,但是这条语句还是定义了 pi,分配并初始化了存储空间。只有当 extern 声明位于函数外部时,才可以含有初始化式,在函数体内部写extern double pi = 3.1416;是会报错的.

由于头文件包括在多个源文件里。而且变量的定义仅仅能出现一次,所以在头文件里, 仅仅能够声明不能够出现定义.extern声明也可以写在.c里面.

实验如下:

  

///

keil c的extern跟qt的又不一样.

头文件声明:

extern extern uint8_t  abc[56];

在此头文件的c文件或者其他包含此头文件的地方定义:

 uint8_t  abc[56]={0x00};

此处如果定义时和qt一样不带变量类型会报错未定义类型,应该说规范更严谨了.

 

头文件不能用static要用extern

在C语言,C++和makefile中,include所做的事情实际上是将被include的文件内容原样复制到使用include的文件中

因此在一个头文件中定义一个static变量,然后该头文件被多个cpp文件包含后,包含该头文件的cpp文件实际上会各自拥有独立的同名变量(等同于分别在多个cpp文件中定义同名static变量)

具体验证
在头文件test.h中定义静态变量static int a

//头文件test.h
#pragma once
 
 
static int a;
在头文件t0.h中包含头文件test.h,并声明一个可以改变变量a的函数

//头文件t0.h
#pragma once
 
 
void change();
//t0.cpp文件
#include"test.h"
#include<iostream>
#include"t0.h"
 
 
void change()
{
    
    a = 100;
 
    std::cout  << "in t0.cpp  " << "a = " << a << " &a = " << &a << std::endl;
    
}
在main.cpp中包含test.h和t0.h

#include"test.h"
#include"t0.h"
using namespace::std;
 
 
int main(int argc, char* argv[])
{
    
    a = 200;
    change();
    cout << "in main  " << " a = " << a << "  &a = " << &a << endl;
 
 
    system("pause");
    return 0;
 
}

运行结果为:

 根据运行结果我们可以看出,两个cpp文件中的同名变量a实际上是只在自己头文件范围内有效的(有不同的地址,也就是等同于在各自的cpp中定义static变量,该变量只在定义的cpp文件中有效)

在头文件中定义全局变量
根据include的性质,如果要在头文件中定义一个全局变量是不可以直接定义的。正确的做法应该是在头文件中以extern声明一个全局变量,并在包含该头文件的其中一个源文件中定义该变量,这样其他文件就可以正常使用该全局变量了。
————————————————
版权声明:本文为CSDN博主「Ch0s1n_1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Ch0s1n_1/article/details/127330998

关于全局函数

比如一个函数在某个.h或者.c里面声明为extern  void abc();

那么,在其他任意一个.c文件里定义都可以(假设定义这个函数的文件是a.c),但是在b.c要用abc()时就要在b.h里面再次声明一下void abc();.不然会报错----Warning:Implicit declaration of function “xxx” is invalid in C99.函数“xxx”的隐式声明在C99中无效,重点是“声明”。

C语言规范中,函数定义要出现在函数调用之前,否则就会报错!如果调用前没有定义,就要在调用前做一下声明,函数的定义就可以放到被调用的后边。总之:
1.先定义函数-----再调用函数
2.先声明函数-----再调用函数-------最后定义函数

如果只声明函数而没有定义函数(函数的具体实现部分),那么就会直接报错:
Error: L6218E: Undefined symbol function“XXX” (referred from main.o)!
如果没有声明,但是已经定义了函数,只是会出现警告:
Warning: #223-D: function “XXX” declared implicitly!
关于警告Warning:Implicit declaration of function “xxx” is invalid in C99!,说明函数已经定义,是函数的声明存在问题,检查以下几点:
1.函数的声明放在头文件(H文件);
2.函数定义在源文件(C文件);
3.函数的名称是否一致(大小写要一致);
4.声明被调用函数的头文件已经被包含(#include);
5.函数声明的先后顺序(被调用的函数声明放在执行调用函数的声明前面)
6.如果以上检查都没有问题,查看H头文件的头部,如下代码:
————————————————
版权声明:本文为CSDN博主「family20102010」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/family20102010/article/details/126155338

关于变量的定义位置:

在VC中,变量定义在头文件中为public时,其对象可见.而在CPP中声明定义不能加public private修饰符.但其默认为private只在本cpp中可见.

在C++中,变量的定义应在.cpp源文件中,头文件中只可声明变量。

如果变量 int a ;定义在.cpp中,但在.h文件中用到了a;则在.h文件中声明extern int a;

如果一定要在.h文件中定义,则可以这样定义 inline int  a;

原因:.h文件是不参与编译的,所以,如果在.h文件中定义了变量,那么在链接过程就会出错。

文件的标准命名法:  C++ 语言文件: 头文件.h 源文件.cpp



 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值