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