c 入门笔记

176 阅读7分钟

字符串

strcpy(s1,s2)
strcat(s1,s2)
strcmp(s1,s2)

strchr(s1,char1)
strstr(s1,s2)

char  *index=strstr("hello,ss,world","ss");
printf("index is %s\n",index);//index is ss,world

从键盘读取数据

putchar(100);
putchar(98);
printf("\n");
char str[100];
puts("enter something\n");
gets(str);
puts(str);
puts("enter something\n");
scanf("%s",str);
printf("your enter: %s\n",str);

scanf: 碰到空格,回车就自动结束读取了。比如输入hello world,因为有空格,第一次只能读取hello,下次继续sanf才能读取world char c=getchar() 这个一次读取一个字符 gets这个可以一次读取的字符串限定的大小字符。

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

ptr 一般就是个buffer数组来存储读取到的字符 size:一次读取的字节数 nmemb:读取几次 stream:就是打开的FILE流 比如

FILE *fp =fopen("xxx.txt","r")
char buffer[255]
//我们打算一次读取100个字符,那么可以这样写
int length= fread(buffer,100,1,fp) //读取成功,length返回1
int length= fread(buffer,20,5,fp) //读取成功,length返回5
int length= fread(buffer,1,100,fp) //读取成功,length返回100
//如果直接读完了,也就是到file末尾了,那么length返回的是0

snprintf 格式化字符串到buffer里

char buff[30];
int j=snprintf(buff,30,"%d--%d--%d",2022,10,1);

常量的定义

#define abc 10+10
const int thread_hold = 13;

#define 这种更像一种占位符,也就是哪里用到它就把它后边的值替换过去,比如 abc*2 ,替换完就是10+10*2,结果就不是自己想要的,所以define后边的值最后加个括号,或者在用的时候加个括号
#define abc (10+10)
或者(abc)*2

函数声明

参数名字不重要,可以省略

int max(int num1, int num2);
int max(int, int);

引用方式调用函数

注意符号: 指针* 地址&

/* 函数定义 */
void swap(int *x, int *y)
{
   int temp;
   temp = *x;    /* 保存地址 x 的值 */
   *x = *y;      /* 把 y 赋值给 x */
   *y = temp;    /* 把 temp 赋值给 y */
  
   return;
}
int a = 100;
int b = 200;
swap(&a, &b);

传递数组给函数

方式 1

形式参数是一个指针(您可以在下一章中学习到有关指针的知识):

void myFunction(int *param) { . . . }

方式 2

形式参数是一个已定义大小的数组:

void myFunction(int param[10]) { . . . }

方式 3

形式参数是一个未定义大小的数组:

void myFunction(int param[])

枚举

在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的

#include <stdio.h> 
#include <stdlib.h> 
int main() { 
enum day { saturday, sunday, monday, tuesday, wednesday, thursday, friday } workday; 
int a = 1; 
enum day weekend; 
weekend = ( enum day ) a; 
//类型转换 //weekend = a; //错误 
printf("weekend:%d",weekend); 
return 0; }

从函数返回指针

C 语言不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。

int * getRandom( ) { 
static int r[10]; 
int i; 
/* 设置种子 */ 
srand( (unsigned)time( NULL ) ); 
for ( i = 0; i < 10; ++i) { 
r[i] = rand(); 
printf("%d\n", r[i] ); 
} 
return r; }

字符串以及结构体赋值

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */

   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
 
 
   /* 输出 Book1 信息 */
   printf( "Book 1 title : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);
 
 
   return 0;
}

c里的字符串和java不太一样,它就是个char数组,默认还是个默认的'\0',长度多个1,
比如char name[]="jerry" ,strlen 结果是6 其他字符串操作 strcmp: string compare 

strcat: string catenate 

strcpy: string copy 

strlen: string length 

strlwr: string lowercase 

strupr: string upercase

1strcpy(s1, s2); 复制字符串 s2 到字符串 s1。
2strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。
3strlen(s1); 返回字符串 s1 的长度。
4strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。
5strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

'a'  表示是一个字符, "a"  表示一个字符串相当于 'a'+'\0';

结构体指针

struct Books *struct_pointer;

struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符

struct_pointer->title;

共用体

共用体和上边的struct长得差不多,就是修饰符变成了union而已。
所谓的共用体就是 大家同在一个屋檐下,不过同一时间只能有一个可用【嗯,就是那种移动厕所,男女老少都可以去,可是一次只能一个人进去】,同一时间只用到一个成员

union Data { 
int i; 
float f; 
char str[20]; 
};

共用体占用的内存应足够存储共用体中最大的成员,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的

位域

如下,就是在变量名字后边加个冒号数字,限制下变量的存储长度,节省内存,为啥?因为
比如 int a:1; 这个a只会存储0或者1,用个int的长度就太浪费了,加上冒号1就限制它的存储长度了。 当然了,你可以给a赋值2,也就是二进制的10,那么a打印的结果其实是0,只会取一位,最后一位。

struct bs{ 
int a:8; 
int b:2; 
int c:6; }data;

输入输出

char a=getchar ; putchar(a);

char str[100]; gets(str); puts(name);

//scanf,printf 第一个参数就是一个format的字符串,替换后边的变量 char str[100]; int i; printf( "Enter a value :"); scanf("%s %d", str, &i); printf( "\nYou entered: %s %d ", str, i); printf("\n");

预处理器

字符串常量化运算符(#)

标记粘贴运算符##

#include <stdio.h> 
#define tokenpaster(n) printf ("token" #n " = %d", token##n) 
int main(void) { 
int token34 = 40; 
tokenpaster(34); 
return 0; }

打印结果:token34 = 40

参数化的宏

int square(int x) {
   return x * x;
}

下边和上边一样的效果

#define square(x) ((x) * (x))

函数指针

而函数指针是指向函数,或者可以说给原方法起个别名?

int max(int x, int y) { return x > y ? x : y; }
int (* p)(int, int) = & max; // &可以省略

完事p(a, b) 就和max(a,b)效果一样了

看下源码里的真实代码,struct最后那个参数 process

struct android_app;
struct android_poll_source {
    // The identifier of this source.  May be LOOPER_ID_MAIN or
    // LOOPER_ID_INPUT.
    int32_t id;

    // The android_app this ident is associated with.
    struct android_app* app;

    // Function to call to perform the standard processing of data from
    // this source.
    void (*process)(struct android_app* app, struct android_poll_source* source);
};

void

对于函数来说,void表示返回为空或者参数为空 ,比如 void fun (void);

类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size );  返回指向 void 的指针,可以转换为任何数据类型。
void* userData;

__attribute__关键字

描述函数,变量和数据类型的属性,用于编译器对源代码的优化 void noreturnfun() _attribute_((noreturn));//函数不会返回。

void centon() _attribute_((alias("__centon")));//设置函数别名,函数是__cencon,别名是centon.

void main_enter() _attribute_((constructor));//main_enter函数在进入main函数前调用

void main_exit() _attribute_((destructor));//main_exit函数在main函数返回后调用

void fun() _attribute_ ((noinline));//fun函数不能作为inline函数优化

void fun() _attribute_ ((section("specials”)));//将函数放到specials段中,而不是通常的text段中

no_instrument_function、constructor和destructor关键字主要用于剖析(profiling)源代码的。

可以放在函数后边也可以放在前边,如下:

__attribute__((destructor)) void main_exit() {
printf("end==============\n"); //这个函数在main执行完以后会被调用
}; 

比如这个,函数过期注解

__attribute__((
    deprecated("Calls to app_dummy are no longer necessary. See "
               "https://github.com/android-ndk/ndk/issues/381."))) void
app_dummy();

可变参数

第一个参数int类型的,表示可变参数的个数,后边三个点表示可变参数

int func(int, ... ) { . . . }

使用

func(2, 2, 3); //2个参数,2,3
func(3, 2, 3, 4);//3个参数,2,3,4