Skip to content

C语言基础

上手

  • 类型
    • 整形
      • int 4 2^(4*8-1)
      • short 2 2^(2*8-1)
      • long 4
      • unsigned short 2 2^(2*8)
      • 负数补码为正数-1再全部取反
      • (int) 类型转换
    • 实型
      • float 4
      • double 8
      • long double 16
    • 字符型
      • char
      • unsigned char
    • auto 自动推断
  • 运算符
    • ++ -- + -
    • + - * / % = += *=
    • ? :
    • < <= => > == !=
    • ! && ||
    • ,取后者
    • ~ << >> & | ^
  • printf
    • printf("a = %d",a)
    • %d %ld %x %c %f %lf 整形 长整形 十六进制整形 字符型 浮点
    • %m.nf 总宽m,n位小数,左补空格
    • %9d,小于9位时左边补空格
  • scanf
    • scanf("%d,%f,%c,%u",&a,&b,&c,&d)
    • char a[100];scanf("%s",&a)
  • putchar 字符输出
  • getchar 字符输入
  • puts 字符串输出
  • gets 字符串输入

流程控制

c
if(a==3)
{
  printf("a")
}
else if(a==5) printf("aa")
else printf("aaaa")
c
char op;
scanf("%c",&op);
switch (op)
{
  case '1': printf('a');break;
  case '2': printf("aa");break;
  default: printf("error");
}
c
int i,sum=0;
i=1;
while (i<=100)
{
  sum+=i;
  i++
}
printf("%d\n",sum);
// while(1)
c
int i,sum=0;
i=1;
do
{
  sum+=i;
  i++  
}while (i<=100);
printf("%d\n",sum);
c
int i,sum=0;
for (i=1;i<=100,i++) 
  sum+=i;
printf("%d\n",sum);
// for(;;)
c
int i,f=1;
i=1;
loop : if (i<=6)
{
  f=f*i;
  i++;
  goto loop;
}
printf("%d\n",f);

数组

  • 数组
    • int array[]={1,2,3,4,5}
    • int a [3] [3]={1,2,3,4,5,6,7,8,9}
    • 未赋值为0
    • sizeof(a) / sizeof(a[0]) 长度
  • 字符串
    • char str[] = "string"
    • 未赋值的自动为'\0'
    • 长度后面一项也为"\0"
    • char c[7]; scanf("%s",c)
    • printf("%s",c)
    • <string.h>
      • gets() puts()
      • strcpy() strncpy() 复制
      • strcat() 合并
      • strcmp() 比较
      • strlen() 长度
      • strchr() strrchr() 首/尾开始查找
      • strspn() strcspn() (不)属于字符集的长度
      • strpbrk() 查指定字符集的任一个字符
      • strstr() 查找\另一个字符串
      • strtok() 分割
      • strcoll() 比较
      • 其它

函数

  • 不能嵌套定义
  • 函数名本质是函数的入口地址
  • 可变参数
    • void func(char *a, ...)
    • va_list arg
    • va_start(arg, a)
    • va_end(arg)
c
#include "stdio.h"
#include "math.h"
int main()
{
  int m;
  int prime(int); // 函数声明
  scanf("%d", &m);
  if (prime(m))
  printf("%d是素数\n", m);
  else
  printf("不是素数\n");
  return 0;
}

int prime(int n)
{
  for (int i = 2; i <= sqrt(n); i++)
  {
  if (n % i == 0)
  return 0;
  }
  return 1;
}

指针

  • &为取地址,* 为取指向的变量
  • int *node=NULL; 防止野指针
c
// 想通过函数改变量值要传指针
// 同理 想改指针指向要传指针的指针
#include "stdio.h"
void swap(int *p1,int *p2)
{
  int t ;
  t=*p1;
  *p1=*p2;
  *p2=t;
}
void main()
{
  int a=10,b=4;
  swap(&a,&b);
  printf("%d,%d\n",a,b);
}

指针和数组

  • 数组名表示数组首地址
  • int* p = a
  • *(a+i) a[i]
  • a &a[0]
  • p++ *(a+=1)
  • void func(int (*p)[]) fun(arr)

指针(的)数组

  • char* p[5]={"xyz","nbplus","hkye","c"}; 字符串数组
  • void main(int argc,char* argv[]){} 也可用于函数参数
c
void main()
{
  char* c[5]={"xyz","nbplus","hkye","c"};
  char** p;
  for(p=c;p<c+5;p++)
  {
  printf("%s\n",*p)
  }
}

指针和函数

c
int* min(int* x,int n)
{
  int i,*q;
  q=x;
  for(i=1;i<n;i++)
  if(*q>*(x+i)) q=x+i;
  return q;
}
void main()
{
  int *p,a[5]={4,7,2,6,9};
  p=min(a,5);
  printf("min:%d\n",*p);
}
c
int max(int x,int y)
{
  return x>y?x:y;
}
void main()
{
  int a,b,c;
  int (*f)(int,int);
  f=max;
  scanf("%d%d",&a,&b);
  c=(*f)(a,b);
  printf("%d\n",c);
}

结构体

  • 支持嵌套定义
  • 默认值数字类型为0或4096 字符为空
c
// 
struct Date
{
    int year;
    int month;
    int day;
}birth1={1999,7,21};
struct Date birth2={1998,12,10};
struct Date birth5={
  .year=1997,
  .month=7,
  .day=7
}
struct Date birth3,birth4;
c
struct Stu
{
    int num;
    char name[10];
    int score;
}stu1;
void main()
{
    printf("please input records:\n");
    scanf("%d%s%d",&stu1.num,&stu1.name,&stu1.score);
    printf("%d,%s,%d\n",stu1.num,stu1.name,stu1.score);
}
c
struct Person
{
    char name[10];
    int count;
}candi[5]={"lucy",0,"bob",0,"kai",0,"tom",0,"bella",0,"tom",0};
c
typedef struct {
    int a;
    double b;
}emp_i, *pemp_i;    //typedef 了两个新的数据类型(结构体),其中一个是指针方式的名字

int main(void)
{
  emp_i  a1;
  pemp_i  b1 = &a1;
  a1.a++;
  b1->a++;
}

链表

c
#include "stdio.h"
#include "string.h"
struct Book
{
    char title[20];
    int total;
    struct Book *next;
};
viod main()
{
    struct Book a,b,c,*head,*p;
    strcpy(a.title,"c语言");
    a.total=105;
    strcpy(b.title,"网页设计");
    b.total=90;
    strcpy(c.title,"数据结构");
    c.total=200;
    head=&a;
    a.next=&b;
    c.next=&c;
    c.next=NULL;
    p=head;
    while (p!=NULL)
    {
        printf("%s,%d\n",(*p).title,(*p).total);
        p=(*p).next;
    }
}
c
#include "stdio.h"
#include "stdlib.h"

struct Book
{
    int num;
    char title[20];
    int total;
    struct Book *next;
};

int n;
struct Book *creat() //创建链表
{
    struct Book *head,*p1,*p2;
    n=0;
    printf("input book information:\n");
    p1=p2=(struct Book *)malloc(sizeof(struct Book));
    scanf("%d%s%d",&(*p1).num,(*p1).title,&(*p1).total);
    while((*p1).num!=0)
    {
        n=n+1;
        if(n==1)
            head=p1;
        else
            (*p2).next=p1;
        p2=p1;
        p1=(struct Book *)malloc(sizeof(struct Book));
        scanf("%d%s%d",&(*p1).num,(*p1).title,&(*p1).total);
    }
    (*p2).next=NULL;
    return head;
};

struct Book *insert(struct Book *head,struct Book *bo)
{
    struct Book *p0,*p1,*p3;
    p1=head;
    p0=bo;
    if(head==NULL)
    {
        head=p0;
        (*p0).next=NULL;
    }
    else
    {
        while(((*p0).num>(*p1).num)&&((*p1).next!=NULL))
        {
            p2=p1;
            p1=(*p1).next;
        }
        if((*p0).num<=(*p1).num)
        {
            if(head==p1)
                head=p0;
            else
                (*p2).next=p0;
            (*p0).next=p1;
        }
        else
        {
            (*p1).next=p0;
            (*p0).next=NULL;
        }
    }
    n+=1;
    return head;
};

struct Book *dele(struct Book *head,int num)  //删除节点
{
    struct Book *p1,*p2;
    if(head==NULL)
    {
        printf("\n the list is empty. \n");
        return head;
    }
    p1=head;
    while(num!=(*p1).num&&(*p1).next!=NULL)
    {
        p2=p1;
        p1=(*p1).next;
    }
    if(num==(*p1).num)
    {
        if(p1==head)
            head=(*p1).next;
        else
            (*p2).next=(*p1).next;
        n=n-1;
    }
    else
        printf("the node could not be found.\n");
    return head;
};

void print(struct Book *head)  //输出链表
{
    struct Book *p;
    p=head;
    printf("book information: \n");
    if(head!=NULL)
        while(p!=NULL)
        {
            printf("%d,%s,%d\n",(*p).num,(*p).title,(*p).total);
            p=(*p).next;
        }
}

void main()
{
    struct Book *head,bo;
    int num;
    head=create();
    printf(head);
    printf("please input the insert record:\n");
    scanf("%d%s%d",&bo.num,bo.title,&bo.total);
    head=insert(head,&bo);
    printf(head);
    printf("the delete number:\n");
    scanf("%d",&num);
    head=dele(head,num);
    printf(head);
}

共用体

共用体同一时间只有一个成员的值是有效的

c
union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

枚举类型

可以看成一个宏定义的集合

c
typedef enum
{
  MONDAY=1,      //如果是从1开始的序列可不写
  TUESDAY,
  WEDNESDAY
}Week_t;

int main()
{
  Week_t week;
  week=MONDAY;    //week==1
  week=TUESDAY;   //week==3
  week=8;    //报错
  b=MONDAY;        //可以不定义直接用b==1
}

别名

c
typedef float FLA;
typedef char NAME[20];
typedef struct Person
{
    int num;
    char name[20];
    char addr[30];
}PER;
PER a,b;

文件

详见stdlib.h

r只读打开文本文件w只写建立新文本文件a追加打开文本文件
rb只读打开二进制文件wb只写建立新二进制文件ab追加打开二进制文件
r+读写打开文本文件w+读写建立新文本文件a+读写追加打开文本文件
rb+读写打开二进制文件wb+读写建立新二进制文件ab+读写追加打开二进制文件

常用方法

  • fopen() 打开
    • FILE *f = fopen("file.txt", "w");
  • fclose() 关闭
    • fclose(f);
    • f=NULL
  • fgetc() 读取一个字符
    • while(c != EOF)
    • c = fgetc(f)
  • fputc() 写入一个字符
    • do{}while(c != '$')
    • fputc(getchar(), f)
  • fgets() 读取一个字符串
    • fgets(str, 99, f)
  • fputs() 写入一个字符串
    • fputs(str, f)
  • fprintf() 写入格式化数据
  • fscanf() 格式化读取数据
  • fread() 读取数据
    • int len = fread(str, size, count, f);
  • fwrite() 写入数据
    • size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
  • feof() 文件是否结束
    • feof(f)
  • ferror() 文件读/写是否出错
  • clearerr() 清除文件错误标志
    • clearerr(f)
  • ftell() 文件指针的当前位置
    • ftell(f)
    • fseek(pf,0,SEEK_END);
    • long n = ftell(f) 文件大小
  • rewind() 把文件指针移到开始处
    • rewind(f)
  • fseek() 重定位文件指针
    • fseek(f,offset,1/2/0)
    • SEEK_CUR 1 当前位置
    • SEEK_END 2 末尾
    • SEEK_SET 0 开头
  • rename() 重命名
    • rename(old, new)
  • remove() 删除
    • remove(f)

例子

c
#include "stdio.h"
#include "stdlib.h"
void main()
{
    FILE *fp;
    char ch;
    if((fp=fopen("C:\\brgzz.tet","w"))==NULL)
    {
        printf("cannot open file!");
        getchar();
        exit(0);
    }
    printf("input a string:\n");
    ch=getchar();
    while(ch!='\n')
    {
        fputc(ch,fp);
        ch=getchar();
    }
    fclose(fp);
}
c
#include "stdio.h"
#include "stdlib.h"
void main()
{
    FILE *fp;
    char ch;
    if((fp=fopen("C:\\brgzz.tet","r"))==NULL)
    {
        printf("cannot open file!");
        getchar();
        exit(0);
    }
    while((ch=fgetc(fp))!=EOF)
        putchar(ch);
    putcgar('\n');
    fclose(fp);
}
c
//将一个文本文献复制到另一个
#include "stdio.h"
#include "stdlib.h"
#define N 80
void main()
{
    FILE *in,*out;
    char infile[10],outfile[10];
    char str[N];
    printf("enter the infile name:\n");
    scanf("%s",infile);
    printf("enter the outfile name:\n");
    scanf("%s",outfile);
    if((in=fopen(infile,"r"))==NULL)
    {
        printf("cannot open file!");
        getchar();
        exit(0);
    }
    if((out=fopen(outfile,"w"))==NULL)
    {
        printf("cannot open file!");
        getchar();
        exit(0);
    }
    while (fgets(str,N,in)!=NULL)
        fputs(str,out):
    fclose(in);
    fclose(out);
}
c
//追加字符串并全部输出
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define N 80
void main()
{
    FILE *fp;
    char str[N];
    if((fp=fopen("C:\\brgzz.txt","a+"))==NULL)
    {
        printf("cannot open file!");
        getchar();
        exit(0);
    }
    printf("input a string:\n");
    gets(str);
    fputs(str,fp);
    rewind(fp); //位置标记移到开头
    while(fgets(str,N,fp)!=NULL)
        puts(str);
    fclose(fp);
}
c
#include "stdio.h"
#include "stdlib.h"
#define N 6
struct stu
{
    char name[10];
    int num;
    int age;
    char addr[15];
}boya[N],boyb[N],*pp,*qq;

void main()
{
    FILE *fp;
    int i;
    pp=boya;
    qq=boyb;
    if((fp=fopen("C:\\stu_list.dat","wb+"))==NULL)
    {
        printf("cannot open file");
        getchar();
        exit(0);
    }
    printf("\ninput data\n");
    for(i=0;i<N;i++,p++)
        scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);
    pp=boya;
    fwrite(pp,sizeof(struct stu),N,fp);
    rewind(fp);
    fread(qq,sizeof(struct stu),N,fp);
    printf("name \tnumber     age      addr\n");
    for(i=0;i<N;i++,qq++)
        printf("%s\t%5d%7d%10s\n",(*qq).name,(*qq).num,(*qq).age,(*qq).addr);
    fclose(fp);
}
c
#include "stdio.h"
#include "stdlib.h"
struct stu
{
    char name[10];
    int num;
    int age;
    char addr[15];
}boya[6],boyb[6],*pp,*qq;
void main()
{
    FILE *fp;
    int i;
    pp=boya;
    qq=boyb;
    if((fp=fopen("c:\\stu_list.dat","w+"))==NULL)
    {
        printf("cannot open file!");
        exit(0);
    }
    printf("\ninput data\n");
    for(i=0;i<6;i++,pp++)
        scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);
    pp=boya;
    for(i=0;i<6;i++,pp++)
        fprintf(fp,"%s%d%d%s\n",(*pp).name,(*pp).num,(*pp).age,(*pp).addr);
    rewind(fp);
    for(i=0;i<6;i++,qq++)
        fscanf(fp,"%s%d%d%s",(*qq).name,&(*qq).num,&(*qq).age,(*qq).addr);
    printf("\n \nname \tnumber age addr \n");
    qq=boyb;
    for(i=0;i<6;i++,qq++)
        printf("%s\t%5d%7d%11s\n",(*qq).name,(*qq).num,(*qq).age,(*qq).addr);
    fclose(fp);
}
c
struct _iobuf {
  char *_ptr; //指向buffer中第一个未读的字节
  int _cnt; //记录剩余的未读字节的个数
  char *_base;//文件的缓冲
  int _flag;//打开文件的属性
  int _file;//获取文件描述
  int _charbuf;//单字节的缓冲,即缓冲大小仅为1个字节
  int _bufsiz;//记录这个缓冲大小
  char *_tmpfname;//临时文件名
};
typedef struct _iobuf FILE;

其它

宏定义

  • 习惯上用大写字母表示
  • 不要分号,不参与检查
  • 可以使用#undef宏名来终止宏定义
  • 可嵌套使用
    • #define A 2
    • #define B (A*10)
  • 带参数使用
    • #define SQ(x) x*x
    • a=SQ(5);//a=25
  • 带逻辑
    • #define MAX(x,y) (x)>(y)?(x):(y)
  • 带函数
    • #define F1(a,b) printf("%d\n",a>b?a:b);
  • 定义格式字符串
    • #define F2 "%d,%d\n"

模块

  • include "文件名"
  • .h 头文件
    • 函数声明
    • 宏定义
    • 结构体定义
  • .c 程序文件
    • 主函数实现
  • .cpp c++文件

条件编译

c
//如果标识符被#define宏命令过,则编译程序1
#ifdef 标识符
	程序1;
#else
	程序2;
#endif

//如果标识符未被#define宏命令过,则编译程序1
#ifndef 标识符
	程序1;
#else
	程序2;
#endif

//如果表达式非0,则编译程序1
#if 表达式
	程序1;
#else
	程序2;
#endif

关键字

  • static
    • 局部变量的值保持
    • 静态全局变量仅对当前文件可见
    • 静态类成员属于整个类
  • extern
    • 用于跨文件使用变量
  • volatile
    • 阻止编译器优化
    • 运行时不用缓存
cpp
// c语言中的#include 基本等效于把文件内容写进来
// 因此其实.h文件里面东西写进来就不用引入了
// 编译的时候要把用到的文件都写上
// g++ -o demo main.cpp test.cpp
#include <iostream>
using namespace std;

// static int a; // 使用文件自己的a
// extern int a; // 使用全局的a

int print(void);

int main() {
  cout << a << endl;
  print();
  return 0;
}
cpp
#include <iostream>
using namespace std;
int a = 17;

void print() { cout << a << endl; }

内置函数

  • exit(0) 退出
  • perror(char *string) 报错
  • memset()
  • bzero(void *s, int n) 将内存块前n个字节清零 string.h
c
#include <stdio.h>
#include <string.h>

int main() {
    char str[50] = "Hello, World!";
    printf("Before memset: %s", str);
    // 将字符串的前 5 个字符设置为 'A'
    memset(str, 'A', 5);
    printf("After memset: %s", str);
    return 0;
}

动态内存分配

使用malloc可以在程序运行时确定数组长度

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

int main() {
    int len;
    int i, b;
    // 注意:这里应先声明指针,然后使用malloc分配内存
    int *p = (int *)malloc(4 * sizeof(int)); // 分配内存空间,size为所需字节数
    if (p == NULL) { // 检查内存是否成功分配
        printf("内存分配失败");
        return -1;
    }
    printf("请输入数组个数:");
    scanf("%d", &len);
    // 根据用户输入调整内存分配大小
    p = (int *)realloc(p, len * sizeof(int)); 
    if (p == NULL) { // 再次检查内存是否成功分配
        printf("内存重新分配失败");
        return -1;
    }
    printf("请输入要存储的数字:");
    for (i = 0; i < len; i++) {
        scanf("%d", &p[i]);
    }
    for (b = 0; b < len; b++) {
        printf("%d", p[b]);
    }
    // 释放所分配的内存
    free(p);
    return 0;
}

time.h 时间库

c
#include "stdio.h"
#include "time.h"

time_t ts;
struct tm *date;
char *str;

int main()
{
  ts = time(0);
  printf("%d\n", ts);
  date = gmtime(&ts);
  printf("%d\n", date->tm_hour);
  date = localtime(&ts);
  printf("%d\n", date->tm_hour);
  ts = mktime(date);
  printf("%d\n", ts);
  str = ctime(&ts);
  printf("%s\n", str);
  str = ctime(date);
  printf("%s\n", str);
  str = ctime(date);
  printf("%s\n", str);
  return 0;
}

argc & argv

  • ./argtest 1234 abcd
  • argc 3
  • argv ["./argtest", "1234", "abcd"]