C++的指针

2023-11-03

C++的指针

在C++中,指针被称为是C/C++中的精髓所在,指针是存放内存地址的一种变量,特殊的地方就在它存放的是内存地址。

计算机中的内存都是编址的,每个地址都有一个符号。指针是一个无符号整数,它是一个以当前系统寻址范围为取值范围的整数,声明指针和声明一个无符号整数实质上并无区别。

一、变量内存实质

(一)变量的实质

要理解指针,首先就要理解“变量”存储实质,内存空间图:

根据图中,内存只不过是一个存放数据的空间,可以将其理解成装水果的篮子、电影院的座位。在电影院中每个位置都有编号,而内存中要存放各种各样的数据,所以我们需要知道这些数据存放的位置。所以内存也需要像影院那样需要编号。也就是说内存编址(为内存进行地址编码)。内存按一个字节接着一个字节的次序进行编址,每个字节都有个编号,称为内存地址。

内存编址:

                               

程序中写下了语言声明:

int i;

char a;

它其实是内存中申请一个名为i的整形变量宽度空间(DOS 下的 16 位编程中其宽度为 2 个字节),和一个名为 a 的字符型变量宽度的空间(占 1 个字节)。

在内存中映象:

图中可看出,i在内存起始地址为6的上面申请了两个字节的空间(假设int的宽度为16位,不同系统中 int 的宽度可能是不一样的,最常用的win32环境下为4个字节)并将其命名为i。a在内存地址为8上申请一个字节的空间,并命名为a。这样我们就拥有两个不同类型的变量,看变量如何给变量进行赋值。

(二)赋值给变量

i=30;

a='p';

两个语句将30存入i变量的内存空间中,将'p'字符存进a变量的内存空间中,可以这样理解

将30存在以6为起始地址的两个字节空间里,a的内存地址为8上申请了一字节的空间存入了'p',那么变量i和a在哪里?

(三)变量位置

使用&i取i变量所在的地址编号,返回的是i变量的地址编号,(返回i变量地址编号)

#include <iostream>
#include <string>
using namespace std;
int main(){
   int i=30;
   cout<<"&i= "<<&i<<endl;
   cout<<"i= "<<i<<endl;
	return 0;
}

输出的&i的值为0x6ffe3c(windows 64位)就是我们图示中内存空间编码为6的内存地址。接下来就进入我们真正的主题——指针

二、指针

计算机中的内存都是编址的,每个地址都有一个符号,就像家庭地址或者IP地址一样。指针,是一个无符号整数(unsigned int),它是一个以当前系统寻址范围为取值范围的整数。声明指针和声明一个无符号整数实质上并无区别。

指针是存放内存地址的一种变量,特殊的地方就在它存放的是内存地址。因此,指针的大小不会像其他变量一样变化,只跟当前平台相关——不同平台内存地址的范围是不一样的,32位平台下,内存最大为4GB,因此只需要32bit就可以存下,所以sizeof(pointer)的大小是4字节。64位平台下,32位就不够用了,要想内存地址能够都一一表示,就需要64bit(但是目前应该没有这么大的内存吧?),因此sizeof(pointer)是8。

比如有天你说你要学习C++,要借我的这本 C++ Primer Plus,我把书给你送过去发现你已经跑出去打篮球了,于是我把书放在了你桌子上书架的第三层四号的位置。并写了一张纸条:你要的书在第三层四号的书架上。贴在你门上。当你回来时,看到这张纸条,你就知道了我借与你的书放在哪了。你想想看,这张纸条的作用,纸条本身不是书,它上面也没有放着书。那么你又如何知道书的位置呢?因为纸条上写着书的位置嘛!聪明!!!其实这张纸条就是一个指针了。它上面的内容不是书本身,而是
书的地址,你通过纸条这个指针找到了我借给你的这本书。

声明一个指向整型变量的指针的语句: int *pi;

pi是一个指针,其实它也是一个变量,与变量并没有实质的区别。

(说明:这里我假设了指针只占 2 个字节宽度,实际上在 32 位系统中,指针的宽度是 4 个字节宽的,即 32 位。)
由图示中可以看出,我们使用“int *pi”声明指针变量 —— 其实是在内存的某处声明一个一定宽度的内存空间,并把它命名为 pi。你能在图中看出pi 与前面的 i、a 变量有什么本质区别吗?没有,当然没有!肯定没有!!真的没有!!!pi 也只不过是一个变量而已嘛!那么它又为什么会被称为“指针”?关键是我们要让这个变量所存储的内容是什么。现在我要让 pi 成为具有真正“指针”意义的变量。请接着看下面语句:

pi=&i;

把i地址的编号赋值给pi。并在pi里面写上i的地址编号;

执行完 pi=&i 后,在图示中的内存中,pi 的值是 6。这个 6 就是i 变量的地址编号,这样 pi 就指向了变量 i 了。你看,pi 与那张纸条有什么区别?pi 不就是那张纸条嘛!上面写着 i 的地址,而 i 就是那本厚书C++ Primer Plus。你现在看懂了吗?因此,我们就把 pi 称为指针。所以你要牢牢记住:指针变量所存的内容就是内存的地址编号 ! 也会随着你不断的学习对这句话会理解的越来越深。我们就可以通过这个指针 pi 来访问到 i 这个变量了:

#include <iostream>
#include <string>
using namespace std;
int main(){
   int i=30;
   cout<<"&i= "<<&i<<endl;
   cout<<"i= "<<i<<endl;
   int *pi=&i;
   cout<<"*pi= "<<*pi<<endl;
	return 0;
}

pi 内容所指的地址的内容(读上去好像在绕口令了),就是 pi 这张“纸条”上所写的位置上的那本 “书”—— i 。你看,Pi 的内容是 6,也就是说 pi 指向内存编号为 6 的地址。*pi嘛,就是它所指地址的内容,即地址编号 6 上的内容了,当然就是 30 这个“值”了。所以这条语句会在屏幕上显示 30。我们的纸条就是我们的指针,同样我们的 pi 也就是我们的纸条!剩下的就是我们如何应用这张纸条了。如何用?下面的代码并正确理解含义。

#include <iostream>
#include <string>
using namespace std;
int main(){
   int a,*pa;
   a=10;
   cout<<"&a= "<<&a<<endl;
   cout<<"a= "<<a<<endl; 
   pa=&a;
   *pa=20;
   cout<<"*pa= "<<*pa<<endl; 
    cout<<"a= "<<a<<endl;
	return 0;
}

三、二级指针(指针的指针)

(一)二级指针,是一种指向指针的指针。我们可以通过它实现间接访问数据,和改变一级指针的指向问题。

                                                                                  

#include <iostream>
#include <string>
using namespace std;
int main(){
  	int i=30;
  	cout<<"&i= "<<&i<<endl;
  	cout<<"i= "<<i<<endl;
  	int *pi=&i;
  	cout<<"*pi= "<<*pi<<endl;
  	int* *ppi=&pi;
  	cout<<"**ppi= "<<**ppi<<endl;
  	cout<<endl;
  	**ppi=40;
  	cout<<"i= "<<i<<endl;
  	cout<<"*pi= "<<*pi<<endl;
  	cout<<"**ppi= "<<**ppi<<endl;
	return 0;
}

结果如下:

(二)间接数据访问

1.改变一级指针指向

#include <iostream>
#include <string>
using namespace std;
int main(){
  	int i=30;
  	int *pi=&i;
  	cout<<"一级指针*pi= "<<*pi<<endl;
  	int* *ppi=&pi;
  	cout<<"二级指针**ppi= "<<**ppi<<endl;
  	cout<<endl;
  	*pi=40;
  	cout<<"改变一级指针内容:*pi= "<<*pi<<endl;
  	cout<<"一级指针*pi= "<<*pi<<endl;
  	cout<<endl;
  	int b=10;
  	*ppi=&b;
  	cout<<"改变一级指针指向*pi= "<<*pi<<endl;
  	cout<<"二级指针**ppi= "<<**ppi<<endl; 
	return 0;
}

2.改变n-1级指针的指向

可以通过一级指针,修改0级指针(变量)的内容;

可以通过二级指针,修改一级指针的指向;

可以通过三级指针,修改二级指针的指向;

...

可以通过修改n级指针,修改n-1级指针的指向。

3.二级指针的步长

所以类型的二级指针,由于均指向一级指针类型,一级指针类型大小为4,所以二级指针步长也为4。

四、指针与数组

(一)指针与数组名

1.通过数组名访问数组元素

#include<iostream>
using namespace std;
int main(){
    int i,a[]={1,2,3,4,5,6,7,8,9,10};
    for(i=0;i<=9;i++)
        cout<<a[i]<<" ";
        cout<<endl;
    for(i=0;i<=9;i++)
        cout<<*(a+i)<<" ";
    return 0;
}

2.通过指针访问数组元素

#include<iostream>
using namespace std;
int main(){
    int i,a[]={1,2,3,4,5,6,7,8,9,10};
    int *pa;
    pa=a;
    for(i=0;i<=9;i++)
        cout<<pa[i]<<" ";
		cout<<endl;
    for(i=0;i<=9;i++)
        cout<<*(pa+i)<<" ";
    return 0;
}

3.数组名与指针变量区别

#include<iostream>
using namespace std;
int main(){
    int i,a[]={1,2,3,4,5,6,7,8,9,10};
    int *pa;
    pa=a;
    for(i=0;i<=9;i++){
    	cout<<*pa;
    	pa++;  //指针值被修改
	}
    return 0;
}

可以看出,这段代码也是将数组各元素值输出。不过,你把循环体{}中的 pa改成 a 试试。你会发现程序编译出错,不能成功。看来指针和数组名还是不同的。其实上面的指针是指针变量,而 数组名只是一个指针常量。

(二)指针数组

虽然说指针数组,但是本质上还是数组,数组中每一个成员时一个指针。

char *pArray[10];

pArray先与"[]"结合,构成一个数组,char*修饰数组内容,即数组的每个元素。

#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
    char *pArray[]={"apple","banner","cat","dog","egg"};
    for(int i=0;i<sizeof(pArray)/sizeof(*pArray);i++){
    	cout<<pArray[i]<<endl;
	} 
    return 0;
}

(三)二级指针与指针数组

1.指针数组名赋给二级指针的合理性

二级指针与指针数组名等价原因:

char  **p是二级指针

char* array[N];array=&array[0];  array[0]本身是char* 型

char **p=array;

#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
    char *pArray[]={"apple","banner","cat","dog","egg"};
    cout << "**********pArray[i]************" << std::endl;
    for(int i=0;i<sizeof(pArray)/sizeof(*pArray);i++){
    	cout<<pArray[i]<<endl;
	} 
	char **pArr=pArray;
	cout<<"***********pArr[i]****************"<<endl;
	for(int i=0;i<sizeof(pArray)/sizeof(*pArray);i++){
		cout<<pArr[i]<<endl;
	}
    return 0;
}

(三)完美匹配前提

数组名,赋给指针以后,就会少了唯独的概念,所以用二级指针访问指针数组,需要维度,也可以不需要。

#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
    cout << "**********one************" <<endl;
    int arr[10]={1};
    for(int i=0;i<10;i++){
    	cout<<arr[i]<<endl;
	}
	int *parr=arr;
	for(int i=0;i<10;i++)
		cout<<*parr++<<endl;
		
	cout<<"************two************"<<endl;
	char *str="banner";
	while(*str){
		cout<<*str++<<endl;
	}
	char* pArray[]={"apple","banner","cat","dog","egg",NULL};
	char **pa=pArray;
	while(*pa!=NULL){
		cout<<*pa++<<endl;
	}
    return 0;
}

五、堆空间与指针

(一)堆上的一维空间

1.返回值返回(一级指针)

char* allocSpace(int n){
    char *p=(char*)malloc(n);
    return p;
}

2.参数返回(二级指针)

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
int allocSpace(char **p,int n){
    *p=(char*)malloc(n);
    return *p==NULL?-1:1;
}
int main(){
    char *p;
    if(allocSpace(&p,100)<0){
        return -1;
    }
    strcpy(p,"banner");
    //cout<<p<<endl;
    printf("%s\n",p);
    free(p);
    return 0;
}

输出结果为:banner

3.堆上的二维空间

二维数组,是一种二维空间,但不是代表着二维空间就是二维数组;二维空间并不一定就是二维数组,但是可以具有数组的访问形式,但也已经远远不是数组的定义。

3.1使用指针做函数返回值

(1)当使用指针做为函数的返回值时,主函数处的char *p;将获得调用函数char *pf;的值,即一个地址值,如oxAE72。此时需要我们注意的是该地址值所指向的空间是否存在(即已向操作系统声明注册,不会被释放,即可能被其他操作修改);

(2)使用栈内存返回指针是明显错误的,因为栈内存将在调用结束后自动释放,而主函数使用该地址空间将很危险

char *GetMemory(){
    char p[]="banner";
    return p;
}
int main(){
    char *str=GetMemory();  //报错,得到一块已经释放的内存
    printf(str);
}

(3)使用堆内存返回指针,但需要注意的是内存泄露问题,在使用完成后在主函数中释放该段内存

char *GetMemory(){
    char *p=new char[100];
    return p;
}
int main(){
    char *str=GetMemory();
    delete[] str; //防止内存泄露问题
}

3.2使用指针做函数参数

1、有的情况下我们可能需要需要在调用函数中分配内存,而在主函数中使用,而针对的指针此时为函数的参数。此时应注意形参与实参的问题,因为在C语言中,形参只是继承了实参的值,是另外一个量(ps:返回值也是同理,传递了一个地址值(指针)或实数值),形参的改变并不能引起实参的改变。

2、直接使用形参分配内存的方式是错误的,因为实参的值并不会改变,下面则实参一直为NULL:

void GetMemory(char* p){
    char *p=new char[100];
}
int main(){
    char *str;
    GetMemory(str);
    strcpy(str,"hi");  //str=NULL;
}

3、由于通过指针是可以传值的,因为此时该指针的地址是在主函数中申请的栈内存,我们通过指针对该栈内存进行操作,从而改变了实参的值。

void Change(char *p){
    *p='a';
}
int main(){
    char a='a';
    char *p=&a;
    Change(p);
    printf("%c\n",a);
}

(4)根据上述的启发,我们也可以采用指向指针的指针来进行在调用函数中申请,在主函数中应用。如下:假设a的地址为ox23,内容为'a';而str的地址是ox46,内容为ox23;而pstr的地址是ox79,内容为ox46。

我们通过调用函数GetMemory,从而将pstr的内容赋给了p,此时p = ox46。通过对*p(ox23)的操作,即将内存地址为ox23之中的值改为char[100]的首地址,从而完成了对char* str地址的分配。 

void GetMemory(char** p) 
{ 
     char *p = new char[100]; 
}   
int main() 
{ 
    char a = 'a'; 
    char* str = &a; 
    char** pstr = &str; 
    GetMemory(pstr); 
    strcpy(str, "hi"); 
}

(5)注意指针的释放问题,可能形成悬浮指针。

当我们释放掉一个指针p后,只是告诉操作系统该段内存可以被其他程序使用,而该指针p的地址值(如ox23)仍然存在。如果再次给这块地址赋值是危险的,应该将p指针置为NULL。

调用函数删除主函数中的内存块时,虽然可以通过地址传递直接删除,但由于无法对该指针赋值(形参不能传值),可能造成悬浮指针,所以此时也应该采用指向指针的指针的形参。例如:

void MemoryFree(char** p) 
{ 
     delete *p; 
     *p = NULL; 
} 
int main() 
{ 
     char *str = new char[100]; 
     char *pstr = &str; 
     MemoryFree(pstr); 
} 

4.多几指针作为参数输出

void allocSpace(void ***p,int base,int row,int line){
    *p=malloc(row*sizeof(void*));
    for(int i=0;i<row;i++){
        (*p)[i]=malloc(base*line);
    }
}

六、const修饰指针

(一)const int *pi 与 int *const pi

#include<stdio.h>
int main(){
    int a=20;
    int b=30;
    const int *pi=&a;
    printf("const int *pi=%d\n",*pi);
    pi=&b;
    printf("const int *pi=%d\n",*pi);
    
    int *const pi2=&a;
    printf("int *const pi2=%d\n",*pi2);
    *pi2=10;
    printf("int *const pi2=%d\n",*pi2);
    return 0;
}

const int *pi = &a;这句代码中const 修饰的是*pi,将*pi定义为常量,所以给*pi重新赋值是非法的,而pi是普通的变量,可对其进行再赋值,如: pi = &b;我们再来看这句代码:int *const pi2 = &a;这句代码中const修饰的是 pi2,将pi2定义为常量,所以给pi2重新赋值是非法的,而*pi2则可以重新赋值。

  • 如果 const 修饰在*pi 前,则不能改的是*pi(即不能类似这样:*pi=50;赋值)而不是指 pi。
  •  如果 const 是直接写在 pi 前,则 pi 不能改(即不能类似这样:pi=&i;赋值)。

(1)int *pi指针指向const int i常量情况

#include<iostream>
int main(){
    const int i1=10;
    int *pi;
    pi=&i1;  //编译报错
    return 0;
}

分析:const修饰的是i1,直接访问的是i1,间接访问是*pi,*pi就有间接访问修改的风险,因此将*pi需要用const修饰,从而杜绝间接访问修改常量内存块的风险。const int *pi; 这样便能够编译通过,也可以强制转换 pi=(int*)(&i1),同样能够通过编译输出一样结果。

 

(2)const int *pi 指针指向 const int i1 的情况

#include <stdio.h>
int main(void)
{
    const int i1=40;
    const int * pi;
 
    pi=&i1;/* 两个类型相同,可以这样赋值。很显然,i1 的值无论是通过 pi 还是 i1 都不能修改的。 */
 
    printf("i1 = %d\n",i1);
    printf("pi = %d\n",pi);
    printf("*pi = %d\n",*pi);
    return 0;
}

(3)使用const int *const pi声明的指针

#include<iostream>
int main(){
    int i=10;
    const int *const pi=&i;
    return 0;
}

七、函数与函数指针

(一)函数多惨返回

(1)引列

写一个函数,同时返回两个正整数数据的和与差。在函数中,只有一个返回值,将如何实现

int foo(int *sum,int *diff,int a,int b);

(2)解法

当我们既需要通过函数返回值来判断函数调用是否成功,又需要把数据传递出来,此时,就需要用到多参数返回,多参返回都是通过传递调用空间中的空间地址来实现,例如:通过参数返回堆上的一维空间,二维空间和初始化指针。

(二)函数指针

(1)函数本质是一段可执行性代码段。函数名,则是指向这代码段的首地址。

#include<iostream>
void print(){
    printf("banner\n");
}
int main(){
    print();
    printf("%p\n",&print);
    printf("%p\n",print);
    int a;
    int *p=&a;  //函数也是一个指针
    return 0;
}

(2)函数指针变量定义与赋值

#include<iostream>
void print(){
    printf("banner\n");
}
void dis(){
    printf("banner\n");
}
int main(){
    void (*pf)()=print;
    pf();
    pf=dis;
    pf();
    return 0;
}

(3)函数指针类型定义

#include<iostream>
void print(){
    printf("banner\n");
}
void dis(){
    printf("banner\n");
}
typedef void (*PFUNC)();
int main(){
    PFUNC pf=print;
    pf();
    pf=dis;
    pf();
    return 0;
}

(4)应用

函数指针的一个用法出现在 菜单驱动系统中。例如程序可以提示用户输入一个整数值来选择菜单中的一个选项。用户的选择可以做函数指针数组的下标,而数组中的指针可以用来调用函数。

#include <stdio.h>
void function0(int);
void function1(int);
void function2(int);
int main()
{
    void (*f[3])(int) = {function0,function1,function2};
    //将这 3 个函数指针保存在数组 f 中
    int choice;
    printf("Enter a number between 0 and 2, 3 to end: ");
    scanf("%d",&choice);
    while ((choice >= 0) && (choice <3))
    {
        (*f[choice])(choice);
        //f[choice]选择在数组中位置为 choice 的指针。
        //指针被解除引用,以调用函数,并且 choice 作为实参传递给这个函数。
        printf("Enter a number between 0 and 2,3 to end: ");
        scanf("%d",&choice);
    }
    printf("Program execution completed.");
    return 0;
}
void function0(int a)
{
    printf("You entered %d so function0 was called\n",a);
}
void function1(int b)
{
    printf("You entered %d so function1 was called\n",b);
}
void function2(int c)
{
    printf("You entered %d so function2 was called\n",c);
}

(三)回调函数

(1)当我们需要排序时候,升序/降序,都是写死在函数中了,如果将程序以库的形式出现,将会是怎样?

#include<iostream>
using namespace std;
void selectSort(int *p,int n){
    for(int i=0;i<n-1;i++){
        for(int j=i+1;j<n;j++){
            if(p[i]<p[j]){
                p[i]=p[i]^p[j];
                p[j]=p[i]^p[j];
                p[i]=p[i]^p[j];
            }
        }
    }
}
int main(){
    int arr[10]={5,4,8,3,2,1,9,7,6,0};
    selectSort(arr,10);
    for(int i=0;i<10;i++)
        cout<<arr[i]<<" ";
    return 0;
}

(2)回调(函数做参数)

#include<iostream>
using namespace std;
int callBackCompare(int a,int b)
    return a<b?1:0;
void selectSort(int *p,int n,int(*pf)(int ,int)){
    for(int i=0;i<n-1;i++){
        for(int j=i+1;j<n;j++){
            if(pf(p[i]<p[j])){
                p[i]=p[i]^p[j];
                p[j]=p[i]^p[j];
                p[i]=p[i]^p[j];
            }
        }
    }
}
int main(){
    int arr[10]={5,4,8,3,2,1,9,7,6,0};
    selectSort(arr,10,callBackCompare);
    for(int i=0;i<10;i++)
        cout<<arr[i]<<" ";
    return 0;
}

本质:回调函数,本质也是一种函数调用,先将函数以指针的方式传入,然后,调用。这种写法的好处是,对外提供函数类型,而不是函数定义。这样我们只需要依据函数类型和函数功能提供函数就可以了。给程序的书写带来了很大的自由。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++的指针 的相关文章

  • BASIC 中的 C 语言中的 PeekInt、PokeInt、Peek、Poke 等效项

    我想知道该命令的等效项是什么Peek and Poke 基本和其他变体 用 C 语言 类似PeekInt PokeInt 整数 涉及内存条的东西 我知道在 C 语言中有很多方法可以做到这一点 我正在尝试将基本程序移植到 C 语言 这只是使用
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲

随机推荐

  • 基于深度学习的人脸表情识别(一)

    第一篇博客就不用Markdown 什么鬼 来写了 今天主要是被老板一通说 然后说两月看10篇paper 算了 还是丫丫自己先多码码论文吧 再加之这几天有开博的想法 就索性一起开了 顺道总结下最近看的一篇中文的 Facial Expressi
  • 【CPU】常见术语解释

    interrupt service routine ISR 中断服务程序 中断 指当CPU正在处理某件事情时 外部发生的某一事件 如一个电平的变化 一个脉冲沿的发生或 定时器计数溢出等 请求CPU迅速去处理 于是CPU暂时中止当前的工作 转
  • 【机器学习基础】Python机器学习入门指南(全)

    前言 机器学习 作为人工智能领域的核心组成 是计算机程序学习数据经验以优化自身算法 并产生相应的 智能化的 建议与决策的过程 一个经典的机器学习的定义是 A computer program is said to learn from ex
  • 计算机转换汉子英语,中英文切换(电脑怎么切换拼音打字)

    在打字时需要输入英文怎么切换 用搜狗等各类拼音法的话 不用切换就可自由地 中英 非常简单 没有人不知道吧 方法是 汉字状态时 按回车键就是英文字母 此时按空格键是汉字 谁能告诉我小键盘旁边 也就是全角和半角的旁边的中文和英文符号 切换的 c
  • vue-element-admin/template登录Request failed with status code 405

    问题 vue element admin vue admin template 登录不上 报错Request failed with status code 405 解决 main js的开发配置production修改为开发模式 deve
  • opencv 识别长方形_使用OpenCV检测图像中的矩形

    本文实例为大家分享了OpenCV检测图像中矩形的具体代码 供大家参考 具体内容如下 前言 1 OpenCV没有内置的矩形检测的函数 如果想检测矩形 要自己去实现 2 我这里使用的OpenCV版本是3 30 矩形检测 1 得到原始图像之后 代
  • shell基础语法

    1 变量 语法 变量名 变量值 PS 两边不能有空格 1 使用变量 变量名 ex Name wendy 声明变量 echo Name 或 echo Name 输出变量 ps 花括号可选 2 只读变量 readonly 变量 3 删除变量 u
  • maven明明本地仓库有依赖包,还会远程下载的问题

    我今天在无网的环境下 打算进行maven编译打包 可是明明有本地仓库 也配置了本地仓库 但是还是会从远程下载 然后再各大网友的帮助下 百度 谷歌 查询到主要的原因是在本地仓库的每个依赖包都存在 remote repositories文件 直
  • layui多文件上传与下载示例

    第一次写文件上传 不知道怎么下手 幸好有万能layui 方便了很多 HTML div class layui body header span class layui body header title 产品文件上传 span div di
  • 对话用友网络副总裁、用友大易创始合伙人石磊:新的人力资源红利时代已经到来

    数科星球原创 作者丨苑晶 编辑丨十里香 在这个日新月异的科技时代 无论是企业还是个人 拥抱先进的技术工具以及前沿的思维成为建立差异化优势 取得长期价值的不二法门 在真实的场景中 企业内部的管理状况更为复杂 2023年 在全行业跑步奔向增长之
  • 用python编写一个弹球游戏

    用python编写一个简单的弹球游戏 这是学习python时用来练习的一个项目 作为笔记 最终是实现一个简单的弹球游戏 效果图如下 源代码 无限命版的弹球游戏python代码 from tkinter import 来源于python的标准
  • “互联网+”定义及相关概念解析

    来源 中国互联网技术联盟 2015年5月 6月 7月 国家密集性的发布了三大重型文件 中国制造2025 大众创业万众创新政策措施意见 互联网 行动指导意见 随后 中国互联网技术联盟邀请专家委员会对此专门进行了闭门研讨和解读梳理 并将梳理成果
  • 有关res://ieframe.dll/dnserrordiagoff_webOC.htm# http://www.51hainuo.cn

    有关这个 res ieframe dll dnserrordiagoff webOC htm http www 51hainuo cn 大部分的人应该会觉得是dns错误或者dns解析本机不正常 然后就去找杀毒软件来杀毒 网上我搜索的到的很多
  • html水平导航和垂直导航,简单却实用的CSS水平和垂直导航栏【演示/源码】

    说到CSS导航栏 各种漂亮炫酷的样式都应有尽有 不过本文要介绍的是简单却又很实用的导航栏 分为水平导航栏和垂直导航栏两种样式 适合初学者学习使用 以及一些对设计要求不高的网页使用 简单却实用的CSS水平和垂直导航栏 概述 这个简单的教程将教
  • IOException parsing XML document from class path resource [applicationContent.xml]; nested exception

    Spring报错问题 IOException parsing XML document from class path resource applicationContent xml nested exception is java io
  • 深度学习算法优化系列

    1 前言 这是Google在CVPR 2018上发表的一篇int8量化的论文 题目为 Quantization and Training of Neural Networks for Efficient Integer Arithmetic
  • 机器学习数据预处理——特征选择

    引言 在机器学习的训练过程中 总是会碰到样本大 特征多的数据集 而这些数据集里面的数据有些是用处很小甚至完全无用的 如果一组数据中的无用数据占比较大时 一方面会使得模型的训练时间变长 另一方面模型容易出现欠拟合现象 而如果一组数据中作用较小
  • 你还在手动对数据进行校验,快来使用validation吧

    本篇主要讲解使用javax validation constraints org hibernate validator constraints下的校验方法对实体类进行自动校验 直接对数据进行校验 通过对接收的数据进行校验 如果不符合我们定
  • chatgpt赋能python:Python中的d是什么?详解Python字典(Dictionary)

    Python中的d是什么 详解Python字典 Dictionary 在Python中 d是一个非常重要的数据类型 d代表字典 Dictionary 它是一种可变容器模型 可以存储任意数量的键值对 字典的定义 字典使用花括号 来表示 每个键
  • C++的指针

    C 的指针 在C 中 指针被称为是C C 中的精髓所在 指针是存放内存地址的一种变量 特殊的地方就在它存放的是内存地址 计算机中的内存都是编址的 每个地址都有一个符号 指针是一个无符号整数 它是一个以当前系统寻址范围为取值范围的整数 声明指