C/C++-指针

news2025/1/20 7:22:28

C/C++-指针

  • 参考
  • 1. 指针
    • 指针与内存/地址
    • 指针使用
  • 2.数组指针
    • 数组/指针/sizeof
    • 一维数组与指针
    • 多维数组指针
  • 3.字符/字符串指针
  • 4. 其他指针
    • 二级指针 -- 还没看
    • 空指针
    • void指针
    • 野指针
  • 5.指针与函数
    • 函数指针
    • 引用传递
    • 指针函数
  • 6.结构体指针
      • 结构体数组指针
      • ???
  • c++ 对象指针

参考

https://www.bilibili.com/video/BV1s5411J78m?p=3&spm_id_from=pageDriver&vd_source=7155082256127a432d5ed516a6423e20 – 入门 讲的不错

1. 指针

适用于C/C++

指针与内存/地址

数据以二进制的形式存在内存中,每个数据占n个字节
每个字节都有一个内存地址

指针:就把他理解为一个数据,只要是数据就以二进制的形式存储在内存中
指针(在内存中存的值是 被指向的 那个数据的 内存地址值) – 见下图
且每个指针在内存中也有一个地址
总结:指针就是被指向数据的内存地址

CPU访问内存时需要的是地址,而不是变量名和函数名,变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,变量名和函数名都被替换成地址
编译和连接过程的一项重要的任务就是找到这些名称所对应的地址

通常:变量名表示的是数据本身;
函数名、字符串名、数组名是表示的是代码块和数据块的首地址

地址本质上是一个整数

指针使用

一个变量A 存放的是 另一个变量B的指针,那么将A变量 称为 指针变量
指针必须进行初始化!

指针创建

dataType* name=value,** dataType表示该指针所指向的数据的类型**
注意指针的类型是 dataType*而不是dataType

int *p; // 表示指针p指向的内容是整型
int* p; //表示指针p是一个int*类型
int a;
int *p; // *表示指针变量
p=&a; //p的值 时a的地址值

int *p=&a; // 等价
int* p=&a; // 等价 ; 感觉这种更符合实际的意思

printf("%d",*p); // 取值

指针修改

int a;
int *p;
p=&a; //p的值 时a的地址值
// 等价于 int *p=&a;
// 等价于 int* p=&a; //感觉这种更符合实际的意思

a=1;
&p // p的地址值
*p // *表示取消引用,*p 取了p的值(地址)所指向的数据
*p=10; // a此时变成了5

char c;
char *pc;

double d;
double *pd;

// *p++ 等价于*(p++)
int a=10;
int* p=&a;
printf("%p\n",p);
printf("%d\n",*p++);
printf("%d\n",a);
printf("%p\n",p);
#include <stdio.h>

int main(){
    int a;
    a=10;
    int *p;
    p=&a;
    printf("%d\n",p); // 6422036 'python':hex(6422036) =='0x61fe14'
    printf("%p\n",p); //000000000061FE14 
    printf("%p\n",&a); //000000000061FE14

    int b=20;
    *p=b; // 只是值的修改
    printf("%d\n",a); // 20
    printf("%p\n",p); // 000000000061FE14
    printf("%p\n",&a); // 000000000061FE14 不会改变a的地址
    printf("%p\n",&b); // 000000000061FE10

    p=&b;
    printf("%p\n",p); // 000000000061FE10,指向了b
    printf("%p\n",&a); // 000000000061FE14
    printf("%p\n",&b); // 000000000061FE10

    return 0;
}

在这里插入图片描述

指针算数

指针的值+1,指针的值+dataType个字节
尽量不要对变量的指针进行运算,这样没有意义

int a;
a=10;
int *p;
p=&a;
printf("%p\n",&a); // 000000000061FE14
printf("%p\n",p+1); // 000000000061FE18
printf("%p\n",&a); // 000000000061FE14

*运算符优先级高于双目运算符

int a=1;
int* p=&a;
printf("%d\n",*p+1); // 2

指针的比较运算
对指针变量进行比较运算时,比较的是指针变量本身的值,也就是数据的地址,如果地址相等那么两个指针指向用一个数据,否则指向不同的数据

2.数组指针

数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关

数组/指针/sizeof

数组在内存中只是数组元素的简单排列,没有开始和结束标志
不能使用int *p=arr; sizeof§/sizeof(int),因为p只是一个指向int类型的指针,编译器并不知道它指向的到底是一个整数还是一些列的整数(数组),所以sizeof§求得的是p这个指针变量本身所真用的字节数,而不是整个数组占用的字节数。
指针指向的数据类型可以不同
指针变量占用的内存空间相同

一维数组与指针

数组指针:指向数组的指针
不同于指针数组!!!

数组名可以认为是做一个指针,指向数组的第0个元素
数组本身是指针这个说法不准确!!!
第0个元素的地址称为数组的首地址
数组指针 指向的是数组中的一个具体元素,而不是整个数组,所以指针数组的类型和数组元素的类型有关

数组指针与数组名不同,数组名不可以改变,而数组指针可以改变
(下面的具有 右结合性)
*p++ 等价于*(P++),不能使用*arr++,因为数组名不能改变
*++p 等价于*(++P) 等价于*(p+1)
(*p)++只对数值进行改变

type *p=arr p+1相当于移动了一个type类型的字节

int a[3]={1,2,4};
int* p=a;
// 下面三个是等价的
printf("%p\n",p);
printf("%p\n",a);
printf("%p\n",&a[0]);

// printf("",a++); // 这个是错误的,数组名是不能改变的
printf("%d\n",*p++); // 1
printf("%d\n",*(p++)); // 1,*p赋值之后,再++
printf("%d\n",*p+1); // 2
printf("%d\n",*(p+1)); // 2 
printf("%d\n",*(++p)); //2 
printf("%d\n",*++p); //2 
int main()
{
    int a[3]={1,4,5};

    int *p=a;
 
    // printf("%d\n",*p++);
    // printf("%d\n",*p);
    printf("%d\n",(*p)++);
    printf("%d\n",*p);
    // printf("%d\n",*(p++));
    // printf("%d\n",*p);

    for (int i=0;i<3;i++)
    {
        printf("%d\n",a[i]);
    }
    return 0;
}

重要

[]符号具有取内容的作用
a[i],*(a+i),p[i], *(p+i) 这四个是等价的
&a[i],(a+i),&p[i], (p+i) 这四个是等价的

int a[3]={1,2,3};
for (int i=0;i<3;i++)
{
    printf("%d,%d,%d,%d\n",a[i],*(a+i),p[i],*(p+i));
    printf("%p,%p,%p,%p\n",&a[i],(a+i),&p[i],(p+i));
}

多维数组指针

https://blog.csdn.net/angiusc/article/details/106599792

二维数组与一维数组的关系

a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]
嵌套理解 a[3][4] 中 a[0]是一个数组(也是一个一维数组名)

// 可以定义1xX的数组
int a[1][3]={1,2,3};
for (int i=0;i<1;i++){
    // for (int j=0;j<3;j++){
    //     printf("%d\n",a[i][j]);
    // }
    printf("%p\n",a[i]);
    printf("%p\n",&a[i][0]); // &a[i][0] 与a[i] 等价
    printf("%d\n",a[i][0]);
}

a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]

对于一维数组及其指针 type *p=arr p+1相当于移动了一个type类型的字节
对于二维数组及其指针,p+1应该移动整个一维数组对应的字节,type (*p)[n],(*p) 表示指针,int [n] 表示指针指向的数据类型

int a[1][3]={1,2,3};
for (int i=0;i<1;i++){
    // for (int j=0;j<3;j++){
    //     printf("%d\n",a[i][j]);
    // }
    printf("%p\n",a[i]);
    printf("%p\n",&a[i][0]); // &a[i][0] 与a[i] 等价
    printf("%d\n",a[i][0]); // 这是数值
}

int a[2][3]={{1,2,3},{4,5,6}};
// 下面三个是等价的 
// *a[2][3] 可以看成是2个一维数组,每个一维数组的数组名是a[0],a[1]*
printf("%p\n",a);
printf("%p\n",a[0]);
printf("%p\n",&a[0][0]);

// 下面是等价的
int (*p)[3]=a;
printf("%p\n",p+1);
printf("%p\n",a+1);
printf("%p\n",a[1]);
printf("%p\n",&a[1][0]);

重要

a[i]==*(a+i)==p[i]==*(p+i)
a[i][j]==*(a[i]+j)==*(*(a+i)+j)==p[i][j]==*(p[i]+j)==*(*(p+i)+j)

int (*p)[3]=a;
for (int i=0;i<2;i++)
{
    for (int j=0;j<3;j++)
    {
        printf("%d,%d,%d,%d,%d,%d\n",a[i][j],*(a[i]+j),*(*(a+i)+j),p[i][j],*(p[i]+j),*(*(p+i)+j));
    } 
}

/*  /// 补充 ///
    // 理解
    对于1维数组
    int a={1,2,3};
    int* p=a;
    a[1]==*(P+1)==*(a+1)==p[1]
    &a[1]==p+1==a+1

    // 二维数组
    // 看成嵌套的一维数组
    int a[][2]={1,2,3,4};
    int (*p)[2]=a; 
    *(*(p+1)+1) ==a[1][1]
    p指向了一个都是指针的数组(首地址),而数组元素的每个指针,指向了一个一维数组(首地址)
    p+1==a[1]==&a[1][0]
    *(p+1)==a[1]==&a[1][0] // 这个记忆方法放到下面可以理解

    // 下面三个方法是等价的
    printf("%d\n",*(a[1]+1)); //a[1]也是一个指针,表示一维数组
    printf("%d\n",*(*(p+1)+1));  // *(p+1) p+1表示一个一维数组,
    printf("%d\n",a[1][1]);
*/ 

重要 - 第二种表达方法

int a[2][3]={{1,2,3},{4,5,6}};

int *p=&a[0][0];
for (int i=0;i<2;i++)
{
    for (int j=0;j<3;j++)
    {
        printf("%d,%d\n",a[i][j],*((p+i*3)+j));
    }
}

3.字符/字符串指针

指向字符串的指针
通常利用字符数组表示字符串

字符数组归根结底还是一个数组,所以数组大部分的功能都适用

char s[]="hello";
char* p=s;
for (int i=0;i<sizeof(s)-1;i++){
    printf("%c,%c,%c\n",s[i],p[i],*(p+i));
}

for (int i=0;i<strlen(s);i++){
    printf("%c,%c,%c\n",s[i],p[i],*(p+i));
}

另一种字符串表示方法

直接使用一个指针指向字符串
被称为:字符常量
能够修改指针指向的地址,但是不能修改内容

char *s="hello";

char *s;
s="hello";

s="world"; // 正确
// s[2]='1';// 错误

两种创建方式的不同

char s[]="xxx"以字符数组存储在全局数据区或栈区,具有读写权限
char* s="xxx"存储在常量区,只有读取权限,一旦定义不能修改

两种字符串的补充

// 初始化注意事项
// char s1[10];
// s1="hello"; // 这种不行
char *s2;
s2="world"; // 这种可以

// 访问
char arr1[]="hello world";
char *arr2="hello cpp";

for (int i=0;i<11;i++)
{
    printf("%c,%c",arr1[i],*(arr1+i));
}
printf("\n");
for (int i=0;i<9;i++)
{
    printf("%c,%c\n",arr2[i],*(arr2+i));
}

/* 重要 */
printf("%s\n",arr1); // hello world
printf("%s\n",arr2); // hello cpp
printf("%s\n",arr1+1); // ello world
printf("%s\n",arr2+2); // llo cpp

*运算符优先级高于双目运算符

char a='c';
char* p=&a;
printf("%d\n",a); //99
printf("%c\n",*p+1); //d
printf("%d\n",*p+1); //100

4. 其他指针

二级指针 – 还没看

指向指针的指针
指针存放的是一个变量的地址,而指针的地址也可以被另一个指针存放
指针变量也是变量,因此也需要存储空间

int a=100;
int* p1=&a;
int** p2=&p1; // 可以理解为 (int*)* p2=&p1 因为指向的是指针,而指针的类型是int*,而创建的又是一个指针,所以是(int*)* 

空指针

对未初始化的指针赋值为NULL
空指针是不指向任何数据的指针,是无效指针

// NULL 其实是一个宏定义,指向了内存的0地址,
#define NULL ((Void*)0)
char* s=NULL;

if (p==NULL){
	// ...
}

void指针

void* 表示一个有效指针,指向实实在在的数据,只是数据的类型尚未确定,在后序使用过程中需要进行强制类型转换

char* s=(char*)malloc(sizeof(char)*30);

野指针

如果一个指针指向的内存没有访问权限,或者指向一块已经释放掉的内存,那么就无法对该指针进行操作,这样的指针就是野指针

free

free§并不能改变指针p的值,p依然指向以前的内存,为了防止再次使用该内存,建议将p的值手动置为NULL
free§ 只是释放掉动态分配的内存,p的值并不是NULL,仍然指向之前这个被释放掉的内存,所以if§仍然会执行,但是输出p指向的内存会报错

避免野指针

初始化为NULL
free之后,赋值为NULL

5.指针与函数

https://blog.csdn.net/L_fengzifei/article/details/126291514

函数指针

使指针变量指向函数坐在的内存区域,然后通过指针变量就可以找到并调用该函数
returnType (*p)(param list)returnType为函数返回值类型

typedef int (*PTR_TO_FUNC)(int, int);
PTR_TO_FUNC pfunc;

// 例子
typedef int (*PTR_TO_FUNC)(int, int);
int max(int a, int b){
    return a>b ? a : b;
}
PTR_TO_FUNC pfunc = max;
printf("max: %d\n", (*pfunc)(10, 20));

注意与 引用传递、指针函数的区别

引用传递

int max(int a,int b){
    return a>b?a:b;
}

int main(){
    int x=1;
    int y=2;
    int maxval;
    int (*pmax)(int,int)=max;

    maxval=(*pmax)(x,y);    
    printf("%d\n",maxval);
    
    return 0;
}

指针函数

下面是指针函数返回值是指针,指针指向的数据类型

char *strlong(char* s1,char* s2){
    if (strlen(s1)>=strlen(s2)){
        return s1;
    }
    else{
        return s2;    
    }
}

注意局部变量作为指针函数的返回值情况

函数运行结束后会销毁在他内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们会在后续使用过程中可能引发运行时错误

// 下面的例子,有的编译器直接报错,提示 返回局部变量的指针
int *func()
{
    int n=100;
    return &n;
}

int main()
{
    int *p=func(),n;
    n=*p;
    printf("%d\n",n);

    return 0;
}

6.结构体指针

一个指针变量指向结构体,叫做结构体指针
struct struct_name* var

struct str{
	char* name;
	int num;
} stu1={"tom",1};

struct stu* pstu=&stu1;

// 直接创建指针
struct str{
	char* name;
	int num;
} stu1={"tom",1},*pstu=&stu1;

// 使用指针获取结构体成员
(*pstu).name; // 必须加括号
pstu->name; // 直接通过结构体指针获取成员,这种方法更有效

结构体指针作为函数参数传递

‘C-语言函数中的例子’

结构体数组指针

因为是数组,所以数组名可以作为元素的首地址

struct stu class[]={
    {"li",2},
    {"wang",3}
};

// 下面两个是等价的,都表示地址
printf("%p\n",class);
printf("%p\n",&class[0]);

// 所以可以利用指针指向地址
struct stu* pstu=class; 

// 下面这两种访问方法都是等价的
struct stu* pstu=class;
for (int i=0;i<2;i++){
    printf("%s,%d\n",(pstu+i)->num,(pstu+i)->age);
}

for (int i=0;i<2;i++,pstu++){
    printf("%s,%d\n",pstu->num,pstu->age);
}

???

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

#define N 2

struct stu{
    char name[10];
    int num;
}boya[N],boyb[N],*pa,*pb;


int main(){
    FILE* fp;
    int i;
    if ((fp=fopen("ex4.txt","wt+"))==NULL){
        puts("fail to open file");
        exit(0);
    }

    printf("input data\n");

    pa=boya;
    for (i=0;i<N;i++,pa++){
        scanf("%s %d",pa->name,&pa->num);
    }
    pa=boya; // 为什么要写两遍??
    for (i=0;i<N;i++,pa++){
        fprintf(fp,"%s %d\n",pa->name,pa->num);
    }
    return 0;
}

c++ 对象指针

见 c++ – 面向对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/48640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin 开发Android app(十四):startActivity跳转Activity活动

从一个Activity跳到另一个Activity 在编写安卓代码是最常见的事情了。我们不可能在一个页面中&#xff0c;把所有的事情都做完。 在kotlin中跳转的程序也比较简单&#xff0c;跟java差不多。如果熟悉java代码的话&#xff0c;只需要把代码改变过来而已。 带参数的调整 从一个…

极空间Docker安装Alist套件整合阿里云盘、百度云盘等网盘资源并挂载到本地供极影视刮削播放完整教程

文章目录0、前言1、在docker中安装alist套件1.1、拉取并下载alist镜像1.2.安装alist镜像2、访问并设置alist2.1、访问alist2.2、配置alist2.2.1、在alist中添加阿里云盘2.2.2、在alist中添加其它网盘3、在极空间中将前述网盘挂载到本地4、在极影视中扫描刮削挂载到本地的云盘中…

如何制作一个微信小程序【微信小程序是怎么做的】

为什么现在这么多人使用微信小程序呢&#xff1f;因为微信小程序除了便捷易开发&#xff0c;公司企业可以用来做小程序展示官网&#xff0c;商家也可以做小程序商城&#xff0c;甚至个人也可以拥有自己的小程序。那么如何制作一个微信小程序&#xff1f;微信小程序是怎么做的呢…

第二证券|房地产股债嗨了,百余只个股谁受热捧?谁还受益?

29日&#xff0c;AH股房地产板块狂飙&#xff0c;地产债反常火热。 A股地产股开盘即掀涨停潮&#xff0c;中国武夷、中交地产、空港股份、光大嘉宝、中华企业等超10股竞价涨停。港股内房股大幅高开&#xff0c;碧桂园、富力地产、新城开展等多股涨超10%&#xff0c;盘中三巽集…

Crack:Stimulsoft BI Server 2022.4.5

Stimulsoft BI Server 是一个客户端-服务器系统&#xff0c;可让您高效且有效地实施使用报告和仪表板的完整周期&#xff0c;从执行信息处理任务的设计和自动化开始&#xff0c;到为方便地向用户展示结果做准备结束。报告模块的功能和功能是使用 Stimulsoft 的快速现代技术实现…

一、Vue3基础[组件(props、事件、插槽)]

一、组件化 解释:正如上图所示,一个页面可以分为多块部分,但是如果把所有代码都写在一个vue文件当中,维护性和可读性都会很差,所以需要用到组件化思维->创建多个vue文件每个里面写一部分代码,然后集中在一个主的vue文件调用 二、组件的注册 1.全局 解释:顾名思义,…

【Java盲点攻克】「时间与时区系列」让我们一起完全吃透对于时区和日期相关的功能开发原理

技术简介 java中的日期处理一直是个问题&#xff0c;没有很好的方式去处理&#xff0c;所以才有第三方框架的位置比如joda。文章主要对java日期处理的详解&#xff0c;用1.8可以不用joda。 时间概念 首先我们对一些基本的概念做一些介绍&#xff0c;其中可以将GMT和UTC表示时…

自然算法 - AI面试基础补全

手撕BP神经网络手写Bert和Transformer&#xff08;BERT很细节的地方&#xff0c;比如文字标签CLS&#xff0c;par&#xff09;学习pytorch&#xff0c;tensorflow AI算法岗位 可看网站 牛客网站 面经回复 github 项目连接 算法工程师岗位必备知识 问答 ELMO、GPT、…

Linux系统下KVM虚拟机的基本管理和操作

Linux系统下KVM虚拟机的基本管理和操作一、检查本地环境1.检查系统版本2.检查防火墙状态3.检查selinux3.检查libvirtd服务状态4.检查kvm安装结果5.检查kvm虚拟机状态6.检查virsh版本二、virsh常用命令1.列出虚拟机2.虚拟机开关机操作3.删除虚拟机4.设置虚拟机在宿主机开机时自启…

装在笔记本里的私有云环境:K8s 集群准备

本篇是系列中的第六篇内容&#xff0c;继续聊聊如何把一个简化过的私有云环境部署在笔记本里&#xff0c;以满足低成本、低功耗、低延时的实验环境。 在前几篇内容中&#xff0c;我们聊过了&#xff1a;虚拟化、监控、基础的存储、持续集成等内容&#xff0c;接下来的内容中&a…

告诉你如果对一个新产品进行测试

初入一家公司&#xff0c;当一个全新的产品摆在你的面前&#xff0c;你会如何快速入手呢&#xff1f;点、点、点。。。虽说实践是熟悉系统的第一要素&#xff0c;但我们需要静静思考一下。我是谁&#xff1f;--QA我在哪&#xff1f;--**产品组我要做什么&#xff1f;--保质量有…

Nature:“我还有用!“凋亡细胞释放的代谢物充当组织信使

代谢组学文献分享&#xff0c;细胞凋亡是指为维持内环境稳定&#xff0c;由基因控制的细胞自主的有序的死亡。2002年授予在“发现细胞凋亡的重要调控分子并阐述其作用机制”方面做出重要贡献的三位科学家诺贝尔生理和医学奖&#xff0c;caspase依赖的细胞凋亡约占机体内稳态细胞…

多线程初阶(一)

目录 前言&#xff1a; 认识多线程 创建线程 run方法和start区别 继承Thread类 实现Runnable接口 匿名内部类实现继承Thread类 匿名内部类实现Runnable接口实例 Lambda表达式 中断线程 等待线程 线程休眠 线程状态 线程状态之间切换 代码观察线程的状态 线程安…

多点DMALL × Apache Kyuubi:构建统一SQL Proxy探索实践

伴随着国家产业升级的推进和云原生技术成熟&#xff0c;多点 DMALL 大数据技术也经历了从存算一体到存算分离的架构调整变迁。本文将从引入 Kyuubi 实现统一 SQL Proxy 的角度讲述这一探索实践的历程。 多点 DMALL 成立于2015年&#xff0c;提供一站式全渠道数字零售解决方案 D…

STL的常用算法-查找 (20221130)

STL的常用算法 概述&#xff1a; 算法主要是由头文件<algorithm> <functional> <numeric> 组成。 <algorithm>是所有STL头文件中最大的一个&#xff0c;涉及比较、交换、查找、遍历等等&#xff1b; <functional>定义了一些模板类&#xff0…

使用记账软件记录生活收支明细,如何防止收支不被他人修改

坚持记账是每个人都必须要做的事情&#xff0c;日常生活中的生活开支都是一笔笔的支出&#xff0c;一个月挣来的工资&#xff0c;在不知不觉之中就花完了&#xff0c;可以使用——晨曦记账本记录生活明细&#xff0c;为了防止被他人修改&#xff0c;该如何操作呢&#xff1f;一…

Allegro调丝印规范操作指导

Allegro调丝印规范操作指导 Allegro和其它PCB设计软件一样,丝印的排布也是类似的,具体规范介绍如下 以下图为例 打开Setup-Design Parameter 选择text 设置丝印字体的参数 设置需要丝印的字体,比如3号字体,参数如下 然后点击OK Edit-Change需要调整丝印的字体

Linux-Hadoop部署

部署Hadoop一、Hadoop部署模式1、独立模式2、伪分布式模式3、完全分布式模式二、Hadoop集群规划1、集群拓扑2、角色分配三、JDK安装与配置1、下载JDK压缩包2、上传到master虚拟机3、在master虚拟机上安装配置JDK4、将JDK分发到slave1和slave2虚拟机5、将环境配置文件分发到slav…

图的初识·存储结构

邻接矩阵存储结构 用矩阵表示表示图中各个顶点之间的邻接关系和权值。如图G(V,E)G(V,E)G(V,E)&#xff0c;其中有N个结点&#xff0c;使用NxNNxNNxN的矩阵表示。 不带权值的图 Gij{1,无向图(vi,vj)或有向图的<vi,vj>是图中的边0,无向图的(vi,vj)或有向图的<vi,vj>…

猕猴桃的红色果肉受到特定的激活-抑制系统的控制

文章信息 题目&#xff1a;The red flesh of kiwifruit is differentially controlled by specific activation–repression systems 刊名&#xff1a;New Phytologist 作者&#xff1a;Wen-qiu Wang&#xff0c;Andrew C. Allan,Xue-ren Yin et al 单位&#xff1a;Zhejia…