C语言笔记
等号赋值的返回
将等号赋值表达式作为返回值, 返回的是被赋值的变量的值. 例如
int x = 10;
int y = (x += 1);
其结果是 x = 11, y = 11
可以通过 int a = b = c = 10
协助记忆, 因为如果返回的不是10, 那么a和b就不会被赋值为10
if 的整数判断
用if(integer)判断时, 不管integer是正数还是负数, 只要不是0, 都会返回真, 例如对于 -1, 实际上int -1的值为0xFFFFFFFF, 对应无符号数就是正数.
在 C99 标准之后, 建议使用 <stdbool.h>
define
使用#
和##
将宏参数转字符串和连接宏字符串
使用#
把宏参数变为一个字符串,用##
把两个宏参数贴合在一起。
#include <stdio.h>
#define toString(str) #str // convert to string
#define conStr(a,b) (a##b) // concat
int main()
{
printf(toString(12345)); // print string "12345"
printf("\n%d", conStr(1,3)); // print int 13
}
当宏参数是另一个宏时, 宏参数不会再展开, 例如
#include <stdio.h>
#define toString(str) #str
#define conStr(a,b) (a##b)
#define AGE 18
int main()
{
printf("str is: %s", toString(AGE)); // print string "AGE", not "18"
printf("\n%s", conStr(AGE, AGE)); // error, undefined AGE
return 0;
}
由于AGE是宏, 且作为宏toString和conStr的参数, 并且宏conStr和toString中均含有#或者##符号, 所以AGE不能被解引用
常量赋值
无符号常数
使用U后缀, 例如1U
, 2U
, 在需要对bit进行操作时使用
num
{
IsDynamic = (1U << 0), // ...
IsSharable = (1U << 1), // ...
IsStrong = (1U << 2) // ...
};
就等价于
enum
{
IsDynamic = 1U, // binary: 00000000000000000000000000000001
IsSharable = 2U, // binary: 00000000000000000000000000000010
IsStrong = 4U // binary: 00000000000000000000000000000100
}
以及单片机中的寄存器操作
#define BITS_PER_BYTE 8
#define CLR(x) (compl(1U << (x % BITS_PER_BYTE)))
#define SET(x) (1U << (x % BITS_PER_BYTE))
/** brief bit operation for register */
#define CLRB(reg,x) (reg and_eq (compl(1U << (x % BITS_PER_BYTE))))
#define NOTB(reg,x) (reg xor_eq (1U << (x % BITS_PER_BYTE)))
#define SETB(reg,x) (reg or_eq (1U << (x % BITS_PER_BYTE)))
#define TESTB(val,x) (not(not(val bitand (1U << (x % BITS_PER_BYTE)))))
#define CONFB(reg,x,val) (reg = (reg bitand (compl(1U << (x % BITS_PER_BYTE)))) bitor (val << x))
char
不管是32位还是64位系统, char都是一个字节, 对于用 *char 表示的字符串, 如果将每个char用int表示, 其值范围是 -128 ~ 127. 可以试试下面代码打印的结果
char *c = "11月7日召开的“企业合并重组宣布会”上,北京市下属的北京与北京总集团时期0123abcABC12+_=/.,{}~";
while (*c != '\0') {
int i = *c;
char j = *c;
printf("%08x, %4d, %10u, %8c, %4d, %10hhu, %8c\n", c, i, i, i, j, j, j);
c++;
}
typedef
typedef: 类型别名
Typedef is a keyword that is used to give a new symbolic name for the existing name in a C program. This is same like defining alias for the commands.
例如
typedef long long int LLI;
printf("Storage size for long long int data type : %ld \n", sizeof(LLI));
对于下面这样一个struct
struct student
{
int mark [2];
char name [10];
}
如果用这个struct来声明变量, 有两种方式
// 方式一
struct student record; /* for normal variable */
struct student *record; /* for pointer variable */
// 方式二
typedef struct student status;
status record1; /* record 1 is structure variable */
对于第二种方式, 可以合并写成
typedef struct student
{
int mark [2];
char name [10];
} status;
函数指针类型别名
下面这样的定义, 就是将 fptr 定义为一个函数指针类型的别名
typedef void (*fptr)(void)
例如, 如果有三个函数
void hello(void) { printf("Hello"); }
void bye(void) { printf("Bye"); }
void ok(void) { printf("Okay"); }
定义函数指针类型
typdef void (*fptr)(void);
就构造了一个通用的函数调用方法, 使用时
fptr funcs[3] = {&hello, &bye, &ok};
void speak(int id)
{
fptr func = funcs[id];
(*func)();
}
speak(0); // will print "Hello"
对于参数和返回值都一样的函数, 都可以使用函数指针, 例如加, 减, 乘, 除, 可以用下面的 calc 类型定义
typedef int (*calc)(int,int);
struct
struct student
{
int mark;
char name[10];
float average;
};
// 声明变量及其取值方法
struct student report;
struct student report = {100, “Mani”, 99.5};
report.mark;
report.name;
report.average;
// 声明变量指针及取值方法
struct student *report, rep;
struct student rep = {100, “Mani”, 99.5};
report = &rep;
report -> mark;
report -> name;
report -> average;
使用struct时需要注意内存对齐方式造成的空间浪费.
Architecture of a computer processor is such a way that it can read 1 word (4 byte in 32 bit processor) from memory at a time.
To make use of this advantage of processor, data are always aligned as 4 bytes package which leads to insert empty addresses between other member’s address.
typedef struct s2
{
char c;
char cc;
double d;
} s22;
typedef struct s3
{
char c;
double d;
char cc;
} s33;
- sizeof(s22)是10, 但是系统按照sizeof(double)*2分配: 先分配8个字节给c, c占用1个字节, cc再占1个字节, 剩余6字节不够存储d, 系统就额外为d分配8字节, 整个分配浪费内存6字节;
- sizeof(s33)是10, 但是系统按照sizeof(double)*3分配: 先分配8个字节给c, c占用1个字节, 剩余7个字节不够存储d, 所以系统又分配了8个字节给d, 之后又分配8个自己给cc, 总共浪费了14个字节的空间. 所以在定义struct的时候按照s22的顺序分配可以节省内存.
结合无类型指针做通用的数据类型存储
对于不同类型的数据, 引用来源
/*模块A中有这样一个结构体需要非易失存储*/
typedef struct _t_paras{
int language;/*语言种类*/
char SN[20]; /*产品序列号*/
}T_PARAS;
T_PARAS sysParas;
/*模块B中有这样一个结构体需要非易失存储*/
typedef struct _t_pid{
float kp;
float ki;
float kd;
float T;
}T_PID;
T_PID pidParas;
可以定义这样一个struct来统一管理
typedef struct _t_nv_layout{
void * pElement; /*参数地址*/
int length; /*参数长度*/
}T_NV_LAYOUT;
/*参数映射表*/
T_NV_LAYOUT nvLayout[]={
{&sysParas,sizeof(T_PARAS)},/*参数映射记录*/
{&pidParas,sizeof(T_PID)},
...
};
/*参数映射表记录条数*/
#define NV_RECORD_NUMBER (sizeof(nvLayout)/sizeof(T_NV_LAYOUT))
void nv_load(T_NV_LAYOUT *pLayout,int nvAddr,int number);
void nv_store(T_NV_LAYOUT *pLayout,int nvAddr,int number);
union
联合union在许多其他语言中称作变体记录variant record, 在union中, 所有的成员都从偏移地址零开始存储, 这样每个成员的位置都会重叠在一起. 按照这种特性, union可以把同一个数据解释成多个不同的变量, 该用法的例子
// 可以提取整个32位int, 也可以提取单独的char如 value.byte.c0
union bits32_tag {
int whole; //一个32位的值
struct { char c0, c1, c2, c3;} byte; //四个八位的字节
} value;
union与struct的区别: 在存储多个成员信息时, 编译器会给struct每个成员分配存储空间, struct 可以存储多个成员信息, 而union每个成员用同一个存储空间, 存储成员的信息时, 会覆盖其他成员的内容.
volatile
volatile是一个类型修饰符(type specifier), 就像我们熟悉的const一样, 它被设计用来修饰被不同线程访问和修改的变量, volatile 的作用是作为指令关键字, 确保本条指令不会因编译器的优化而省略, 且要求每次直接读值. volatile 的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了. 简单地说就是防止编译器对代码进行优化。比如下面的代码
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile, 则编译器会逐一地进行编译并产生相应的机器代码(产生每一步的代码). 优化器在用到这个变量时必须每次都小心地重新读取这个变量的值, 而不是使用保存在寄存器里的备份. 下面是volatile变量的几个用途:
- 并行设备的硬件寄存器(如:状态寄存器)
- 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
- 多线程应用中被几个任务共享的变量
这是区分C程序员和嵌入式系统程序员的一点: 嵌入式系统程序员经常同硬件、中断、RTOS等等打交道, 所有这些都要求使用volatile变量, 不懂得volatile 将会带来麻烦. 对于下面的几个问题
- 一个参数既可以是const还可以是volatile吗? 为什么?
- 一个指针可以是volatile 吗? 为什么?
- 下面的函数被用来计算某个整数的平方, 它能实现预期设计目标吗? 如果不能, 存在什么问题?
int square(volatile int *ptr) {
return ((*ptr) * (*ptr));
}
下面是答案:
- 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
- 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。
- 不能, 这段代码的目的是用来返指针ptr指向值的平方,但是由于ptr指向一个volatile型参数,编译器将产生类似下面的代码
int square(volatile int* &ptr)//这里参数应该申明为引用,不然函数体里只会使用副本,外部没法更改
{
int a,b;
a = *ptr;
b = *ptr;
return a*b;
}
由于*ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的未必是期望的平方值. 正确的代码:
long square(volatile int*ptr) {
int a;
a = *ptr;
return a*a;
}
编译器优化常用的方法有:
- 将内存变量缓存到寄存器, 因为访问寄存器要比访问内存单元快的多;
- 调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令.
将内存变量缓存到寄存器可能会导致多线程程序读取脏数据, 而使用volatile声明变量值后, 系统会总是从变量所在内存地址读取数据, 遇到volatile变量, 编译器对访问该变量的代码就不再进行优化, 读后的操作不提前, 写前的操作不推后. 使用volatile变量的场景
- 中断服务程序中修改的供其它程序检测的变量需要加volatile
static int i=0;
int main(void)
{
...
while (1){
if (i) dosomething();
}
}
/* Interrupt service routine. */
void ISR_2(void) { i=1; }
程序的本意是希望ISR_2中断产生时, 在main当中调用dosomething函数, 但是由于编译器判断在main函数里面没有修改过i, 因此可能只执行一次对从i到某寄存器的读操作, 然后每次if判断都只使用这个寄存器里面的副本, 导致dosomething永远也不会被调用. 如果将变量加上volatile修饰, 则编译器保证对此变量的读写操作都不会被优化, 此例中i应该加上volatile修饰符
-
多任务环境下各任务间共享的标志应该加volatile
-
存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义
int *output = (unsigned int *)0xff800000;//定义一个IO端口;
int init(void)
{
int i;
for(i=0;i< 10;i++){
*output = i;
}
}
# 第一行应该改为
volatile int *output=(volatile unsigned int *)0xff800000;//定义一个I/O端口
Array
多维数组的赋值可以使用一维列表, 例如
// declaring and Initializing array
int arr[2][2] = {10,20,30,40};
/* Above array can be initialized as below also
arr[0][0] = 10; // Initializing array
arr[0][1] = 20;
arr[1][0] = 30;
arr[1][1] = 40; */
对于变量长度的数组, 声明时内部的值是不可预测的, 如果需要初始化为0, 可以使用memset快速赋值:
int p[length][length];
memset(p, 0, sizeof(p));
String
C语言的字符串就是char数组
//初始化方式
char string[20] = {'f', 'r', 'e', 's', 'h', '2', 'r', 'e', 'f', 'r', 'e', 's', 'h', '\0'};
char string[20] = "fresh2refresh"; //会分配20个字节的内存空间
char string[] = "fresh2refresh"; //内存空间会按实际大小分配
char *tmp = "test char point tmp"; // 字符串会分配到常量区
//打印string
printf("The string is : %s \n", string);
注意上面三个string与下面的tmp的变量类型是不同的, 三个string类型都是char数组, 对应的sizeof(string)都是数组的内存字节数, 分别为20, 20, 13, 而sizeof(tmp)是指针的字节数, 在64位系统中为8. 但是可以使用string给tmp赋值, 赋值后tmp的打印方式也和char数组一样
tmp = string;
printf("%s\n", tmp);
pointer
指针是一个整形, 在32位系统中占4字节, 在64位中占8字节. 指针一个关键的属性是类型, 即这个指针指向的是什么类型的数据, 指针变量加减运算的结果跟数据类型的字节长度有关.
// 指向char的指针的数组
char *msgTable[5] = {"Sum", "Difference", "Product", "Quotient", "Power"};
// 10个int类型指针的数组
int *arrPtr[10] = NULL;
// 指向10个元素的int数组的指针
int (* arrPtr)[10] = NULL;
int matrix[3][10]; // 3行10列的数组, 数组名称是一个指向第一个元素的指针, 也就是第一行的指针
arrPtr = matrix; // 使得arrPtr指向矩阵的第一行
(*arrPtr)[0] = 5; // 将5赋值给第一行的第一个元素
arrPtr[2][9] = 6; // 将6赋值给最后一行的最后一个元素
++arrPtr; // 将指针移动到下一行, 如果将地址打出来, 可以看到地址值增长了40, 正好是10个int的长度
(*arrPtr)[0] = 7; // 将7赋值给第二行的第一个元素
void* 表示为“无类型指针”,在ANSI C 中使用它来代替 char* 作为通用指针的类型, malloc() 和calloc() 函数返回的类型就是void 。由于 void没有特定的类型,因此它可以指向任何类型的数据。也就是说,任何类型的指针都可以直接赋值给void* ,而无需进行强制类型转换,但是将 void* 赋值给其他类型的指针,必须进行强制类型转换
#include<stdlib.h>
int main() {
int a = 7;
float b = 7.6;
void *p;
p = &a;
printf("Integer variable is = %d", *( (int*) p) );
p = &b;
printf("\nFloat variable is = %f", *( (float*) p) );
return 0;
}
另外还有指向函数的指针, 例如
# p为一个指向函数的指针, 这个函数返回值为int
int (*p)();
# 如果有一个函数int foo(),则可以令
p = foo;
对于指针变量声明的阅读, 可以通过"就近原则"来判断. 例如
int *p
- 这里 p 和 * 最近, 所以p首先是一个指针, 这个指针是int类型的int *p[5]
- 这里 p 和 [5] 最近, 所以p首先是一个数组, 数组的内容呢是指针, 这些指针是int类型的int (*p)[5]
- 这里 p 和 * 最接近, 所以p首先是一个指针, 这个指针是 int[5] 类型的int (*p)()
- 这里 p 和 * 最接近, 所以p首先是一个指针, 这个指针是指向 int () 类型的
对于指针传参的理解
指针传递, 对于变量A, 传递A的地址就是指针传递, 这里传递的是A的地址的值, 这个值的载体可以是一个A类型的指针变量, 假设为P, 这个变量P也有自己的地址, 这个地址在主函数和子函数里是不同的, 在子函数里只能操作其携带的地址所指向的值, 修改P的值是没用的, 因为在子函数里P只是一个局部变量. 可以用下面的代码来说明
void point_test(int *p) {
printf("Func: point addr:%X, value:%X, target:%d\n", &p, p, *p);
// Change the target value
*p = 128;
}
int main(void) {
int target = 100;
int *p = ⌖
printf("Main: point addr:%X, value:%X, target:%d\n", &p, p, *p);
point_test(p);
printf("Main: point addr:%X, value:%X, target:%d\n", &p, p, *p);
}
# 输出
Main: point addr:E5A2A680, value:E5A2A67C, target:100
Func: point addr:E5A2A658, value:E5A2A67C, target:100
Main: point addr:E5A2A680, value:E5A2A67C, target:128
什么时候需要传递"指向指针的指针变量"? 在子函数需要修改"外部指针的值"的时候(注意和"外部指针指向的值"区分), 这种方式经常用于在子函数里申请地址空间的时候, 例如
void point_test(char **p, int num) {
printf("Func: point addr:%X, value:%X, target:%X\n", &p, p, *p);
*p = (char *)malloc(sizeof(char) * num);
printf("Func: point addr:%X, value:%X, target:%X\n", &p, p, *p);
}
int main(void) {
char *p;
printf("Main: point addr:%X, value:%X, target:%X\n", &p, p, *p);
point_test(&p, 10);
printf("Main: point addr:%X, value:%X, target:%X\n", &p, p, *p);
}
# 输出
Main: point addr:F9B4CA0, value:F9B4D90, target:1
Func: point addr:F9B4C78, value:F9B4CA0, target:F9B4D90
Func: point addr:F9B4C78, value:F9B4CA0, target:9C8C8670
Main: point addr:F9B4CA0, value:9C8C8670, target:0
在子函数里新申请了内存空间, 将新内存空间的地址作为值, 写到了F9B4CA0这个地址上. 而F9B4CA0这个地址, 就是main函数里p的地址, 可以看到执行子函数之后, p变了.
内建函数
Type Casting Functions
atof() Converts string to float
atoi() Converts string to int
atol() Converts string to long
itoa() Converts int to string
ltoa() Converts long to string
Utils Functions
getenv() This function gets the current value of the environment variable
setenv() This function sets the value for environment variable
putenv() This function modifies the value for environment variable
perror() Displays most recent error that happened during library function call
rand() Returns random integer number range from 0 to at least 32767
delay() Suspends the execution of the program for particular time
Arithmetic Functions
内建的数学函数, 需要包含头文件 math.h 和 stdlib.h
abs() This function returns the absolute value of an integer. The absolute value of a number is always positive. Only integer values are supported in C.
floor() This function returns the nearest integer which is less than or equal to the argument passed to this function.
round() This function returns the nearest integer value of the float/double/long double argument passed to this function. If decimal value is from “.1 to .5”, it returns integer value less than the argument. If decimal value is from “.6 to .9”, it returns the integer value greater than the argument.
ceil() This function returns nearest integer value which is greater than or equal to the argument passed to this function.
sin() This function is used to calculate sine value.
cos() This function is used to calculate cosine.
cosh() This function is used to calculate hyperbolic cosine.
exp() This function is used to calculate the exponential “e” to the xth power. 自然数e的n次方
tan() This function is used to calculate tangent.
tanh() This function is used to calculate hyperbolic tangent.
sinh() This function is used to calculate hyperbolic sine.
log() This function is used to calculates natural logarithm. 自然对数
log10() This function is used to calculates base 10 logarithm. 以10为底的对数
sqrt() This function is used to find square root of the argument passed to this function.
pow(double base, double exponent) This is used to find the power of the given number. 返回base的exponent次方
trunc() This function truncates the decimal value from floating point value and returns integer value.
Char Validation Functions
内建的字符检查和处理函数, 需要包含头文件夹 ctype.h
isalpha() checks whether character is alphabetic
isdigit() checks whether character is digit
isalnum() Checks whether character is alphanumeric
isspace() Checks whether character is space
islower() Checks whether character is lower case
isupper() Checks whether character is upper case
isxdigit() Checks whether character is hexadecimal
iscntrl() Checks whether character is a control character
isprint() Checks whether character is a printable character
ispunct() Checks whether character is a punctuation
isgraph() Checks whether character is a graphical character
tolower() Checks whether character is alphabetic & converts to lower case
toupper() Checks whether character is alphabetic & converts to upper case
Time Related Functions
setdate() This function used to modify the system date
getdate() This function is used to get the CPU time
clock() This function is used to get current system time
time() This function is used to get current system time as structure
difftime() This function is used to get the difference between two given times
strftime() This function is used to modify the actual time format
mktime() This function interprets tm structure as calendar time
localtime() This function shares the tm structure that contains date and time informations
gmtime() This function shares the tm structure that contains date and time informations
ctime() This function is used to return string that contains date and time informations
asctime() Tm structure contents are interpreted by this function as calendar time. This time is converted into string.
Memory Allocation And Manipulation Functions
malloc()
malloc() is used to allocate space in memory during the execution of the program. It does not initialize the memory allocated during execution. It carries garbage value. It returns null pointer if it couldn’t able to allocate requested amount of memory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = malloc( 20 * sizeof(char) );
if( mem_allocation== NULL ) {
printf("Couldn't able to allocate requested memory\n");
} else {
strcpy( mem_allocation,"something");
}
printf("Dynamically allocated memory content: %s\n", mem_allocation);
free(mem_allocation);
}
calloc()
Like malloc() but calloc() initializes the allocated memory to zero.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = calloc( 20, sizeof(char) );
if( mem_allocation== NULL) {
printf("Couldn't able to allocate requested memory\n");
} else {
strcpy( mem_allocation,"fresh2refresh.com");
}
printf("Dynamically allocated memory content: %s\n", mem_allocation);
free(mem_allocation);
}
realloc()
realloc() modifies the memory size allocated by malloc() and calloc(). If no enough space in current memory block, new block will be allocated for the full size of reallocation then copies the existing data to new block and then frees the old block.
free()
free() frees the allocated memory by malloc(), calloc(), realloc().
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = malloc( 20 * sizeof(char) );
if( mem_allocation == NULL ) {
printf("Couldn't able to allocate requested memory\n");
} else {
strcpy( mem_allocation,"fresh2refresh.com");
}
printf("Dynamically allocated memory content: %s\n", mem_allocation);
mem_allocation=realloc(mem_allocation,100*sizeof(char));
if( mem_allocation == NULL ) {
printf("Couldn't able to allocate requested memory\n");
} else {
strcpy( mem_allocation,"space is extended upto 100 characters");
}
printf("Resized memory : %s\n", mem_allocation);
free(mem_allocation);
}
memset()
It is used to initialize a specified number of bytes to null or any other value in the buffer
memcpy(target, string, len)
It is used to copy a specified number of bytes from one memory to another
memmove(str1+2, str1, strlen(str1))
It is used to copy a specified number of bytes from one memory to another or to overlap on same memory. Difference between memmove and memcpy is, overlap can happen on memmove whereas memcpy should be done in non-destructive way
memcmp(str1, str2, 5*sizeof(char))
It is used to compare specified number of characters from two buffers
memicmp()
It is used to compare specified number of characters from two buffers regardless of the case of the characters
memchr(string, 'h', strlen(string))
It is used to locate the first occurrence of the character in the specified string
String Related Functions
string的操作方法通过string.h提供, 包含以下方法
strcat(str1, str2) 在str1后拼接str2
strncat(str1, str2, n) 在str1后拼接str2的前n个字符
strcpy(str1, str2) 将str2 复制到 str1, 如果str1长度不够, 超过部分将被丢弃
strncpy(str1, str2, n) 将str2的前n个字符复制到str1, 如果str1长度不够, 超过部分将被丢弃
strlen(str1) 返回str1的长度. 计算到\0的位置
strcmp(str1, str2) str1和str2相等返回0. str1长度小于str2返回负值, str1长度大于str2返回正值, 长度相等, 则逐字比较
strcmpi() 与strcmp()相似, 但是不区分大小写字符
strchr(const char *str, int character) str1中第一次出现character的位置, 返回的是char类型指针
strrchr(const char *str, int character) str1中从末尾开始第一次出现character的位置,
strstr(const char *str1, const char *str2) str1中第一次出现str2的位置, 返回的是char类型指针
strrstr(const char *str1, const char *str2) str1从末尾开始, 第一次出现str2的位置, 返回的是char类型指针. 非标准函数, 可能在标准C库中不存在
strdup(const char *string) 复制字符串, 返回char类型指针, 非标准函数
strlwr(char *string) 将字符串转为小写, 非标准函数
strupr(char *string) 将字符串转为大写, 非标准函数
strrev(char *string) 将字符串倒序, 非标准函数
strset(char *string, int c) 将字符串所有字符修改为输入的字符, 非标准函数
strnset(char *string, int c, int n) 将字符串前n个字符修改为输入的字符, 非标准函数
strtok(char * str, const char * delimiters) 用delimiters里的每个字符作为分隔符, 分隔str字符串. 操作直接在str内存地址中进行. 当strtok()在参数str字符串中发现参数delimiters中包含的字符时, 会将该字符改为\0, 在第一次调用时必须给予参数str字符串, 之后的调用则将参数s设置成NULL, 每次调用成功返回指向被分割出片段的指针.
File Related Functions
文件打开模式
r – 只读模式打开, 返回指针指向第一个字符, 如果文件不存在则返回null
w – 写模式打开, 文件内容将被覆盖, 如果文件无法打开则返回null
a – 追加模式打开, 如果文件无法打开则返回null
r+ – 读写模式打开, 返回指针指向第一个字符. 打开文件不删除内容, 如果文件不存在也不创建
w+ – 读写模式打开, 返回指针指向第一个字符. 打开文件时删除内容, 如果文件不存在则创建.
a+ – 读写模式打开, 返回指针指向第一个字符, 但是不能修改已经存在的内容.
文件处理方法
FILE *fopen (const char *filename, const char *mode) 创建新文件或打开存在的文件
int fclose(FILE *fp) 关闭打开的文件,
int getw(FILE *fp) 从文件读取一个整数
int putw(int number, FILE *fp) 向文件写入一个整数
int fgetc(FILE *fp) 从文件读取一个字符
int fputc(int char, FILE *fp) 向文件写入一个字符
char *gets (char *string) 读取键盘输入的字符串, 内容会被存入string
int puts(const char *string) 向输出屏幕写字符串
char *fgets(char *string, int n, FILE *fp) 从文件读取字符串, 每次一行
int fputs (const char *string, FILE *fp) 向文件写入字符串
int feof(FILE *fp) 用于判断fp是否已经处于文件结尾
int fgetchar(void) 读取键盘输入的一个字符
int fprintf(FILE *fp, const char *format, …) 将字符串格式化后写入文件
int fscanf(FILE *fp, const char *format, …) 从文件中读入格式化好的内容
fputchar() fputchar() function writes a character onto the output screen from keyboard input.
int fseek(FILE *fp, long int offset, int whence) 将文件指针移动到给定的位置
SEEK_SET 表示文件开始位置, 例如 fseek(fp, 21, SEEK_SET);
SEEK_CUR 表示文件指针当前位置, 例如 fseek(fp, -10, SEEK_CUR);
SEEK_END 将文件结尾位置, 例如 fseek(fp, -7, SEEK_END);
long int ftell(FILE *fp) 得到当前文件指针的位置
void rewind(FILE *fp) 将文件指针移回文件开始位置
int getc(FILE *fp) 读取一个字符
int getch(void) 等待并读取键盘输入的字符, 但是不会在屏幕上显示输入的字符
int getche(void) 等待并读取键盘输入的字符, 会在屏幕上显示输入的字符
int getchar(void) 从键盘输入读取一个字符
int putc(int char, FILE *fp) 显示一个字符到标准输出, 或者写入一个字符到文件, 例如 putc(char, stdout); putc(char, fp);
int putchar(int char) 朝标准输出或屏幕输出一个字符
printf() 输出格式化内容
int sprintf(char *string, const char *format, …) 将变量值输出成格式化字符串
scanf() 从键盘输入读取格式化内容
int sscanf(const char *string, const char *format, …) 从格式化字符串中读取变量值
int remove(const char *filename) 删除文件, 文件名必须包含全路径
int fflush(FILE *fp) 清空文件或buffer
例子
#include <stdio.h>
int main ()
{
FILE *fp;
char data[60];
fp = fopen ("test.c","w");
fputs("Fresh2refresh.com is a programming tutorial website", fp);
fgets(data, 60, fp);
printf("Before fseek - %s", data);
// To set file pointet to 21th byte/character in the file
fseek(fp, 21, SEEK_SET);
fflush(data);
fgets(data, 60, fp);
printf("After SEEK_SET to 21 - %s", data);
// To find backward 10 bytes from current position
fseek(fp, -10, SEEK_CUR);
fflush(data);
fgets(data, 60, fp);
printf("After SEEK_CUR to -10 - %s", data);
// To find 7th byte before the end of file
fseek(fp, -7, SEEK_END);
fflush(data);
fgets(data, 60, fp);
printf("After SEEK_END to -7 - %s", data);
// To set file pointer to the beginning of the file
fseek(fp, 0, SEEK_SET); // We can use rewind(fp); also
fclose(fp);
return 0;
}