Linux 程序设计学习笔记----ANSI C 文件I/O管理

转载请注明出处:http://blog.csdn.net/suool/article/details/38129201


问题引入

文件的种类

根据数据存储的方式不同,可以将文件分为文本文件和二进制文件.具体的区别和关系如下:

文本文件与二进制文件在计算机文件系统中的物理存储都是二进制的,也就是在物理存储方面没有区别都是01码,这个没有异议,他们的区别主要在逻辑存储上,也就是编码上。
文本文件格式存储时是将值作为字符然后存入其字符编码的二进制文本文件用‘字符’作为单位来表示和存储数据,比如对于1这个值,文本文件会将其看做字符‘1’然后保存其ASCII编码值(这里假定是ASCII编码),这样在物理上就是0x31这个二进制值,而若是二进制保存1,则直接保存其二进制值,比如如果程序中是处理1为整数则保存的二进制值就是 0x00000001 (4字节)。
当然如果程序本来就是按字符保存的 也就是 char ch ='1' ;则二进制保存后值就是其ASCII码,因为该变量的二进制本来就是其ASCII码。可以总结出二进制文件就是值本身的编码,那么就是不定长的编码了,因为值本身就是不等字节的,如整数4个字节那么保存在二进制文件就是这四个字节的原生二进制值。

综上,可以知道文本文件与二进制文件就是编码方式不一样而已,而这个是用户行为,把一个数据以什么样的编码(字符还是值本身)存入文件是由用户主动选择的,也就是写入的接口选择,如果以二进制接口方式写入文件那么就是一个二进制文件,如果以字符方式写入文件就是一个文本文件了。既然有写入时候的编码也就会有读出的编码,只有两个编码对应才能读出正确的结果,如用记事本打开一个二进制文件会呈现乱码的,这里稍微提一下后缀名,后缀名并不能确定其是否就是文本文件,二进制文件也可以是txt后缀名,后缀名只是用来关联打开程序,给用户做备注用的,与文件的具体编码没有关系

可以使用字符接口读写二进制文件,只需要做些处理即可,所以所谓的二进制文件,文本文件主要体现在读写方式这里。此外windows有一个明显的区别是对待文本文件读写的时候,会将换行 \n自动替换成 \r\n。

最后文本文件和二进制文件主要是windows下的概念,UNIX/Linux并没有区分这两种文件,他们对所有文件一视同仁,将所有文件都看成二进制文件。

文件操作方式

根据应用程序对文件的访问方式不同,可以分为带缓冲区的文件操作和非缓冲文件操作,具体区别简单介绍如下:

缓冲文件操作:高级文件操作,将在用户空间中自动为正在使用的文件开辟内存缓冲区,遵循ANSI C标准的I/O函数就是缓冲文件操作

非缓冲文件操作:低级文件操作,如果需要,只能由用户自己在程序中为每个文件设置缓冲区,遵循POSIX标准的系统调用I/O函数就是这种类型.

具体的区别见:http://www.360doc.com/content/11/0521/11/5455634_118306098.shtml


ANSI C库函数为了实现他的特性,采用了流的概念,在流的实现中,缓冲区是最重要的单元,根据需要可以分为全缓冲,行缓冲,无缓冲.

下面就具体讲一下关于ANSI  C的流和文件I/O相关的方法和函数.

问题解析

关于流及其功能

在linux系统中,系统默认为每个进程打开了三个文件,即是每个进程可以默认操作三个流:标准输入流,输出流,错误流.

在系统源文件中的宏定义如下:


文件流的主要功能是:

1'格式化内容:实现不同输入输出格式转换.

2'缓冲功能:将数据读写集中,从而减少系统调用次数

文件流指针

在应用编程层面上,程序对流的操作主要是体现在文件流指针FILE上,操作一个文件之前,需要使用fopen打开文件,之后返回该文件的文件流指针与该文件关联,所有针对该文件的读写操作都是通过文件指针完成.下面是在应用层能够访问的FILE的结构体,因此结构体成员可以在用户空间访问:

struct _IO_FILE {
  int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
..............
  int _fileno;                         / 文件描述符
#if 0
}
上面那个结构体中包含了I/O库为管理该流所需要的所有信息.

下面是打印了一个打开的文件流指针指针成员信息的示例程序,在此程序中,使用标准的C库函数实现了文件的复制操作,在复制过程中,实时打印当前的读写位置和缓冲区信息.

代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define prt(CONTENT,MSG) printf(CONTENT":\t%p\n",MSG)

int main(int argc, char *argv[])
{
    FILE *fp_src,*fp_des;                                // 文件读写指针 
    char buffer[10],buffer1[128];                        // 文件读写缓冲区
    int i;
    if((fp_src=fopen(argv[1],"r+"))== NULL)	             // 从第一个命令行文件参数,读文件
    {
        perror("open1");
        exit(EXIT_FAILURE);
    }
    if((fp_des=fopen(argv[2],"w+"))== NULL)              // 从第二个命令行文件参数,写文件
    {
        perror("open2");
        exit(EXIT_FAILURE);
    }
    setvbuf(fp_src,buffer1,_IOLBF,128);                  // 显式设置缓冲区的位置和类型
    do
    {
        /*
         * 以下的prt内容均是属于提示性内容,是读取应用层所能访问的FILE结构体得到的.
         */
        prt("src_IO_read_ptr",fp_src->_IO_read_ptr);     // 源文件读位置,source
        prt("_IO_read_end",fp_src->_IO_read_end);
        prt("_IO_read_base",fp_src->_IO_read_base);

        prt("src_IO_write_ptr",fp_src->_IO_write_ptr);
        prt("_IO_write_base",fp_src->_IO_write_base);
        prt("_IO_write_end",fp_src->_IO_write_end);

        prt("_IO_buf_base",fp_src->_IO_buf_base);        // 源文件缓冲区位置
        prt("_IO_buf_end",fp_src->_IO_buf_end);

        memset(buffer,'\0',10);
        i = fread(buffer,1,10,fp_src);                   // 读
        fwrite(buffer,1,i,fp_des);                       // 写

        prt("des_IO_read_ptr",fp_des->_IO_read_ptr);  
        prt("des_IO_write_ptr",fp_des->_IO_write_ptr);   // 目标文件写位置

    }while(i==10);
    fclose(fp_src);
    fclose(fp_des);                                      // 关闭文件读写
}

运行结果如下:


最终成功复制.

缓冲区类型

刚刚说了三种缓冲区类型,他们依然在系统源代码文件有所定义.

对于标准流ANSI C有如下的要求:

1.标准输入输出:当且仅当不涉及交互作用设备时,他们才是全缓冲的

2.标准错误:绝不会是全缓冲的

下面是用于测试缓冲区类型的示例程序.

代码:

#include <stdio.h>

void pr_stdio(const char *, FILE *);
int main(void)
{
    FILE    *fp;
    fputs("enter any character\n", stdout);
    if(getchar()==EOF)
        printf("getchar error");
    fputs("one line to standard error\n", stderr);
    pr_stdio("stdin",  stdin);                    // test for standard input stream
    pr_stdio("stdout", stdout);                   // test for standard output stream
    pr_stdio("stderr", stderr);                   // test for standard error stream

    if ( (fp = fopen("/etc/motd", "r")) == NULL)  // 普通文件
        printf("fopen error");
    if (fgetc(fp) == EOF)
        printf("getc error");
    pr_stdio("/etc/motd", fp);
    return(0);
}
void pr_stdio(const char *name, FILE *fp)
{
    printf("stream = %s, ", name); 
    if (fp->_flags & _IO_UNBUFFERED)              // 无缓冲
        printf("unbuffered");
    else if (fp->_flags & _IO_LINE_BUF)           // 行缓冲
        printf("line buffered");
    else
        printf("fully buffered");                 // 全缓冲
    printf(", buffer size = %ld\n", fp->_IO_buf_end-fp->_IO_buf_base);
}

结果如下:

指定缓冲区类型,通过sretbuf函数.其中三种缓冲的定义如下:


一个示例代码如下:

/* Example show usage of setbuf() &setvbuf() */
#include<stdio.h>
#include<error.h>
#include<string.h>
int main( int argc , char ** argv )
{
    int i;
    FILE * fp;
    char msg1[]="hello,wolrd\n";
    char msg2[] = "hello\nworld";
    char buf[128];

    //open a file and set nobuf(used setbuf).and write string to it,check it before close of flush the stream
    if(( fp = fopen("no_buf1.txt","w")) == NULL)
    {
        perror("file open failure!");
        return(-1);
    }
    setbuf(fp,NULL);                                    // set the buff NULL
    memset(buf,'\0',128);
    fwrite( msg1 , 7 , 1 , fp );                        // write message to file
    printf("test setbuf(no buf)!check no_buf1.txt\n");
    printf("now buf data is :buf=%s\n",buf);            // test buff

    printf("press enter to continue!\n");
    getchar();
    fclose(fp);


    //open a file and set nobuf(used setvbuf).and write string to it,check it before close of flush the stream
    if(( fp = fopen("no_buf2.txt","w")) == NULL)
    {
        perror("file open failure!");
        return(-1);
    }
    setvbuf( fp , NULL, _IONBF , 0 );
    memset(buf,'\0',128);                                // clear the buff
    fwrite( msg1 , 7 , 1 , fp );
    printf("test setvbuf(no buf)!check no_buf2.txt\n");

    printf("now buf data is :buf=%s\n",buf);

    printf("press enter to continue!\n");
    getchar();
    fclose(fp);

    //open a file and set line buf(used setvbuf).and write string(include '\n') to it,
    //
    //check it before close of flush the stream
    if(( fp = fopen("l_buf.txt","w")) == NULL)
    {
        perror("file open failure!");
        return(-1);
    }
    setvbuf( fp , buf , _IOLBF , sizeof(buf) );
    memset(buf,'\0',128);
    fwrite( msg2 , sizeof(msg2) , 1 , fp );
    printf("test setvbuf(line buf)!check l_buf.txt, because line buf ,only data before enter send to file\n");

    printf("now buf data is :buf=%s\n",buf);
    printf("press enter to continue!\n");
    getchar();
    fclose(fp);

    //open a file and set full buf(used setvbuf).and write string to it for 20th time (it is large than the buf)
    //check it before close of flush the stream
    if(( fp = fopen("f_buf.txt","w")) == NULL)
    {
        perror("file open failure!");
        return(-1);
    }
    setvbuf( fp , buf , _IOFBF , sizeof(buf) );
    memset(buf,'\0',128);
    fwrite( msg2 , sizeof(msg2) , 1 , fp );
    printf("test setbuf(full buf)!check f_buf.txt\n");

    printf("now buf data is :buf=%s\n",buf);    // check data of the current buff 
    printf("press enter to continue!\n");
    getchar();

    fclose(fp);

}

result:


ANSI C 文件I/O操作

1.打开关闭文件三个函数:

fopen()

fclose()

fflush()  // 刷新流

具体代码见stdio.h源代码

2.读写文件

字符单位

1.字符读

从流中读取


从stdin中:

/* Read a character from stdin.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int getchar (void);
2.字符写

/* Write a character to STREAM.

   These functions are possible cancellation points and therefore not
   marked with __THROW.

   These functions is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream);

/* Write a character to stdout.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int putchar (int __c);
行单位

行读出&行写入

/* Write a string to STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fputs (const char *__restrict __s, FILE *__restrict __stream);

/* Write a string, followed by a newline, to stdout.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int puts (const char *__s);

块单位

读写

/* Read chunks of generic data from STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern size_t fread (void *__restrict __ptr, size_t __size,
		     size_t __n, FILE *__restrict __stream) __wur;
/* Write chunks of generic data to STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern size_t fwrite (const void *__restrict __ptr, size_t __size,
		      size_t __n, FILE *__restrict __s);

文件流检测

即是检测文件是否已经读写到末尾或者出错.,使用feof函数.

对于ascii码文件,可以通过是否=EOF判断

对于二进制文件,则需要使用feof来判断是否结束,结束返回1.否则返回0.

ferror函数判断是否出错,无错返回0.

文件流定位

ftell()函数返回流的当前读写位置距离文件开始的字节数

fseek()函数修改当前读写位置

rewind()函数重置读写位置到开头.

/* Seek to a certain position on STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fseek (FILE *__stream, long int __off, int __whence);
/* Return the current position of STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern long int ftell (FILE *__stream) __wur;
/* Rewind to the beginning of STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern void rewind (FILE *__stream);

实例应用

为实现磁盘文件的复制,在ANSI C 的标准下,首先需要将源文件和目标文件建立联系以读的方式打开源文件,以写的方式打开目标文件,先将源文件的数据集中写到缓冲区,然后从内存写入目标文件所在的磁盘.

其中最重要的是判断文件的是否结束.一种方式是使用feof函数,另一种方式是使用读操作的返回值,比如,每次读128字节,只有读到结束位置的时候毒的字节数会小于128,如果出错则返回-1.

一种实现代码如下:

#include<stdio.h>
int main(int argc,char *argv[])
{
    FILE *fp=NULL;
    char ch;
    if(argc<=1)
    {
        printf("check usage of %s \n",argv[0]);
        return -1;
    }
if((fp=fopen(argv[1],"r"))==NULL)			//以只读形式打开argv[1]所指明的文件
    {
        printf("can not open %s\n",argv[1]);
        return -1;
    }
    while ((ch=fgetc(fp))!=EOF)			   //把已打开的文件中的数据逐字节的输出到标准输出stdout
        fputc(ch,stdout);
    fclose(fp);						       //关闭文件
    return 0;
}
具体结果就不演示了.可以自行编译验证.


ElSE

流的格式化输入和输出操作

其实就是几个函数的讲解,这个部分很多资料,所以不在讲了,具体的可以自己google或者看源代码了.

1.

printf()和scanf(0函数.

2.

fprintf()函数和fscanf()函数

3.sprintf函数

4.sscanf()函数

下面贴一下一个使用sscanf获取cpu频率的示例程序:

#include <stdio.h> 
#include <string.h> 
float get_cpu_clock_speed () 
{ 
      FILE* fp; 
      char buffer[1024]; 
      size_t bytes_read; 
      char* match; 
      float clock_speed; 
       
      fp = fopen ("/proc/cpuinfo", "r"); 
      bytes_read = fread (buffer, 1, sizeof (buffer), fp); 
      fclose (fp); 
      if (bytes_read == 0 || bytes_read == sizeof (buffer)) 
      	return 0; 
      buffer[bytes_read] = '\0'; 
      match = strstr (buffer, "cpu MHz");			//匹配 
      if (match == NULL) 
      	return 0; 
      sscanf (match, "cpu MHz : %f", &clock_speed);	//读取 
      return clock_speed; 
} 
int main (void) 
{ 
      printf ("CPU clock speed: %4.0f MHz\n", get_cpu_clock_speed ()); 
      return 0; 
}

result:


reference

关于二进制和文本文件 http://www.cnblogs.com/whutzhou/p/3215210.html

linux高级程序设计 李宗德

NEXT

POSIX 文件及目录管理

普通文件\连接文件及目录文件属性管理


转载请注明出处:http://blog.csdn.net/suool/article/details/38129201

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言教程(原书第4版) 《c语言教程(原书第4版)》是一本优秀的c程序设计语言教材,完整描述了ansi c语言及其语法特性,并对c语言的高级特性和应用作了深入阐述,介绍了从c到c++和java过渡的相关知识。《c语言教程(原书第4版)》的一个鲜明特色就是结合大量示例描述c语言的重要特征,并对很多工作代码给出了逐步的分析,以这种独特的教学方法向读者解释新接触的编程元素及一些惯用法。   《c语言教程(原书第4版)》系统、完整,可作为c语言的参考手册,也非常适合作为学习c语言的入门和高级课程教材。 前言 第0章 从零开始 0.1 为什么要用c 0.2 ansi c标准 0.3 从c到c++ 0.4 从c和c++到java 第1章 c语言概述 1.1 编程和预备知识 1.2 程序输出 1.3 变量、表达式和赋值 1.4 使用#define和#include 1.5 使用printf()和scanf() 1.6 控制流 1.7 函数 1.8 数组、字符串和指针 1.8.1 数组 1.8.2 字符串 1.8.3 指针 1.9 文件 1.10 与操作系统有关的内容 1.10.1 编写和运行c程序 1.10.2 中断程序 1.10.3 输入文件尾标志 1.10.4 输入和输出的重定向 1.11 总结 1.12 练习 第2章 词法元素、操作符和c系统 2.1 字符和词法元素 2.2 语法规则 2.3 注释 2.4 关键字 2.5 标识符 2.6 常量 2.7 字符串常量 2.8 操作符和标点符号 2.9 操作符的优先级和结合性 2.10 增值操作符和减值操作符 2.11 赋值操作符 2.12 例子:计算2的乘方 2.13 c系统 2.13.1 预处理器 2.13.2 标准函数库 2.14 总结 2.15 练习 第3章 基本数据类型 3.1 声明、表达式和赋值 3.2 基本数据类型 3.3 字符和char数据类型 3.4 int数据类型 3.5 整数类型short、long和unsigned 3.6 浮点类型 3.7 typedef的用法 3.8 sizeof操作符 3.9 使用getchar()和putchar() 3.10 数学函数 3.10.1 使用abs()和fabs() 3.10.2 unix和数学函数库 3.11 隐式类型转换和强制类型转换 3.11.1 整型提升 3.11.2 寻常算术转换 3.11.3 强制类型转换 3.12 十六进制和八进制常量 3.13 总结 3.14 练习 第4章 控制流 4.1 关系操作符、相等操作符和逻辑操作符 4.2 关系操作符和表达式 4.3 相等操作符和表达式 4.4 逻辑操作符和表达式 4.5 复合语句 4.6 表达式和空语句 4.7 if和if-else语句 4.8 while语句 4.9 for语句 4.10 例子:布尔变量 4.11 逗号操作符 4.12 do语句 4.13 例子:斐波那契数 4.14 goto语句 4.15 break和continue语句 4.16 switch语句 4.17 条件操作符 4.18 总结 4.19 练习 第5章 函数 5.1 函数定义 5.2 return语句 5.3 函数原型 5.4 例子:创建乘方表 5.5 从编译器的角度观察函数原型 5.6 函数定义顺序的另一种风格 5.7 函数调用和传值调用 5.8 开发大型程序 5.9 使用断言 5.10 作用域规则 5.10.1 平行和嵌套代码块 5.10.2 以调试为目的使用代码块 5.11 存储类型 5.11.1 auto存储类型 5.11.2 extern存储类型 5.11.3 register存储类型 5.11.4 static存储类型 5.12 静态外部变量 5.13 默认初始化 5.14 递归 5.15 例子:汉诺塔 5.16 总结 5.17 练习 第6章 数组、指针和字符串 6.1 一维数组 6.1.1 初始化 6.1.2 下标 6.2 指针 6.3 传引用调用 6.4 数组和指针之间的关系 6.5 指针运算和元素的大小 6.6 数组作为函数的实参 6.7 例子:冒泡排序 6.8 用calloc()和malloc()进行动态内存分配 6.9 例子:归并和归并排序 6.10 字符串 6.11 标准函数库中的字符串处理函数 6.12 多维数组 6.12.1 二维数组 6.12.2 存储映射函数 6.12.3 形式参数声明 6.12.4 三维数组 6.12.5 初始化 6.12.6 使用typedef 6.13 指针数组 6.14 main()函数的参数 6.15 不规则数组 6.16 函数作为参数 6.17 例子:使用二分法寻找函数的根 6.18 函数指针数组 6.19 类型限定符const和volatile 6.20 总结 6.21 练习 第7章 位操作符和枚举类型 7.1 位操作符和表达式 7.1.1 按位求反 7.1.2 补码 7.1.3 位逻辑操作符 7.1.4 左移位和右移位操作符 7.2 掩码 7.3 软件工具:打印int值的二进制形式 7.4 包装和解包 7.5 枚举类型 7.6 例子:“石头、剪刀、布”游戏 7.7 总结 7.8 练习 第8章 预处理器 8.1 #include的使用 8.2 使用#define 8.3 带参数的宏 8.4 stddef.h中的类型定义和宏 8.5 例子:用qsort()进行排序 8.6 例子:带参数的宏 8.7 stdio.h和ctype.h中的宏 8.8 条件编译 8.9 预定义的宏 8.10 “#”和“##”操作符 8.11 assert()宏 8.12 使用#error和#pragma 8.13 行号 8.14 对应的函数 8.15 例子:快速排序 8.16 总结 8.17 练习 第9章 结构和联合 9.1 结构 9.2 访问结构成员 9.3 操作符的优先级和结合性的总结 9.4 在函数中使用结构 9.5 结构的初始化 9.6 例子:玩扑克牌 9.7 联合 9.8 位字段 9.9 例子:访问位和字节 9.10 adt堆栈 9.11 总结 9.12 练习 第10章 结构和列表处理 10.1 自引用的结构 10.2 线性链表 10.3 链表操作 10.4 一些链表处理函数 10.4.1 插入 10.4.2 删除 10.5 堆栈 10.6 例子:波兰记法和堆栈求值 10.7 队列 10.8 二叉树 10.8.1 二叉树的遍历 10.8.2 创建树 10.9 普通的树 10.9.1 遍历 10.9.2 calloc()的用法以及树的创建 10.10 总结 10.11 练习 第11章 输入/输出和操作系统 11.1 输出函数printf() 11.2 输入函数scanf() 11.3 fprintf()、fscanf()、sprintf() 和sscanf()函数 11.4 fopen()和fclose()函数 11.5 例子:对文件进行空间加倍 11.6 使用临时文件和优雅函数 11.7 随机访问文件 11.8 文件描述符输入/输出 11.9 文件访问权限 11.10 在c程序内部执行命令 11.11 在c程序内部使用管道 11.12 环境变量 11.13 c编译器 11.14 使用性能评估程序 11.15 函数库 11.16 对c代码进行计时 11.17 使用make 11.18 使用touch 11.19 其他有用的工具 11.20 总结 11.21 练习 第12章 高级应用 12.1 用fork()创建并发进程 12.2 进程的叠加:exec...()函数族系 12.3 使用pipe()实现进程间的通信 12.4 信号 12.5 例子:哲学家用餐问题 12.6 矩阵的动态分配 12.6.1 为什么二维数组无法满足要求 12.6.2 用指针数组创建矩阵 12.6.3 调整下标范围 12.6.4 一次分配所有内存 12.7 返回状态 12.8 总结 12.9 练习 第13章 从c到c++ 13.1 输出 13.2 输入 13.3 函数 13.4 类和抽象数据类型 13.5 重载 13.6 构造函数和析构函数 13.7 面向对象编程和继承 13.8 多态 13.9 模板 13.10 c++的异常 13.11 面向对象编程的优点 13.12 总结 13.13 练习 第14章 从c到java 14.1 输出 14.2 变量和类型 14.3 类和抽象数据类型 14.4 重载 14.5 类的创建和销毁 14.6 面向对象编程和继承 14.7 多态和重写方法 14.8 applet 14.9 java的异常 14.10 java和oop的优势 14.11 总结 14.12 练习 附录a 标准函数库 附录b c的语法 附录c ansi c与传统c的比较 附录d ascii字符码 附录e 操作符的优先级和结合性

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值