《C和指针》读书笔记(第八章 数组)

news2024/11/18 12:24:57

目录

  • 0 内容简介
  • 1. 一维数组
    • 1.1 数组名
    • 1.2 下标引用
    • 1.3 指针与下标
    • 1.4 指针的效率
    • 1.5 数组和指针
    • 1.6 作为函数参数的数组名
    • 1.7 声明数组参数
    • 1.8 初始化
    • 1.9 不完整的初始化
    • 1.10 自动计算数组长度
    • 1.11 字符数组的初始化
  • 2. 多维数组
    • 2.1 存储顺序
    • 2.2 数组名
    • 2.3 下标
    • 2.4 指向数组的指针
    • 2.5 作为函数参数的多维数组
    • 2.6 初始化
    • 2.7 数组长度自动计算
  • 3. 指针数组
  • 4. 总结

0 内容简介

在C语言中,数组有着举足轻重的地位。而数组和指针千丝万缕的联系,也让其在求职,学习和工作中成为技术探讨的焦点。计算机编程语言群星璀璨,为何C语言数组在多年面试中的热度居高不下?它究竟有什么样的神奇魅力?今天我们就一起来探讨相关话题。

先来看看本篇的主要内容(章节编号与书中一致)。有一个宏观上的把握。
在这里插入图片描述

1. 一维数组

一维数组是最常见的数组,也是最常用的数组,在实际的开发中,为了便于迭代和阅读,有时会将多个数组拆分成多个一维数组。

1.1 数组名

一维数组的数组名是一个指针常量,指向数组的第一个元素,可以参考下面的程序:

#include <stdio.h>
int main()
{
	int temp[] = {1,2,3};
	printf("%d \n", *(temp));
	printf("%d \n", *(temp + 1));
	printf("%d \n", *(temp + 2));
	return 0;
}

打印输出:
在这里插入图片描述

1.2 下标引用

除了优先级以外,下标引用和间接访问完全一致。可以参考下面的程序:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int temp[] = {1,2,3};
	int *p = temp + 1;
	printf("数组的第一个元素是:%d \n", *(temp));
	printf("数组的第二个元素是:%d \n", *(temp + 1));
	printf("数组的第三个元素是:%d \n", *(temp + 2));
	//打印数组的第一个元素
	printf("数组的第一个元素是:%d \n", p[-1]);
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
从上面的程序可以看出,指针p此时指向了数组的第2个元素,所以p[-1]会指向数组的第一个元素。

1.3 指针与下标

指针与下标,都是访问数组元素的有效方式,然而下标绝不会比指针更有效率,但指针有时会比下标更有效率,因牵扯到底层指令,在此不做展开。

1.4 指针的效率

指针有时比下标更有效率,前提是它们被正确地使用。因牵扯到底层指令,在此不做展开。

1.5 数组和指针

数组和指针并不是相等的。在声明数组的时候,已经分配好了内存,而在声明指针的时候,只知道其指向的数据类型,并不知道指向的具体地址,或者是没有任何意义的地址。
比方说有下面两个声明:

	int a[5];
	int *p;

我们可以通过下面的程序进行验证

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a[5];
	int *p;
	printf("数组a的大小是%d \n", sizeof(a));
	printf("指针p的大小是%d \n", sizeof(p));
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
可以看到,在经过编译后,一个int类型的数据占4个字节,这个时候系统已经为数组分配好了所有的内存;而指针p,我们只知道其指向一个int类型的变量,然而并不知道具体指向了哪个变量

1.6 作为函数参数的数组名

当一个数组名作为参数传递给一个函数时,传递给函数的是一份该指针的拷贝。函数如果进行了下标引用,实际上就是对这个指针执行间接访问操作,并且通过这种间接访问,函数可以访问和修改调用程序的数组元素。

可以参考如下的程序:

#include <stdio.h>
#include <stdlib.h>
void reverse_array(int arr[], int size)
{
	for (int i = 0; i < size / 2; i++)
	{
		int temp = arr[i];
		arr[i] = arr[size - i - 1];
		arr[size - i - 1] = temp;
	}
}
int main()
{
	int a[5];
	for (int i = 0; i < 5; i++)
		a[i] = i;
	reverse_array(a, 5);
	for (int i = 0; i < 5; i++)
	{
		printf("数组a第%d个元素是%d \n", i, a[i]);
	}
	system("pause");
	return 0;
}

1.7 声明数组参数

有一个有趣的问题,当我们把一个数组当做参数传递给函数的时候,正确的函数形参应该怎样的呢?应该声明为一个指针还是数组?

严格意义上来说都是正确的。可参考以下代码

#include <stdio.h>
#include <stdlib.h>
//声明为数组
void reverse_array1(int arr[], int size)
{
	for (int i = 0; i < size / 2; i++)
	{
		int temp = arr[i];
		arr[i] = arr[size - i - 1];
		arr[size - i - 1] = temp;
	}
}
//声明为指针
void reverse_array2(int *arr, int size)
{
	for (int i = 0; i < size / 2; i++)
	{
		int temp = arr[i];
		arr[i] = arr[size - i - 1];
		arr[size - i - 1] = temp;
	}
}
int main()
{
	int a1[5];
	int a2[5];
	for (int i = 0; i < 5; i++)
	{
		a1[i] = i;
		a2[i] = i;
	}
	//翻转数组
	reverse_array1(a1, 5);
	reverse_array2(a2, 5);
	//打印输出
	for (int i = 0; i < 5; i++)
	{
		printf("数组a1第%d个元素是%d \t", i, a1[i]);
		printf("数组a2第%d个元素是%d \n", i, a2[i]);
	}
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
从上述例子可以看出,两种初始化从效果上来说是等同的。但是要说更加准确,应该是使用指针。因为实参实际上是个指针,而不是数组。

1.8 初始化

当数组的初始化局部于一个函数(或代码块)时,应该仔细考虑一下,在程序的执行流每次进入该函数(或代码块)时,每次对数组进行重新初始化是否值得。如果答案是否定的,就把数组声明为static,这样数组的初始化只需要在程序开始前执行一次。

关于static关键字,可以参考这篇文章:static关键字详解(C/C++)

1.9 不完整的初始化

所谓的不完整初始化,是指在数组初始化的时候,如果我们只对部分元素赋值,那么,剩下的元素会自动被赋值为0。可以参考下面的代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a1[5] = {0,1};

	//打印输出
	for (int i = 0; i < 5; i++)
	{
		printf("数组a1第%d个元素是%d \n", i, a1[i]);
	}
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
可以看到,没有初始化的几个元素,会被自动初始化为0,但这种自动初始化是有限制的,只能自动化地赋值后面的元素,不能赋值前面和中间的元素。

1.10 自动计算数组长度

如果在数组定义的时候就进行了初始化,那么不必指定数组长度,参考下面的例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a1[] = {0,1};

	//打印输出
	printf("数组a1的大小是%d \n", sizeof(a1) / sizeof(int));
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述

1.11 字符数组的初始化

字符数组有两种初始化方式,一种是常规的初始化,比如:

	char a1[] = {'0','1'};

还有另一种方式,方便快捷,就是像字符串的定义方式类似:

	char a2[] = "01";

其实这两者并不完全等同,在第二种初始化方式中,默认多了一个‘\0’,所以数组a2有3个元素。可以参考下面的测试代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	char a1[] = {'0','1'};
	char a2[] = "01";

	//打印输出
	printf("数组a1的大小是%d \n", sizeof(a1) / sizeof(char));
	printf("数组a2的大小是%d \n", sizeof(a2) / sizeof(char));
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
C 语言中并不存在字符串这个数据类型,而是使用字符数组来保存字符串。

2. 多维数组

多维数组是二维以及二维以上的数组,其中最常用的是二维数组。需要注意的是多维数组的元素存储顺序。以及元素的访问方式等。

当出现多维数组时,若再采用指针、或者指针和下标结合的方式去访问数组元素,将是稍微有点难度的问题。

2.1 存储顺序

在C语言中,多维数组的元素存储顺序按照最右边的下标率先变化的原则,称为行主序

#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COL 8
int main()
{
	int matrix[ROW][COL];
	int *p = &matrix[0][0];
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			matrix[i][j] = i * ROW + j;
		}
			
	}
	//打印输出
	printf("第一个值是%d \n", *p);
	printf("第二个值是%d \n", *++p);
	printf("第三个值是%d \n", *++p);
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
从上面的例子可以看出,当指针增长的时候,指向的是数组按照最右侧率先变化的顺序的元素。而当一行扫描结束的时候,会自动指向下一行,继续访问。

2.2 数组名

一维数组名的值是一个指针常量,指向一个元素,而多维数组第一维的元素是另一个数组。例如下面的声明:

	int matrix[3][10];

可以看作是一个一维数组,包含了3个元素,每个元素是包含10个整形元素的数组。

或者可以看本文后续的章节,慢慢体会就自然会明白。

2.3 下标

如果要标识一个多维数组的某个元素,必须按照与数组声明时相同的顺序为每一维都提供一个下标,而且都单独位于一对方括号内。

#include <stdio.h>
#include <stdlib.h>
#define ROW 8
#define COL 3
int main()
{
	int matrix[ROW][COL];
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			matrix[i][j] = i * COL + j;
		}
			
	}
	//打印输出
	printf("第一个值是:%d \n", **matrix);
	printf("第二个值是:%d \n", *(*(matrix + 1)));
	printf("第三个值是:%d \n", *(*(matrix) + 2));
	printf("第四个值是:%d \n", *(*(matrix + 1) + 2));
	system("pause");
	return 0;
}

在这里插入图片描述
上面这个例子可能稍微有点难,按照指针移动的方向,仔细琢磨琢磨就可以想清楚。

2.4 指向数组的指针

指向多维(二维)数组的指针,应当如何定义呢?

	int matrix[ROW][COL] = {{0,1,2},{3,4,5}};
	int(*p)[COL] = matrix;

我们定义了一个指针p,指向了一个拥有COL个元素的数组。当把p与一个整数值相加时,该整数值首先根据整形值的长度进行调整,然后再执行加法。参考下面的例子。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 2
#define COL 3
int main()
{
	//定义二维数组
	int matrix[ROW][COL] = {{0,1,2},{3,4,5}};
	//定义指向数组的指针
	int(*p)[COL] = matrix;
	//打印输出
	printf("(*(*p))的值为:%d \n",(*(*p)));
	printf("(*(*p + 1))的值为:%d \n", *(*(p + 1)));
	printf("(*(*p) + 1的值为:%d \n", (*(*p) + 1));
	printf("(*(*p + 1) + 1)的值为:%d \n", *(*(p + 1) + 1));
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述

可以看到,直接利用p指针执行间接访问,肯定访问到的是第0行的第0个元素((*(*p)))。而在对p直接进行加1操作的时候,移动的是一个一维数组,然后再间接访问,所以得到的是数组第1行的第0个元素,也就是*(*(p + 1))这样的表达式;但如果间接访问一次之后在加1,则首先访问到的是二维数组的第0行,再加1自然就是第0行第一个元素,也就是上述(*(*p) + 1)表达式;最后一个表达式(*(*(p + 1) + 1))自然不言而喻了。

2.5 作为函数参数的多维数组

多维(二维)数组作为函数参数的时候,函数声明也与一维数组有所不同。有两种声明方式:
方式1:

void func1(int(*mat)[5])

方式2:

void func2(int mat[][5])

这两种声明方式,在效果上是等同的,两种都可以。从以下的程序中就可以证明这一点:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 3
#define COL 5
//声明方式1
void func1(int(*mat)[5])
{
	int add = 1;
	printf("在函数func1中\n");
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			mat[i][j] += 10;
			printf("数组的第%d个元素是:%d\n", add, mat[i][j]);
			add++;
		}
	}
}
//声明方式2
void func2(int mat[][5])
{
	int add = 1;
	printf("在函数func2中\n");
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			mat[i][j] += 10;
			printf("数组的第%d个元素是:%d\n", add, mat[i][j]);
			add++;
		}
	}
}
int main()
{
	//定义二维数组
	int matrix1[ROW][COL];
	int matrix2[ROW][COL];
	//定义累加变量
	int add = 1;
	//数组初始化
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			matrix1[i][j] = i * COL + j;
			matrix2[i][j] = i * COL + j;
			printf("数组1的第%d个元素是:%d \t", add, matrix1[i][j]);
			printf("数组2的第%d个元素是:%d \n", add, matrix1[i][j]);
			add++;
		}
	}
	printf("-----------------");
	//函数调用
	func1(matrix1);
	printf("-----------------");
	func2(matrix2);
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
上述例子,定义了2个3*5的二维数组,进行相同的初始化,然后分别传到两个函数进行处理,这两个函数仅仅是形参的声明方式不一样。两个函数对原来数组的每个元素进行加10处理,得到了相同的结果。

所以,这两种声明方式在效果上是等同的。

2.6 初始化

多维(二维)数组的初始化有两种常见的形式。

  1. 一种是直接给每个元素赋储值
  2. 一种是用花括号隔开每个维度,并赋值

两种方式都是正确的,只是第二种有方式有两个好处:

  1. 利于阅读
  2. 方便初始化,每个子初始列表都可以省略尾部的几个值(不完整的初始化列表)。

参考下面的程序:

#include <stdio.h>
#include <stdlib.h>
#define ROW 2
#define COL 3
int main()
{
	//初始化形式1
	int matrix1[ROW][COL] = {0,1,2,3,4,5};
	//初始化形式2
	int matrix2[ROW][COL] = { {0,1,2},{3,4,5}};

	int add = 1;
	//打印输出
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			printf("matrix1的第%d个值为%d \t", add, matrix1[i][j]);
			printf("matrix2的第%d个值为%d \n", add, matrix2[i][j]);
			add++; 
		}
	}
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
从上面的例子可以看出,这两种形式,从实现效果上来说,是一致的。

2.7 数组长度自动计算

在多维数组中,只有第1维才能根据初始化列表缺省地提供。剩下的几个维必须显式地写出,这样编译器就能推断出每个子数组维数的长度。例如:

#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COL 5
int main()
{
	int matrix3[][5] = { {0,1,2},{3,4,5},{6,7,8}};

	int add = 1;
	//打印输出
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			printf("matrix1的第%d个值为%d \t", add, matrix3[i][j]);
			add++; 
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

打印输出:
在这里插入图片描述
所以此时即使不写第1个维度的值,编译器在运行的时候,也可以根据初始化的值,以及花括号自动推断出来该维度的值。

3. 指针数组

指针数组很好理解,就是一个数组中的元素是指针,至于该指针指向什么样的数据,是由用户自己定义的。
比如下面这个例子,用指针数组存储了指向字符串(更严谨地说是字符数组)的指针。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 3
#define COL 5
char const *keyword[] = {"do","for"};
int main()
{
	int add = 1;
	//打印输出
	char const desired_word[] = "do";
	char const **p;
	for (p = keyword; p < keyword + 2; p++)
	{
		if (strcmp(desired_word, *p) == 0)
		{
			printf("YES");
			system("pause");
			return 0;
		}
			
	}
	printf("NO");
	system("pause");
	return 0;
}

打印输出如下:
在这里插入图片描述
上述的例子中,用数组存储了若干个字符数组的指针数组。然后实现了多个字符串的匹配功能。

或者用二维数组也可以实现,但是需要提前知道最长字符串的大小。

4. 总结

数组与指针的关系,不可能一两句话说清楚,需要在具体开发中慢慢体会,理解。

数组的元素可以通过下标指针两种方式进行访问,而指针往往更加高效。

指针数组在开发中也会比较常用,而数组元素也不仅仅只会指向字符串(字符数组),也有可能指向结构体变量等数据类型。

----------------------------------------------------------------end----------------------------------------------------------------

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

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

相关文章

爆火出圈的chatGPT,到底是什么东东?

爆火出圈的chatGPT&#xff0c;到底是什么东东&#xff1f; 前言 2022年 11 月 30 日&#xff0c;OpenAI 实验室创始人兼 CEO Sam Altman 宣布发布聊天机器人模型&#xff1a;ChatGPT。ChatGPT 可以模仿人类的说话风格回答问题。很快&#xff0c;ChatGPT 火爆社交圈&#xff…

Linux音频和视频命令速查表

在Linux系统中&#xff0c;有许多命令可以帮助我们处理音频和视频文件&#xff0c;从基本的播放和转码&#xff0c;到编辑和处理音频、视频流。 本文将提供一个Linux音频和视频命令速查表&#xff0c;帮助您快速查找并了解各种常用的命令及其用法。 音频命令 播放音频文件 a…

堆和堆排序

目录 堆的概念 堆的实现 堆的存储结构 堆的插入操作 堆的删除操作 堆的创建 向上调整建堆和向下调整建堆 堆排序 堆的应用 - topK问题 堆的概念 “堆”是计算机科学中一种数据结构&#xff0c;可以看作是一棵完全二叉树。通常满足堆的性质&#xff1a;父节点的值总是…

【Linux】进程控制 — 进程程序替换 + 实现简易shell

文章目录 &#x1f4d6; 前言1. 进程程序替换1.1 程序替换的概念&#xff1a;1.2 为什么要程序替换&#xff1a;1.3 程序替换的原理&#xff1a; 2. 六个exec替换函数2.1 execl函数&#xff1a;2.2 execv函数&#xff1a;2.3 execlp函数&#xff1a;2.4 execvp函数&#xff1a;…

chatgpt赋能python:Python[:2]——简介和应用

Python [:2]——简介和应用 Python [:2]是一种流行的编程语言&#xff0c;其简单易用的语法使其成为许多人的首选编程语言之一。Python [:2]的迅速增长已经超越了其他编程语言&#xff0c;并且它正在成为各行各业中最有前途的编程语言之一。 Python 基础 Python [:2]的语法非…

MSQL系列(三) Mysql实战-索引最左侧匹配原则原理

Mysql实战-索引最左侧匹配原则原理 前面我们讲解了索引的存储结构&#xff0c;我们知道了BTree的索引结构&#xff0c;索引的叶子节点是严格排序的&#xff0c;就像你看到的 底层叶子节点 15->18->20->30->49->50等等 这样做有什么好处呢&#xff1f; 这就引出…

利用qsort排序

一、简单排序10个元素的一维数组 #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:6031) #include<stdio.h> #include<stdlib.h> void print_arr(int arr[], int sz) {int i 0;for (i 0; i < sz; i){printf("%d ", arr[i]);}printf("…

WMS服务启动

WMS服务启动 1、SystemServer.java#startOtherServices(t)中启动2、WindowManagerService.java#main创建初始化3、简易时序图4、相关线程 1、SystemServer.java#startOtherServices(t)中启动 WMS属于SystemServer启动众多的系统服务中的一个&#xff0c;WindowManagerService中…

社会工程学技术框架解读

社会工程学技术其实就是利用各种心理进行技术上的欺骗。 尽管许多社会工程学大师都是无师自通,依赖自己的天赋悟性、聪明才智和临场应变能力不断演绎着社会工程学艺术,然而,社会工程学仍然具有一些通用的技术流程与共性特征。Social-Engineer 网站创始人克里斯哈德纳吉对其加…

Spring Cloud Alibaba 快速上手搭建公司项目(二)Nacos

Nacos(全称为&#xff1a;阿里巴巴开源项目 - 命名服务 & 配置中心)是阿里巴巴集团开源的一个动态服务发现、配置管理和服务管理平台。它提供了一种简单易用的方式来管理和监控微服务应用程序中的服务实例、配置和元数据。 Nacos是一个高度可扩展的平台&#xff0c;支持多…

chatgpt赋能python:Python中的[::-1]操作:反转列表、元组和字符串

Python中的[::-1]操作&#xff1a;反转列表、元组和字符串 在Python编程中&#xff0c;[::-1]是一个相当常用的操作符&#xff0c;它可以对列表、元组、字符串等序列类型进行反转。本文将详细介绍这个操作符的语法和使用方法&#xff0c;并且为您提供一些在实际应用中的例子。…

css浮动特性

1. 传统网页的三种布局方式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"wid…

类和对象【3】初始化列表

全文目录 引言初始化列表定义特性 总结 引言 上一篇文章中介绍了构造函数&#xff0c;它可以在实例化一个类对象的时候自动调用&#xff0c;以初始化类对象&#xff1a; 戳我看默认成员函数详解 但是&#xff0c;不难发现&#xff0c;在构造函数体中对成员变量的初始化其实是属…

武汉环保门禁电子台账视频监控系统

武汉环保门禁电子台账视频监控系统&#xff0c;是顺应国家政策需求&#xff0c;基于视频监控、环保门禁系统、物联技术&#xff0c;结合大数据和人工智能等技术手段&#xff0c;对汽车排放单位进行环境管理的一套综合系统。 系统介绍 该系统实现对机动车排放检测的监管&#…

Android 读取本地数据进行本地开发

前言 在日常开发当中&#xff0c;API接口还没有部署&#xff0c;但是UI已经出来了&#xff0c;这时候往往都会使用本地数据进行功能界面的搭建&#xff0c;这样往往能很大程度节约开发时间&#xff0c;工具类拿来直接用&#xff0c;话不多说&#xff0c;开整 一、项目搭建 1…

Web应用技术(第十四周/持续更新)

本次练习基于how2j和课本,初步认识Spring。 以后我每周只写一篇Web的博客&#xff0c;所以的作业内容会在这篇博客中持续更新。。。 一、Spring基础1.Spring概述:2.Sring组成&#xff1a;3.BeanFactory&#xff1a;4.控制反转&#xff1a;5.依赖注入&#xff1a;6.JavaBean与S…

学习Java可以从事什么岗位(合集)

学习Java可以从事什么岗位 学习Java可以从事的岗位 Java可以做网站 Java可以用来编写网站&#xff0c;现在很多大型网站都用Jsp写的&#xff0c;JSP全名Java Server Pages 它是一种动态网页技术&#xff0c;比如我们熟悉的163&#xff0c;一些政府网站都是采用JSP编写的。 所以…

MySQL小练习(使用JDBC操作数据库)

题目&#xff1a; 1.创建一个数据库(学号姓名缩写,如: 2020001zs)在数据库中创建一张表 (五个以上字段) ; 2.使用JDBC(使用PreparedStatement接口) 操作数据库对表中的数据进行增删改查操作 目录 一、数据库 1.创建数据库 2.创建表 3.添加数据 二、JDBC 1.准备环境 2.查询…

TCO-PEG-Thiol,反式环辛烯聚乙二醇巯基,具有末端硫醇基团的双功能TCO PEG衍生物

产品描述&#xff1a; TCO PEG Thiol是具有末端硫醇基团的双功能TCO PEG衍生物。TCO&#xff08;反式环辛烯&#xff09;基团与四嗪基团快速有效地反应&#xff0c;而硫醇&#xff08;巯基&#xff09;可用于与马来酰亚胺反应&#xff0c;与金表面结合并参与许多其他反应。 TC…

DOTA PSMA,1702967-37-0,PSMA-617,特异性膜抗原 (PSMA) 的强有效抑制剂

产品描述&#xff1a; DOTA-PSMA是Prostate特异性膜抗原 (PSMA) 的强有效抑制剂&#xff0c;其 Ki 值为 0.37 nM。DOTA-PSMA由三种成分组成:药效基团Glutamate-urea-Lysine&#xff0c;螯合剂DOTA&#xff08;能够结合68Ga或177Lu&#xff09;&#xff0c;以及连接这两个实体的…