C语言学习专栏(1):易忘点

2023-05-16

C语言学习专栏系列:

【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权);

本博客的内容来自于:C语言学习专栏(1):易忘点;

学习、合作与交流联系q384660495;

本博客的内容仅供学习与参考,并非营利;


include< > 与 #include ""的区别:

  1. < > 表示系统直接按系统指定的目录检索;
  2. “” 表示系统先在 “” 指定的路径(没写路径代表当前路径)查找头文件,如果找不到,再按系统指定的目录检索;

main函数

  1. 一个完整的 C 语言程序,是由一个、且只能有一个 main()函数(又称主函数,必须有)和若干个其他函数结合而成(可选)。
  2. main 函数是 C 语言程序的入口,程序是从 main 函数开始执行。

C语言编译过程

  1. 预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法 ;
  2. 编译:检查语法,将预处理后文件编译生成汇编文件;
  3. 汇编:将汇编文件生成目标文件(二进制文件);
  4. 链接:C 语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去;

在这里插入图片描述

静态库与动态库

  1. 静态库与动态库都是链接阶段的步骤。静态库(.a、.lib)和动态库(.so、.dll)。
  2. 静态库编译期间打包到可执行文件中,而动态库是执行时才被载入。
  3. 动态库规避了空间浪费和静态库在更新、部署和发布带来的麻烦。不同程序调用相同的动态库,内存中只需要保存一份实例。
  4. 静态库和动态库的最大区别,静态情况下,把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。
  5. 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。静态库在程序编译时被连接,运行时不再需要。

声明与定义

一般的情况下,把建立存储空间的声明称之为“定义”,而把不需要建立存储 空间的声明称之为“声明”。直接为声明赋值会报错。

原码、反码与补码

在计算机系统中,数值一律用补码来存储,主要原因是:

  1. 统一了零的编码
  2. 将符号位和其它位统一处理
  3. 将减法运算转变为加法运算
    在这里插入图片描述

赋值表达式的返回值

注意,赋值表达式有返回值,等于等号右边的值。变量y的值就是赋值表达式(x = 2 * x)的返回值2。赋值变量符是从右向左执行。

除法注意事项

  1. C 语言里面的整数除法是整除,只会返回整数部分,丢弃小数部分。
  2. 如果希望得到浮点数的结果,两个运算数必须至少有一个浮点数,这时 C 语言就会进行浮点数除法。

连续运算符

i < j < k

上面示例中,连续使用两个小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量j的值在i和k之间。因为表示运算符是从左到右计算,所以实际执行的是下面的表达式。

(i < j) < k

python是可以这样判断的

浮点数判断大小

注意,由于存在精度限制,浮点数只是一个近似值,它的计算是不精确的,比如 C 语言里面0.1 + 0.2并不等于0.3,而是有一个很小的误差。

bool类型

C99 标准添加了类型_Bool,表示布尔值。但是,这个类型其实只是整数类型的别名,还是使用0表示伪,1表示真。

头文件stdbool.h定义了另一个类型别名bool,并且定义了true代表1、false代表0。只要加载这个头文件,就可以使用这几个关键字。

#include <stdbool.h>

bool flag = false;

字面值的类型

一般情况下,十进制整数字面量(比如123)会被编译器指定为int类型。如果一个数值比较大,超出了int能够表示的范围,编译器会将其指定为long int。如果数值超过了long int,会被指定为unsigned long。如果还不够大,就指定为long long或unsigned long long。

unsigned int里面的int可以省略,所以上面的变量声明也可以写成下面这样。

unsigned a;

字符类型char也可以设置signed和unsigned。

signed char c; // 范围为 -128 到 127
unsigned char c; // 范围为 0255

注意,C 语言规定char类型默认是否带有正负号,由当前系统决定。这就是说,char不等同于signed char,它有可能是signed char,也有可能是unsigned char。这一点与int不同,int就是等同于signed int。

溢出

每一种数据类型都有数值范围,如果存放的数值超出了这个范围(小于最小值或大于最大值),需要更多的二进制位存储,就会发生溢出。大于最大值,叫做向上溢出(overflow);小于最小值,叫做向下溢出(underflow)。

一般来说,编译器不会对溢出报错,会正常执行代码,但是会忽略多出来的二进制位,只保留剩下的位,这样往往会得到意想不到的结果。

unsigned int i = 5;
unsigned int j = 7;

if (i - j < 0) // 错误
  printf("negative\n");
else
  printf("positive\n");

上面示例的运算结果,会输出positive。原因是变量i和j都是 unsigned int 类型,i - j的结果也是这个类型,最小值为0,不可能得到小于0的结果。正确的写法是写成下面这样。

sizeof返回值

sizeof运算符的返回值,C 语言只规定是无符号整数,并没有规定具体的类型,而是留给系统自己去决定,sizeof到底返回什么类型。不同的系统中,返回值的类型有可能是unsigned int,也有可能是unsigned long,甚至是unsigned long long,对应的printf()占位符分别是%u、%lu和%llu。这样不利于程序的可移植性。

C 语言提供了一个解决方法,创造了一个类型别名size_t,用来统一表示sizeof的返回值类型。该别名定义在stddef.h头文件(引入stdio.h时会自动引入)里面,对应当前系统的sizeof的返回值类型,可能是unsigned int,也可能是unsigned long。

C 语言还提供了一个常量SIZE_MAX,表示size_t可以表示的最大整数。所以,size_t能够表示的整数范围为[0, SIZE_MAX]。

printf()有专门的占位符%zd或%zu,用来处理size_t类型的值。

如果当前系统不支持%zd或%zu,可使用%u(unsigned int)或%lu(unsigned long int)代替。

类型转换

  1. 赋值运算符的自动转换

字节宽度较小的整数类型,赋值给字节宽度较大的整数变量时,会发生类型提升,即窄类型自动转为宽类型。

字节宽度较大的类型,赋值给字节宽度较小的变量时,会发生类型降级,自动转为后者的类型。这时可能会发生截值(truncation),系统会自动截去多余的二进制位,导致难以预料的结果。

  1. 运算符的自动转换

不同的浮点数类型混合运算时,宽度较小的类型转为宽度较大的类型,比如float转为double,double转为long double。

不同的整数类型混合运算时,宽度较小的类型会提升为宽度较大的类型。比如short转为int,int转为long等,有时还会将带符号的类型signed转为无符号unsigned。避免无符号与有符号的混合运算,会出现意想不到的错误。

  1. 函数的参数和返回值,会自动转成函数定义里指定的类型。

可移植类型

整数类型的极限值,有时候需要查看,当前系统不同整数类型的最大值和最小值,C 语言的头文件limits.h提供了相应的常量,比如SCHAR_MIN代表 signed char 类型的最小值-128,SCHAR_MAX代表 signed char 类型的最大值127。

为了代码的可移植性,需要知道某种整数类型的极限值时,应该尽量使用这些常量。

SCHAR_MIN,SCHAR_MAX:signed char 的最小值和最大值。
SHRT_MIN,SHRT_MAX:short 的最小值和最大值。
INT_MIN,INT_MAX:int 的最小值和最大值。
LONG_MIN,LONG_MAX:long 的最小值和最大值。
LLONG_MIN,LLONG_MAX:long long 的最小值和最大值。
UCHAR_MAX:unsigned char 的最大值。
USHRT_MAX:unsigned short 的最大值。
UINT_MAX:unsigned int 的最大值。
ULONG_MAX:unsigned long 的最大值。
ULLONG_MAX:unsigned long long 的最大值。

程序员有时控制准确的字节宽度,这样的话,代码可以有更好的可移植性,头文件stdint.h创造了一些新的类型别名。

(1)精确宽度类型(exact-width integer type),保证某个整数类型的宽度是确定的。

int8_t8位有符号整数。
int16_t16位有符号整数。
int32_t32位有符号整数。
int64_t64位有符号整数。
uint8_t8位无符号整数。
uint16_t16位无符号整数。
uint32_t32位无符号整数。
uint64_t64位无符号整数。

程序员有时控制准确的字节宽度,这样的话,代码可以有更好的可移植性,头文件stdint.h创造了一些新的类型别名。

字符数组与字符串区别

数字 0(和字符‘\0’等价)结尾的 char 数组就是一个字符串,字符串是一种特殊的 char 的数组。

字符串多行

  1. 如果字符串过长,可以在需要折行的地方,使用反斜杠(\)结尾,将一行拆成多行。
"hello \
world"
  1. 只要这些字符串之间没有间隔,或者只有空格,C 语言会将它们自动合并。
char greeting[50] = "Hello, ""how are you ""today!";
// 等同于
char greeting[50] = "Hello, how are you today!";

字符指针和字符数组

  1. 指针指向的字符串,在 C 语言内部被当作常量,不能修改字符串本身。

为什么字符串声明为指针时不能修改,声明为数组时就可以修改?原因是系统会将字符串的字面量保存在内存的常量区,这个区是不允许用户修改的。声明为指针时,指针变量存储的只是一个指向常量区的内存地址,因此用户不能通过这个地址去修改常量区。但是,声明为数组时,编译器会给数组单独分配一段内存,字符串字面量会被编译器解释成字符数组,逐个字符写入这段新分配的内存之中,而这段新内存是允许修改的。

为了提醒用户,字符串声明为指针后不得修改,可以在声明时使用const说明符,保证该字符串是只读的。

const char* s = "Hello, world!";
  1. 指针变量可以指向其它字符串。

为什么数组变量不能赋值为另一个数组?原因是数组变量所在的地址无法改变,或者说,编译器一旦为数组变量分配地址后,这个地址就绑定这个数组变量了,这种绑定关系是不变的。C 语言也因此规定,数组变量是一个不可修改的左值,即不能用赋值运算符为它重新赋值。

gets(str)与 scanf(“%s”,str)的区别

  1. gets(str)允许输入的字符串含有空格
  2. scanf(“%s”,str)不允许含有空格

fgets与fputs

char *fgets(char *s, int size, FILE *stream);
int fputs(const char * str, FILE * stream);

fgets()在读取一个用户通过键盘输入的字符串的时候,同时把用户输入的回 车也做为字符串的一部分。通过 scanf 和 gets 输入一个字符串的时候,不包 含结尾的“\n”,但通过 fgets 结尾多了“\n”。fgets()函数是安全的,不存在缓冲区溢出的问题。

fputs()是 puts()的文件操作版本,但 fputs()不会自动输出一个’\n’。

数组

  1. 数组scores只有100个成员,因此scores[100]这个位置是不存在的。但是,引用这个位置并不会报错,会正常运行,使得紧跟在scores后面的那块内存区域被赋值,而那实际上是其他变量的区域,因此不知不觉就更改了其他变量的值。这很容易引发错误,而且难以发现。
  2. C 语言规定,数组变量一旦声明,就不得修改变量指向的地址,声明数组时,编译器自动为数组分配了内存地址,这个地址与数组名是绑定的,不可更改。
  3. 数组初始化时,可以指定为哪些位置的成员赋值。
int a[15] = {[2] = 29, [9] = 7, [14] = 48};

上面示例中,数组的2号、9号、14号位置被赋值,其他位置的值都自动设为0。

指定位置的赋值可以不按照顺序,下面的写法与上面的例子是等价的。

int a[15] = {[9] = 7, [14] = 48, [2] = 29};

指定位置的赋值与顺序赋值,可以结合使用。

int a[15] = {1, [5] = 10, 11, [10] = 20, 21}
  1. c99提供了变长数组,运行时才知道数组的具体长度。
  2. 数组作为函数的参数,必须要传入数组名和长度,不然默认大小为指针大小。
  3. 多维数组作为函数参数,除了第一维度,其他维度必须写入定义。
  4. 变长数组作为函数参数,数组a[n]是一个变长数组,它的长度取决于变量n的值,只有运行时才能知道。所以,变量n作为参数时,顺序一定要在变长数组前面,这样运行时才能确定数组a[n]的长度,否则就会报错。
  5. 因为函数原型可以省略参数名,所以变长数组的原型中,可以使用*代替变量名,也可以省略变量名。
int sum_array(int, int [*]);
int sum_array(int, int []);
  1. 数组拷贝一种是挨个元素复制,一种方法是使用memcpy()函数(定义在头文件string.h),直接把数组所在的那一段内存,再复制一份。
memcpy(a, b, sizeof(b));
  1. C 语言允许将数组字面量作为参数,传入函数。
// 数组变量作为参数
int a[] = {2, 3, 4, 5};
int sum = sum_array(a, 4);

// 数组字面量作为参数
int sum = sum_array((int []){2, 3, 4, 5}, 4);

上面示例中,两种写法是等价的。第二种写法省掉了数组变量的声明,直接将数组字面量传入函数。{2, 3, 4, 5}是数组值的字面量,(int [])类似于强制的类型转换,告诉编译器怎么理解这组值。

函数

  1. c语言没有默认参数
  2. 不返回值的函数,使用void关键字表示返回值的类型。没有参数的函数,声明时要用void关键字表示参数类型。
  3. 不要返回局部变量的地址
  4. 形参是实参的拷贝,值传递。
  5. 函数本身就是一段内存里面的代码,C 语言允许通过指针获取函数。
void print(int a) {
  printf("%d\n", a);
}

void (*print_ptr)(int) = &print;

上面示例中,变量print_ptr是一个函数指针,它指向函数print()的地址。函数print()的地址可以用&print获得。注意,(print_ptr)一定要写在圆括号里面,否则函数参数(int)的优先级高于,整个式子就会变成void* print_ptr(int)。

如果一个函数的参数或返回值,也是一个函数,那么函数原型可以写成下面这样。

int compute(int (*myfunc)(int), int, int);

上面示例可以清晰地表明,函数compute()的第一个参数也是一个函数。

  1. 函数原型包括参数名也可以,虽然这样对于编译器是多余的,但是阅读代码的时候,可能有助于理解函数的意图。
int twice(int);

// 等同于
int twice(int num);

上面示例中,twice函数的参数名num,无论是否出现在原型里面,都是可以的。

  1. 在main()函数里面,exit()等价于使用return语句。其他函数使用exit(),就是终止整个程序的运行,没有其他作用。

C 语言还提供了一个atexit()函数,用来登记exit()执行时额外执行的函数,用来做一些退出程序时的收尾工作。该函数的原型也是定义在头文件stdlib.h。

  1. 函数原型默认就是extern
  2. static关键字表示该函数只能在当前文件里使用,如果没有这个关键字,其他文件也可以使用这个函数(通过声明函数原型)。
  3. 有些函数的参数数量是不确定的,声明函数的时候,可以使用省略号…表示可变数量的参数。

int printf(const char* format, …);
上面示例是printf()函数的原型,除了第一个参数,其他参数的数量是可变的,与格式字符串里面的占位符数量有关。这时,就可以用…表示可变数量的参数。

注意,…符号必须放在参数序列的结尾,否则会报错。

头文件stdarg.h定义了一些宏,可以操作可变参数。

(1)va_list:一个数据类型,用来定义一个可变参数对象。它必须在操作可变参数时,首先使用。

(2)va_start:一个函数,用来初始化可变参数对象。它接受两个参数,第一个参数是可变参数对象,第二个参数是原始函数里面,可变参数之前的那个参数,用来为可变参数定位。

(3)va_arg:一个函数,用来取出当前那个可变参数,每次调用后,内部指针就会指向下一个可变参数。它接受两个参数,第一个是可变参数对象,第二个是当前可变参数的类型。

(4)va_end:一个函数,用来清理可变参数对象。
下面是一个例子。

double average(int i, ...) {
  double total = 0;
  va_list ap;
  va_start(ap, i);
  for (int j = 1; j <= i; ++j) {
    total += va_arg(ap, double);
  }
  va_end(ap);
  return total / i;
}

上面示例中,va_list ap定义ap为可变参数对象,va_start(ap, i)将参数i后面的参数统一放入ap,va_arg(ap, double)用来从ap依次取出一个参数,并且指定该参数为 double 类型,va_end(ap)用来清理可变参数对象。

多文件编程

  1. 为了避免同一个文件被 include 多次,C/C++中有两种方式,一种是 #ifndef 方式,一种是 #pragma once 方式。
方法一:
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
// 声明语句 #endif
方法二:
#pragma once
// 声明语句

指针

  1. 使用 sizeof()测量指针的大小,得到的总是:4 或 8
  2. 指针可以和整数加减,指针不能和指针相加,但是可以相减,指针之间可以去进行比较
  3. sizeof()测的是指针变量指向存储地址的大小
  4. 在 32 位平台,所有的指针(地址)都是 32 位(4 字节)
  5. 在 64 位平台,所有的指针(地址)都是 64 位(8 字节)
  6. 任意数值赋值给指针变量没有意义,因为这样的指针 就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的 内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才 会出问题。
  7. void *指针可以指向任意变量的内存空间:
 void *p = NULL;
 int a = 10;
 p = (void *)&a; //指向变量时,最好转换为void *
 //使用指针变量指向的内存时,转换为int *
 *( (int *)p ) = 11;
 printf("a = %d\n", a);
  1. 星号*可以放在变量名与类型关键字之间的任何地方
  2. 如果同一行声明两个指针变量,那么需要写成下面这样。
// 正确
int * foo, * bar;

// 错误
int* foo, bar;
  1. NULL在 C 语言中是一个常量,表示地址为0的内存空间,这个地址是无法使用的,读写该地址会报错。

结构体

  1. 声明自定义类型的变量时,类型名前面,不要忘记加上struct关键字。也就是说,必须使用struct fraction f1声明变量,不能写成fraction f1

struct car saturn = {“Saturn SL/2”, 16000.99, 175};
上面示例中,变量saturn是struct car类型,大括号里面同时对它的三个属性赋值。如果大括号里面的值的数量,少于属性的数量,那么缺失的属性自动初始化为0。

注意,大括号里面的值的顺序,必须与 struct 类型声明时属性的顺序一致。否则,必须为每个值指定属性名。

struct car saturn = {.speed=172, .name="Saturn SL/2"};

上面示例中,初始化的属性少于声明时的属性,这时剩下的那些属性都会初始化为0。

声明变量以后,可以修改某个属性的值。

struct car saturn = {.speed=172, .name="Saturn SL/2"};
saturn.speed = 168; 
  1. struct 结构占用的存储空间,不是各个属性存储空间的总和,而是最大内存占用属性的存储空间的倍数,其他属性会添加空位与之对齐。这样可以提高读写效率。
struct foo {
    int a;
    char* b;
    char c;
};
printf("%d\n", sizeof(struct foo)); // 24

上面示例中,struct foo有三个属性,在64位计算机上占用的存储空间分别是:int a占4个字节,指针char* b占8个字节,char c占1个字节。它们加起来,一共是13个字节(4 + 8 + 1)。但是实际上,struct foo会占用24个字节,原因是它最大的内存占用属性是char* b的8个字节,导致其他属性的存储空间也是8个字节,这样才可以对齐,导致整个struct foo就是24个字节(8 * 3)。

struct foo {
    int a;        // 4
    char pad1[4]; // 填充4字节
    char *b;      // 8
    char c;       // 1
    char pad2[7]; // 填充7字节
};
printf("%d\n", sizeof(struct foo)); // 24

为什么浪费这么多空间进行内存对齐呢?这是为了加快读写速度,把内存占用划分成等长的区块,就可以快速在 Struct 结构体中定位到每个属性的起始地址。

由于这个特性,在有必要的情况下,定义 Struct 结构体时,可以采用存储空间递减的顺序,定义每个属性,这样就能节省一些空间。

  1. struct 变量可以使用赋值运算符(=),复制给另一个变量,这时会生成一个全新的副本。系统会分配一块新的内存空间,大小与原来的变量相同,把每个属性都复制过去,即原样生成了一份数据。这一点跟数组的复制不一样,务必小心。

  2. 通常情况下,开发者希望传入函数的是同一份数据,函数内部修改数据以后,会反映在函数外部。而且,传入的是同一份数据,也有利于提高程序性能。这时就需要将 struct 变量的指针传入函数,通过指针来修改 struct 属性,就可以影响到函数外部。

struct 指针传入函数的写法如下。

void happy(struct turtle* t) {
}
happy(&myTurtle);

上面代码中,t是 struct 结构的指针,调用函数时传入的是指针。struct 类型跟数组不一样,类型标识符本身并不是指针,所以传入时,指针必须写成&myTurtle

函数内部也必须使用(*t).age的写法,从指针拿到 struct 结构本身。

void happy(struct turtle* t) {
  (*t).age = (*t).age + 1;
}

上面示例中,(t).age不能写成t.age,因为点运算符.的优先级高于*。*t.age这种写法会将t.age看成一个指针,然后取它对应的值,会出现无法预料的结果。

(*t).age这样的写法很麻烦。C 语言就引入了一个新的箭头运算符(->),可以从 struct 指针上直接获取属性,大大增强了代码的可读性。

void happy(struct turtle* t) {
  t->age = t->age + 1;
}
  1. 赋值的时候有多种写法。
// 写法一
struct fish shark = {"shark", 9, {"Selachimorpha", 500}};

// 写法二
struct species myBreed = {"Selachimorpha", 500};
struct fish shark = {"shark", 9, myBreed};

// 写法三
struct fish shark = {
  .name="shark",
  .age=9,
  .breed={"Selachimorpha", 500}
};

// 写法四
struct fish shark = {
  .name="shark",
  .age=9,
  .breed.name="Selachimorpha",
  .breed.kinds=500
};
  1. struct 还可以用来定义二进制位组成的数据结构,称为“位字段”(bit field),这对于操作底层的二进制数据非常有用。
struct {
  unsigned int ab:1;
  unsigned int cd:1;
  unsigned int ef:1;
  unsigned int gh:1;
} synth;

synth.ab = 0;
synth.cd = 1;

上面示例中,每个属性后面的:1,表示指定这些属性只占用一个二进制位,所以这个数据结构一共是4个二进制位。

注意,定义二进制位时,结构内部的各个属性只能是整数类型。

实际存储的时候,C 语言会按照int类型占用的字节数,存储一个位字段结构。如果有剩余的二进制位,可以使用未命名属性,填满那些位。也可以使用宽度为0的属性,表示占满当前字节剩余的二进制位,迫使下一个属性存储在下一个字节。

struct {
  unsigned int field1 : 1;
  unsigned int        : 2;
  unsigned int field2 : 1;
  unsigned int        : 0;
  unsigned int field3 : 1;
} stuff;

上面示例中,stuff.field1与stuff.field2之间,有一个宽度为两个二进制位的未命名属性。stuff.field3将存储在下一个字节

  1. 很多时候,不能事先确定数组到底有多少个成员。如果声明数组的时候,事先给出一个很大的成员数,就会很浪费空间。C 语言提供了一个解决方法,叫做弹性数组成员(flexible array member)。

如果不能事先确定数组成员的数量时,可以定义一个 struct 结构。

struct vstring {
int len;
char chars[];
};
上面示例中,struct vstring结构有两个属性。len属性用来记录数组chars的长度,chars属性是一个数组,但是没有给出成员数量。

chars数组到底有多少个成员,可以在为vstring分配内存时确定。

struct vstring* str = malloc(sizeof(struct vstring) + n * sizeof(char));
str->len = n;
上面示例中,假定chars数组的成员数量是n,只有在运行时才能知道n到底是多少。然后,就为struct vstring分配它需要的内存:它本身占用的内存长度,再加上n个数组成员占用的内存长度。最后,len属性记录一下n是多少。

这样就可以让数组chars有n个成员,不用事先确定,可以跟运行时的需要保持一致。

弹性数组成员有一些专门的规则。首先,弹性成员的数组,必须是 struct 结构的最后一个属性。另外,除了弹性数组成员,struct 结构必须至少还有一个其他属性。

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

C语言学习专栏(1):易忘点 的相关文章

随机推荐

  • [ Neo4j ] Docker 安装与 Python 操作

    文章目录 安装运行Python 操作简单示例 安装 使用 docker 安装 Neo4j拉取最新的 Neo4j 镜像 docker pull neo4j 运行 运行 Neo4j 容器 docker run it d p span class
  • Windows和Linux之间如何传递数据|两台Linux之间如何传递数据

    摘要 xff1a 我们租用了一台服务器 xff0c 然后我们想要把我们写的项目上传到自己的Linux服务器中 xff0c 那么我们应该怎么上传呢 xff1f 如果我们想要从服务器中下载一些资料 xff0c 那么又该如何进行呢 xff1f 看
  • mac M1使用goland无法进行调试

    首先查看go的版本查看是否是arm版本的eg xff1a go version go version go1 16 13 darwin arm64 然后查看你的goland版本是否是Apple Sillicon版本 下载apple版本的go
  • 忘了自己是从哪里下载的源码?查看git clone的历史

    有时候忘记自己是从哪个地方下载的源码了 xff0c 这时候可以进入git clone的文件夹根目录 xff0c 在该处打开终端并输入 span class token function git span reflog date span c
  • 【详细步骤】Ubuntu18.04开启SSH服务,使用MobaXterm客户端进行远程登录

    熟悉linux的小伙伴 xff0c 都或多或少会接触到ssh服务 使用MobaXterm远程登录Ubuntu那感觉 xff0c 真是太 爽了 本人推荐此方法原因如下 xff1a 1 颜控 xff0c Ubuntu原生界面太丑 2 方便 xf
  • cuda-trt 学习

    https github com jinmin527 learning cuda trt learning cuda trt A large number of cuda tensorrt cases在这个project中 xff0c 提供
  • 时序知识图谱推理:Know-Evolve: Deep Temporal Reasoning for Dynamic Knowledge Graphs

    0摘要 xff1a 带有时间戳的大规模事件数据的可用性催生了边带有时间的动态知识图谱 在动态的知识图谱中 xff0c 并没有被很好的理解 基于此 xff0c 本文提出Know Evolve xff0c 这是一种新颖的深度进化知识网络 xff
  • 《机器学习实战》源码和数据集的下载

    机器学习实战 这本书对于我们了解机器学习原理和代码实现提供了很大的帮助 xff0c 源码和数据集可在其英文版的官方网站进行下载 xff1a https www manning com books machine learning in ac
  • VNC Viewer :Timed out waiting for a response from the computer

    阿里云主机 xff0c Ubuntu系统 xff0c 通过VNC viewer连接出现超时问题 解决方案 xff1a 首先检查在阿里云主机添加5801 5810 xff1b 5901 5910端口是否开启 查找步骤如下图 xff1a 1 点
  • 从零开始系列(二):数据库基础篇

    从零开始系列 xff08 二 xff09 xff1a 数据库基础篇 相关系列文章推荐 xff1a 从零开始系列 xff08 一 xff09 xff1a 在github上搭建自己的博客 从零开始系列 xff08 三 xff09 xff1a W
  • 从零开始系列(三):Windows10安装Linux子系统(WSL教程)

    从零开始系列 xff08 三 xff09 xff1a Windows10安装Linux子系统 xff08 WSL教程 xff09 相关系列文章推荐 xff1a 从零开始系列 xff08 一 xff09 xff1a 在github上搭建自己的
  • 从零开始系列(四):一文看懂arm架构和x86架构有什么区别

    从零开始系列 xff08 四 xff09 xff1a 一文看懂arm架构和x86架构有什么区别 相关系列文章推荐 xff1a 从零开始系列 xff08 一 xff09 xff1a 在github上搭建自己的博客 从零开始系列 xff08 二
  • NVIDIA显卡及架构介绍

    版权申明 未经博主同意 xff0c 谢绝转载 xff01 xff08 请尊重原创 xff0c 博主保留追究权 xff09 xff1b 本博客的内容来自于 xff1a NVIDIA显卡及架构介绍 xff1b 学习 合作与交流联系q384660
  • 脉冲神经网络资料汇总

    往期文章推荐 xff1a 损失函数与代价函数 神经网络从入门到精通 脉冲神经网络综述笔记 版权申明 未经博主同意 xff0c 谢绝转载 xff01 xff08 请尊重原创 xff0c 博主保留追究权 xff09 xff1b 本博客的内容来自
  • 什么是NAS

    一 NAS是什么 简单的说就是连接在网络上 xff0c 让大家可以透过网络 xff08 内网 xff0c 外网 xff09 来进行储存和读取资料的设备 通俗点说 xff0c 就是有一台很小很小的台式主机 xff0c 里面只装了很多颗的磁盘
  • numba安装与使用

    一 numba是什么 Numba是一个针对Python的开源JIT编译器 xff0c 由Anaconda公司主导开发 xff0c 可以对Python原生代码进行CPU和GPU加速 Numba对NumPy数组和函数非常友好 解释器可以参考第四
  • 目标检测中算法评价指标FPS

    一 FPS 每秒传输帧数 Frames Per Second 是什么 FPS就是目标网络每秒可以处理 xff08 检测 xff09 多少帧 多少张图片 FPS简单来理解就是图像的刷新频率 xff0c 也就是每秒多少帧 假设目标检测网络处理1
  • pytorch版本对计算能力的要求

    一 pytorch对计算能力要求 首先查看pytorch是否可用cuda完整流程应该是先查看是否在当前环境下的python In span class token punctuation span span class token numb
  • 在VS2013中配置boost_1_58_0过程和遇到的的问题

    Boost是为C 43 43 语言标准库提供扩展的一些C 43 43 程序库的总称 Boost库是一个可移植 提供源代码的C 43 43 库 xff0c 作为标准库的后备 xff0c 是C 43 43 标准化进程的开发引擎之一 xff0c
  • C语言学习专栏(1):易忘点

    C语言学习专栏系列 xff1a 版权申明 未经博主同意 xff0c 谢绝转载 xff01 xff08 请尊重原创 xff0c 博主保留追究权 xff09 xff1b 本博客的内容来自于 xff1a C语言学习专栏 xff08 1 xff09