zoukankan      html  css  js  c++  java
  • c语言_随笔

    C语言技能树 https://bbs.csdn.net/skill/c

    c语言开发环境(VS Code)

    下载编译器:https://sourceforge.net/projects/mingw-w64/files/ 往下稍微翻一下,选最新版本中的x86_64-posix-seh。最好不要用 Download Latest Version,这个是在线安装包

    看好bin文件夹的完整路径,我是C:mingw64in,把它加到环境变量中的PATH里去。Debian系Linux用sudo apt update; sudo apt install build-essential即可。

    gcc -v可以显示出gcc的版本。如果显示出来的版本与你刚下的不同/更老,说明Path里原本有老版本的编译器,可能是安装其它IDE时装上的。则需要去掉Path里原来的那一个gcc的路径。

    安装扩展(extension)

      • C/C++:又名 cpptools,提供Debug和Format功能
      • Code Runner:右键即可编译运行单文件,很方便;但无法Dubug

    注意:如果程序里有scanf()等请求键盘输入数据的函数,此时无法从键盘输入数据,并且程序无法结束需要关闭重启vscode才能重新执行

    解决办法是依次打开:文件>首选项>设置>用户设置>拓展>Run Code Configuration

    找到  Run In Terminal  打上勾 这样运行的程序就会运行在vscode的集成控制台上

    编译运行

    f5

     

    c程序编译多文件(通过tasks.json)

    launch.json

    {
        // 使用 IntelliSense 了解相关属性。 
        // 悬停以查看现有属性的描述。
        // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                "name": "gcc.exe - 生成和调试活动文件",
                "type": "cppdbg",
                "request": "launch",
                "program": "${fileDirname}\${fileBasenameNoExtension}.exe",
                "args": [],
                "stopAtEntry": false,
                "cwd": "${workspaceFolder}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "miDebuggerPath": "C:\mingw64\bin\gdb.exe",
                "setupCommands": [
                    {
                        "description": "为 gdb 启用整齐打印",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "preLaunchTask": "gcc.exe build active file"
            }
        ]
    }

    tasks.json

    {
        "version": "2.0.0",
        "tasks": [
            {
                "type": "shell",
                "label": "gcc.exe build active file",
                "command": "C:\mingw64\bin\gcc.exe",
                "args": [
                    "-g",
                    "${file}",
                    "${fileDirname}\package\hello.c",
                    "-o",
                    "${fileDirname}\${fileBasenameNoExtension}.exe"
                ],
                "options": {
                    "cwd": "C:\mingw64\bin"
                },
                "problemMatcher": [
                    "$gcc"
                ],
                "group": "build"
            }
        ]
    }

    Windows下C语言的Socket编程例子(TCP和UDP) 

    重要提醒:如使用了winsock2.h gcc编译器必须增加 -lws2_32 指令

    server.c

    #include <stdio.h>
    #include <winsock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int main(int argc, char *argv[])
    {
        //初始化WSA
        WORD sockVersion = MAKEWORD(2, 2);
        WSADATA wsaData;
        if (WSAStartup(sockVersion, &wsaData) != 0)
        {
            return 0;
        }
    
        //创建套接字
        SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (slisten == INVALID_SOCKET)
        {
            printf("socket error !");
            return 0;
        }
    
        //绑定IP和端口
        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_port = htons(8888);
        sin.sin_addr.S_un.S_addr = INADDR_ANY;
        if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
        {
            printf("bind error !");
        }
    
        //开始监听
        if (listen(slisten, 5) == SOCKET_ERROR)
        {
            printf("listen error !");
            return 0;
        }
    
        //循环接收数据
        SOCKET sClient;
        struct sockaddr_in remoteAddr;
        int nAddrlen = sizeof(remoteAddr);
        char revData[255];
        while (1)
        {
            printf("等待连接...
    ");
            sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
            if (sClient == INVALID_SOCKET)
            {
                printf("accept error !");
                continue;
            }
            printf("接受到一个连接:%s 
    ", inet_ntoa(remoteAddr.sin_addr));
    
            //接收数据
            int ret = recv(sClient, revData, 255, 0);
            if (ret > 0)
            {
                revData[ret] = 0x00;
                printf(revData);
            }
    
            //发送数据
            char *sendData = "你好,TCP客户端!
    ";
            send(sClient, sendData, strlen(sendData), 0);
            closesocket(sClient);
        }
    
        closesocket(slisten);
        WSACleanup();
        return 0;
    }

    client.c

    #include <stdio.h>
    #include <winsock2.h>
    #include <STDIO.H>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int main(int argc, char *argv[])
    {
        WORD sockVersion = MAKEWORD(2, 2);
        WSADATA data;
        if (WSAStartup(sockVersion, &data) != 0)
        {
            return 0;
        }
    
        SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sclient == INVALID_SOCKET)
        {
            printf("invalid socket !");
            return 0;
        }
    
        struct sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(8888);
        serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        if (connect(sclient, (struct sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
        {
            printf("connect error !");
            closesocket(sclient);
            return 0;
        }
        char *sendData = "你好,TCP服务端,我是客户端!
    ";
        send(sclient, sendData, strlen(sendData), 0);
    
        char recData[255];
        int ret = recv(sclient, recData, 255, 0);
        if (ret > 0)
        {
            recData[ret] = 0x00;
            printf(recData);
        }
        closesocket(sclient);
        WSACleanup();
        return 0;
    }

    ------------------------------------------------------------------------------------------------分割线------------------------------------------------------------------------------------------------

    LIB

      nanomsg是一个socket library,提供了几种常见的通信模式

      libwebsockets 
     
    静态局部变量
    void f(void){
        static int i;//static local variable
        ...           
    }

    因为局部变量的i已经声明为static,所以在程序执行期间它所占据的内存单元是不变的。在f返回时,变量i不会丢失其值。

    静态局部变量始终有块作用域,所以它对其它函数是不可见的。概括来说,静态变量是对其它函数隐藏数据的地方,但是它会为将来同一个函数的在调用保留这些数据。

    const保护参数

    void f(const int *p){
        *p = 0; //wrong
    }

    指针作为返回值

    int *max(int *a, int *b){
        if(*a>*b)
            return a;
        else
            return b;    
    }
    
    int *p,i,j;
    ...
    p = max(&i,&j);

    指针的算数运算

    只有3种方式

      指针加上整数;

      指针减去整数;

      两个指针相减;

    指向符合常量的指针

    int *p = (int []){3,0,3,4,1};
    
    //对比
    
    int a[] = {3,0,3,4,1};
    int *p = &a[0];

    指针用于数组处理

    #define N 10
    ...
    int a[N],sum,*p;
    ...
    sum = 0;
    for(p = &a[0]; p < &a[N]; p++)
        sum += *p;
    //简化
    for(p = a; p < a + n; p++)
      sum += *p;

     用数组名作为指针

    int a[10];
    
    *a = 7;//store 7 in a[0]
    
    *(a+1) = 12;//store 12 in a[1]
    
    //通常情况下,a+i 等同于&a[i]

     预处理指令

    #define //宏定义
    #undef //删除一个宏定义
    #include //文件包含
    #if #ifdef #ifndef #elif #else #endif //条件编译

    带参数宏

    #define MAX(x,y) ((x)>(y)?(x):(y))
    #define IS_EVEN(n) ((n)%2==0)
    
    //检测字符c是否在'a'与'z'之间,在:返回对应的大写,不在:原值返回
    #define TOUPPER(c) ('a'<=(c)&&(c)<='z'?(c)-'a'+'A':(c))
    
    //#运算符将宏的一个参数转换为字符串字面量
    #define PRINT_INT(n) printf(#n " = %d
    ",n)
    
    //##运算符可以将两个记号(如标识符)“粘合”在一起,成为一个记号
    #define MK_ID(n) i##n

    参数可变宏 

    #define TEST(condition,....) ((condition)?
        printf("Passed test:%s
    ",#condition):
        printf(__VA_ARGS__))

     预定义宏

    __LINE__   被编译的文件中的行号

    __FILE__    被编译的文件名

    __DATE__  编译的日期(格式“Mmm dd yyyy”)

    __TIME__   编译的时间(hh:mm:ss)

    __STDC__  编译器符合c标准(c89 c99)值为1

     ...等

    共享变量的声明

    int i;//declares i and defines it as well

    extern int i; //declares i without defining it

    extern 告诉编译器,变量i是在程序中其它位置定义的(很可能是在不同的源文件中),因此不需要为i分配空间。

    结构标记的声明

    struct part{
        int number;
        char name[NAME_LEN+1];
        int on_hand;      
    };
    
    struct part part1,part2;

    结构类型的定义

    typedef struct{
        int number;
        char name[NAME_LEN+1];
        int on_hand;  
    } Part;
    
    Part part1,part2;

    联合

    //编译器只为联合中最大的成员分配足够的内存空间。
    union{
        int i;
        double d;  
    } u;

    枚举

    //与结构和联合一样,两种方法命名枚举。
    
    enum suit{CLUBS,DIAMONDS,HEARTS,SPADES};
    enum suit s1,s2;
    
    typedef enum {CLUBS,DIAMONDS,HEARTS,SPADES} Suit;
    Suit s1,s2;

     内存分配函数

    malloc 分配内存块,但是不对内存块进行初始化。

    calloc 分配内存快,并且对内存块进行清零。

    realloc 调整先前分配内存快大小。

    //为字符串分配内存,实际参数是n+1而不是n,给空字符留了空间
    p = (char *)malloc(n+1);
    
    //对上述数组初始化的一种方法是调用strcpy函数
    strcpy(p,"abc");
    //使用malloc函数为数组分配储存空间
    int *a;
    a = malloc(n * sizeof(int));
    for(i = 0; i < n; i++)
        a[i] = 0;
    //为nmemb个元素的数组分配内存空间,其中每个元素的长度是size个字节。
    void *calloc(size_t nmemb, size_t size);
    
    //保证所有整数初始均为零
    a = calloc(n, sizeof(int));
    
    //p指向一个结构,此结构的成员x和y都被设为零
    struct point {int x, y;} *p;
    p = calloc(1, sizeof(struct point));
    //prt指向分配好的内存块,size表示内存块的新尺寸
    void *realloc(void *ptr, size_t size);

    free函数

    //“悬空指针”
    char *p = malloc(4);
    ...
    free(p);
    ...
    strcpy(p,"abc");//wrong

    函数指针

    //integrate函数求函数f在a点和b点之间的积分
    double integrate(double (*f)(double),double a,double b);
    
    double integrate(double f(double),double a,double b);
    
    //sin是函数
    result = integrate(sin,0.0,PI/2);

    qsort函数 给任意数组排序的通用函数

    /**
     *base 数组中第一个元素 
     *nmemb 要排序元素的数量
     *size 每个数组元素的大小(字节)
     *compar 比较函数的指针
     */
    void qsort(void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *));
    
    qsort(inventory,num_parts,sizeof(struct part),compare_parts);
    
    int compare_parts(const void *p, const void *q){
        const struct part *p1 = p;
        const struct part *q1 = q;
        if(p1->number < q1->number)
            return -1;
        else if(p1->number == q1->number)    
            return 0;
        else
            return 1;
    }
    
    //简写
    int compare_parts(const void *p, const void *q){
        if(((struct part *)p)->number < ((struct part *)q)->number)
            return -1;
        else if(((struct part *)p)->number == ((struct part *)q)->number)
            return 0;  
        else
            return 1;
    }

    函数指针的其它用途

    可以把函数指针存储在变量中,或者用作数组的元素,再或者用作结构或联合的成员,甚至可以编写返回函数指针的函数。

    //pf可以指向任何带有int型形式参数并且返回void型值的函数。
    void (*pf)(int);
    
    //如果f是这样的函数,pf指向f
    pf = f;
    
    //注意,在f的前面没有取地址符号(&)。一旦pf指向函数f,可以用下面写法调用f
    (*pf)(i);
    
    //也可以
    pf(i);
    
    //元素是函数指针的数组,假设我们编写的程序需要向用户显示可选择的命令菜单。编写函数实现这些命令,把指向这些函数的指针储存在数组中
    void (*file_cmd[])(void)={
        new_cmd,
        open_cmd,
        close_cmd,
        close_all_cmd,
        save_cmd,
        save_as_cmd,
        save_all_cmd,
        print_cmd,
        exit_cmd
    };
    
    //如果选择命令n,对数组取下标,调用函数
    (*file_cmd[n])();//or file_cmd[n]();

     受限制指针

    // 如果指针p指向的对象在之后需要修改,那么该对象不允许通过除指针p之外的任何方式访问(其他访问对象的方式包括让另一个指针指向同一个对象,或者让指针p指向命名变量)。如果一个对象有多种访问方式,通常把这些方式互称为别名。
    int * restrict p;

     灵活数组成员c99

    struct vstring{
        int len;
        char chars[];
    };
    
    struct vstring *str = malloc(sizeof(struct vstring)+n);
    str ->len = n;

     register 储存类型

    声明变量具有register存储类型就要求编译器把变量存储在寄存器中,而不是像其他变量一样保留在内存中。

    register是一种请求,而不是命令。

    //
    int sum_array(int a[],int n){
        register int i;
        int sum = 0;
        
        for(i=0;i<n;i++)
            sum+=a[i];
        return sum;
    }

    函数的存储类型

    extern说明函数具有外部链接,也就是允许其他文件调用此函数。

    static说明是内部链接,也就是说只能在定义函数的文件内部调用此函数。

    如果不指明函数的储存类型,那么会假设函数具有外部链接。

    解释复杂声明

    int *(*x[10])(void);

    无论多么复杂,下面有两条简单的规则可以用来解释任何声明

      1 始终从内往外读声明符。

      2 在作选择时,始终使 []和()优先于*。

    内联函数 (inline function)

    "内联"表明编译器把函数的每一次调用都用函数的机器指令来代替。会使被编译程序的大小增加一些,但是可以避免函数调用的常规额外开销。

    inline类似于register和restrict关键之,后两者也是用于提升程序性能的,但可以忽略。

    //例
    inline double average(double a,double b){ return (a+b)/2; } //average有外部链接,所以在其他文件也可以调用average。但是编译器并没有考虑average的定义是外部定义(它是内联定义),所以试图在别的文件中调用average将被认为是错误的。 //两种方式避免 //1 static inline double average(double a,double b){ return (a+b)/2; } //2 更好一些的实现方式 //内联定义放入头文件(average.h) #ifndef AVERAGE_H #define AVERAGE_H static inline double average(double a,double b){ return (a+b)/2; } #endif //接下来,在创建与之匹配的源文件average.c #include "average.h" extern double average(double a,double b);

     对内联函数的限制

     因为内联函数的实现方式和一般函数不大一样,所以需要不同的规则和限制。

      1 函数中不能定义可改变的static变量。

      2 函数中不能引用具有内部链接的变量。

     不完整类型

    c标准对不完整类型的描述是:描述了对象但缺少定义对象大小所需的信息。

    //这样做的意图是:不完整类型将会在程序的其他地方将信息补充完整
    struct t; //incomplete declaration of t
    
    //因为编译器不知道不完整类型的大小,所以不能用它来声明变量
    struct t s; //wrong
    
    //但是完全可以定义一个指针类型引用不完整类型
    typedef struct t *T;

    位运算符

    移位运算符

    << //左移位
    >> //右移位

    注意:移位运算符的优先级比算术运算符的优先级低。

    按位求反运算符、按位与、按位异或、按位或

    ~    //按位求反
    &    //按位与
    ^    //按位异或
    |    //按位或

     volatile类型限定符

    volatile类型限定符使我们可以通知编译器,程序中的某些数据是“易变”的。

    //volatile限定符通常使用在用于指向易变内存空间的指针的声明
    volatile BYTE *p; // p will point to a volatile byte
    
    //假设指针p指向的内存空间用于存放键盘输入的最近字符。这个内存空间就是易变的。
    //使用下面循环获取键入字符,并存入一个缓冲区数组中:
    while(缓冲区未满){
        等待输入;
        buffer[i] = *p;
        if(buffer[i++] == '
    ')
            break;
    }
    
    //比较好的编译器可能会注意到这个循环没有改变p,也没改变*p,会对程序进行优化,使*p只被取一次
    在寄存器中存储*p
    while(缓冲区未满){
        等待输入;
        buffer[i] = 存储在寄存器中的值;
        if(buffer[i++] == '
    ')
            break;
    }
    
    //将p声明成指向易变数据的指针可以避免这一问题发生。

    标准库的使用 (c89标准库15个 c99新增了9个 共24个

    <assert.h>//诊断
    <ctype.h>//字符处理  
    <errno.h>//错误
    <float.h>//浮点类型的特性
    <limits.h>//整数类型的大小
    <locale.h>//本地化
    <math.h>//数学计算
    <setjmp.h>//非本地跳转
    <signal.h>//信号处理
    <stdarg.h>//可变参数
    <stddef.h>//常用定义
    <stdio.h>//输入/输出
    <stdlib.h>//常用使用程序
    <string.h>//字符串处理
    <time.h>//日期和时间
    
    <complex.h>//复数算数
    <fenv.h>//浮点环境
    <inttypes.h>//整数类型格式转换
    <iso646.h>//拼写转换
    <stdbool.h>//布尔类型和值
    <stdint.h>//整数类型
    <tgmath.h>//泛型数学
    <wchar.h>//扩展的多字节和宽字符实用工具
    <wctype.h>//宽字符分类和映射使用工具

    使用宏隐藏的函数

    c标准允许在头中定义与库函数同名的宏,为了起到保护作用,还要求有实际的函数存在。声明一个函数并同时定义一个有相同名字的宏的情况并不少见。

    //<stdio.h>中有如下原型
    int getchar(void);
    
    //<stdio.h>通常也把getchar定义为一个宏
    #define getchar() getc(stdin)

     流(stream)

     <stdio.h>中的许多函数可以处理各种形式的流,而不仅仅可以处理表示文件的流。

    文件指针

    FILE *fp1,*fp2;

    标准流和重定向

    <stdio.h>提供了3个标准流。

    文本文件与二进制文件

    <stdio.h>支持两种类型的文件:文本文件和二进制文件。

    文本文件具有两种二进制文件没有的特性:

      1 文本文件分为若干行

      2 文本文件可以包含一个特殊的“文件末尾”

    在无法确定文件是文本形式还是二进制形式时,安全的做法是把文件假定为二进制文件。

    文件操作

    打开文件

    //filename:文件名 mode:模式字符串
    FILE *fopen(const char * restrict filename,const char *restrict mode);
    
    //windows程序员注意,c语言会把字符看成是转义序列。
    fopen("c:project	est1.dat","r"); //error
    
    //可以用\代替
    fopen("c:\project\test1.dat","r");
    
    //用/代替
    fopen("c:/project/test1.dat","r");

    用于文本文件的模式字符串

    "r"//打开文件用于读    
    "w"//打开文件用于写(文件不需存在)
    "a"//打开文件用于追加(文件不需存在)
    "r+"//打开文件用于读和写,从文件头开始
    "w+"//打开文件用于读和写(如果文件存在就截去)
    "a+"//打开文件用于读和写(如果文件存在就追加)

    用户二进制文件的模式字符串

    "rb"//打开文件用于读    
    "wb"//打开文件用于写(文件不需存在)
    "ab"//打开文件用于追加(文件不需存在)
    "rb+"//打开文件用于读和写,从文件头开始
    "wb+"//打开文件用于读和写(如果文件存在就截去)
    "ab+"//打开文件用于读和写(如果文件存在就追加)

    关闭文件

    //成功返回0,否则,返回错误代码EOF(<stdio.h>中定义的宏)
    int fclose(FILE *stream);

    示例

    #include <stdio.h>
    #include <stdlib.h>
    
    #define FILE_NAME "example.dat"
    
    int main(void) {
        FILE *fp = fopen(FILE_NAME, "r");
        if (fp == NULL) {
            printf("Can't open %s
    ", FILE_NAME);
            exit(EXIT_FAILURE);
        }
        //...
        fclose(fp);
        return 0;
    }

    为打开的流附加文件

    //freopen函数为已经打开的流附加上一个不同的文件。最常见的用法是把文件和一个标准流(stdin、stdout、stderr)相关联。
    FILE *freopen(const char * restrict filename,const char * restrict mode,File * restrict stream);
    
    //例如,为了使程序开始往文件foo中写数据
    if(freopen("foo","w",stdout)==NULL){
        //error;foo can't be opened  
    }

    从命令行获取文件名

    demo name.dat dates.dat

    //
    argc是命令行的数量,argv是指向参数字符串的指针数组。 //argv[0]程序名字,argv[argc-1]都指向剩余的实际参数。 int main(int argc,char *argv[]){ .... }

    临时文件

    //创建一个临时文件(用"wb+"模式打开),返回文件指针
    FILE *tmpfile(void);
    
    //为临时文件产生名字。
    char *tmpnam(char *s);
    
    //如果它的参数是空指针,那么tmpnam会把文件名储存到一个静态变量中,并返回指向此变量的指针
    char *filename;
    ...
    filename = tmpnam(NULL); //creates a temporary file name
    
    //否则,tmpnam函数会把文件名复制到程序员提供的字符数组中
    char filename[L_tmpnam];
    ...
    tmpnam(filename);//creates a temporary file name

    文件缓冲

    int fflush(FILE *stream);
    void setbuf(FILE * restrict stream,char * restrict buf);
    void setvbuf(FILE * restrict stream,char * restrict buf,int mode,size_t size);

    fflush可以按我们希望的频率来清洗文件的缓冲区。

    fflush(fb); //flushes buffer for fb
    
    fflush(NULL); //flushes all buffers

    setvbuf函数允许改变缓冲流的方法,并且允许控制缓冲区的大小和位置。

    第三个参数指明了期望的缓冲类型,三个宏:

      1 _IOFBF(满缓冲)。

      2 _IOLBF(行缓冲)。

      3 _IONBF(无缓冲)。

    第二个参数是期望缓冲区地址。可以是静态储存期限,自动储存期限,甚至可以是动态分配的。

    最后一个参数是缓冲区内字节的数量。

    例如

    //利用buffer数组中的N个字节作为缓冲区,而把stream的缓冲变成了满缓冲
    char buffer[N];
    ...
    setvbuf(stream,buffer,_IOFBF,N);

    setbuf函数是一个较早期的函数,缓冲模式和缓冲区大小默认。

    //buf是空指针,等价于
    (void)setvbuf(stream,NULL,_IONBF,0);
    //否则等价于
    (void)setvbuf(stream,buf,_IOFBF,BUFSIZ);

    其他文件操作

    //删除文件
    int remove(const char *filename);
    //重命名
    int rename(const char *old,const char *new);

     检测文件末尾和错误条件

    void clearerr(FILE *stream);
    int feof(FILE *steam);
    int ferror(FILE *steam);

    字符的输入/输出

    输出函数

    int fputc(int c,FILE *stream);
    int putc(int c,FILE *stream);
    int putchar(int c);

    输入函数

    int fgetc(FILE *stream);
    int getc(FILE *stream);
    int getchar(void);
    int ungetc(int c,FILE *stream);

    行的输入/输出

    输出函数

    int fputs(const char * restrict s,FILE * restrict stream);
    int puts(const char *s);

    输入函数

    char *fgets(char * restrict s,int n,FILE * restrict stream);
    char *gets(char *s);

    块的输入/输出

    freade和fwrite函数可以用于文本流,但是它们主要还是用于二进制流

    size_t fread(void * restrict ptr, size_t size,size_t nmemb,FILE * restrict stream);
    size_t fwrite(const void * restrict prt,size_t size,size_t nmemb,FILE * restrict stream);

    文件定位

    int fgetpos(FILE * restrict stream,fpos_t * restrict pos);
    int fseek(FILE * stream,long int offset,int whence);
    int fsetpos(FILE * stream,const fpos_t *pos);
    long int ftell(FILE * stream);
    void rewind(FILE *stream);

    字符串的输入/输出

    输出函数

    int sprintf(char * restrict s,const char * restrict format,...);
    int snprintf(char * restrict s, size_t n,... const char * restrict format,...);

    输入函数

    int sscanf(const char * restrict s,const char * restrict format,...);

    其它

    eclipse cdt导入c项目
      右键Properties->c/c++ Build->Settings->Build artifact->Artifact type->Executable
  • 相关阅读:
    C++_重载、重写和重定义的区别
    C++静态库与动态库
    C++ 中重载运算符 “<” 及 friend属性
    C++中,关于#include<***.h>和#include"***.h"的区别
    static_cast, dynamic_cast, const_cast讨论
    浅析C++中static关键字
    C语言包含头文件时用引号和尖括号的区别
    vc实现透明位图,透明背景
    VS2008调试技巧——断点失效
    Spring解决循环依赖的理解
  • 原文地址:https://www.cnblogs.com/xiaomaoyvtou/p/9212372.html
Copyright © 2011-2022 走看看