文章目录
1、如何给结构体中的字符数组赋值
在了解给结构体字符数组赋值之前,先了解一下字符数组这个东西
例如:
(1)定义并对字符数组初始化
定义一个字符数组,不赋值初始化:
char a[10];
定义一个字符数组,并初始化:
char a[10] = "hello";
定义一个字符数组,对每个元素逐个赋值:
char a[10] = {'h', 'e', 'l', 'l', 'o'};
上面三种方法都是正确的,但是我们很多时候会像下面这样,先定义再赋值,但是这是错误的,编译系统也会报错,例如:
错误1:
char a[10];
a[10] = "hello";
编译提示:
原因:a[10] = “hello”;表达式中,欲将"hello"字符串的首地址赋值给a[10],而字符数组a每个元素存储的是字符,就是ASII码对应的数值,也就是整数,这就是为什么提示,将一个指针赋值给一个整数没有强制转换。而且a[10]只是数组a的一个元素,一个字符怎么能容纳一个字符串?明显不对。
错误2:
char a[10];
a = "hello";
原因:这种情况也是很离谱的,而且不容易发现。在执行第一条语句,char a[10];表达式的时候,系统开辟的一段内存给了字符数组a[10], 所以一开始a代表的是字符数组a[10]内存空间的首地址,即a指向字符数组a[10]的首地址;执行第二条表达式a = “hello”;后,a不再指向字符数组a[10]内存空间的首地址,而是字符串常量"hello"的首地址,这时指针a出现指向混乱,不允许!
但是如果一开始定义了一个字符数组,并没有初始化,后面用到的时候再赋值,那应该怎么办呢?
可以利用strcpy()和strncpy()函数:
char a[10];
strcpy(a,"hello");
(2)如何对结构体的字符数组赋值
其实就是用上面的strcpy()和strncpy()函数
C 库函数 strcpy()
char *strcpy(char *dest, const char *src)
把 src 所指向的字符串复制到 dest。需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况.
C 库函数strncpy()
char *strncpy(char *dest, const char *src, size_t n)
把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
实例:
#include <stdio.h>
#include <string.h>
typedef struct student_s{
char name[64];
int grade;
}student_t;
int main()
{
student_t student;
memset(&student, 0, sizeof(student));
//strcpy(student.name, "zcx");
strncpy(student.name, "zcx", strlen("zcx"));
student.grade = 99;
printf("name:%s, grade:%d, strlen(\"zcx\"):%ld\n", student.name, student.grade, strlen("zcx"));
return 0;
}
2、strlen和sizeof求字符串长度的区别
1.sizeof会将空字符\0计算在内,而strlen不会将空字符\0计算在内。
2.sizeof是操作符(关键字),它结果类型是size_t,它在头文件中typedef为unsigned_int类型。 strlen是函数。
3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’‘\0’'结尾的。
4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
sizeof()的功能是计算一个数据类型的大小,这个类型可以是数组、函数、指针、对象等,单位为字节,它的返回值是size_t类型,也就是unsigned int类型,是一个无符号整数。注意:sizeof不是一个函数,它是一个运算符,所以它不需要包含任何头文件。
strlen()的功能是计算一个指定字符串的长度,函数原型如下:
size_t strlen(const char *s)
它的返回值是size_t类型,也就是unsigned int类型,返回的是字符串的长度,需要包含头文件#inlude <string.h>,参数s是字符串首地址。
size_t:size_t 是为了方便系统之间的移植而定义的,在32位系统上定义为 unsigned int,在64位系统上定义为 unsigned long int。
3、字符串转换为int或float
atoi 是把字符串转换成int型的函数,其函数参数是一个字符串,如果字符串的的开始字符为空格则跳过再做转换,如果第一个非空格字符存在,是数字或者正负号则开始做类型转换,之后检测到非数字(包括结束符 \0和.) 字符时停止转换,返回整型数。否则,返回零。
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int i1, i2;
float f1, f2;
char* str1 = "25.5";//注意:atoi和atof遇到.就停止往后转换了
char* str2 = "25.5a";
i1 = atoi(str1);
i2 = atoi(str2);
f1 = atoi(str1);
f2 = atoi(str2);
printf("str1=%s,str2= %s\n",str1, str2);
printf("i1=%d, i2=%d\n", i1, i2);
printf("f1=%f, f2=%f\n", f1, f2);
return 0;
}
运行结果:
tr1=25.5,str2= 25.5a
i1=25, i2=25
f1=25.000000, f2=25.000000
我们将代码改一下,在字符串面前加上空格和正负号,再运行:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int i1, i2;
float f1, f2;
char* str1 = " 25.5";
char* str2 = "-25.5a";
i1 = atoi(str1);
i2 = atoi(str2);
f1 = atoi(str1);
f2 = atoi(str2);
printf("str1=%s,str2= %s\n",str1, str2);
printf("i1=%d, i2=%d\n", i1, i2);
printf("f1=%f, f2=%f\n", f1, f2);
return 0;
}
运行结果:
str1= 25.5,str2= -25.5a
i1=25, i2=-25
f1=25.000000, f2=-25.000000
4、stat()函数
头文件:
#include <sys/stat.h>
#include <unistd.h>
函数原型:
int stat(const char *file_name, struct stat *buf)
参数:通过文件名filename获取文件信息,并保存在buf所指的结构体;
stat函数中的struct stat结构体成员:
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //指最近修改文件内容的时间
time_t st_ctime; //指最近改动Inoed的时间
};
5、chdir()
头文件:#include <unistd.h>
函数原型:
int chdir(const char * path);
函数说明:chdir()用户将当前的工作目录改变成以参数路径所指的目录。
返回值执行成功则返回0,失败返回-1,errno为错误代码。
6、dirname()
dirname() 函数返回路径中的目录名称部分。
函数原型:
char *dirname(path);
basename作用是得到特定的路径中的最后一个’/',后面的内容
如/usr/bin,得到的内容就是bin
如果/sdcard/miui_recovery/backup
得到的内容就是backup
如果是/sdcard/update.zip
得到的内容就是update.zip
7、snprintf()
其返回值为欲写入第一个参数的字符串长度
需要注意的是:使用snprintf将一个字符串写入一个字符数组后,如果又想重新写入另外一个字符串,我们不用memset来清空字符数组,因为在每写入一个字符串的时候,snprintf会自动在后面加一个"\0",作为字符串的结束标志,所以我们读出来的时候,也就是读到我们最新写入的字符串而已,不存在字符串连接在一起的情况。
测试实例:
//test.c
#include <stdio.h>
int main()
{
char buffer[50];
char* s1 = "runoobcom";
// 读取字符串并存储在 buffer 中
int j1 = snprintf(buffer, 50, "%s\n", s1);
// 输出 buffer及字符数
printf("string:%s\ncharacter count = %d\n", buffer, j1);
char* s2 = "hello";
// 读取字符串并存储在 buffer 中
int j2 = snprintf(buffer, 50, "%s\n", s2);
// 输出 buffer及字符数
printf("string:%s\ncharacter count = %d\n", buffer, j2);
return 0;
}
运行结果:
8、/dev/null设备文件
/dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”
9、getdtablesize()
#include <unistd.h>
int getdtablesize(void);
描述getdtablesize() 返回文件的最大数量进程可以打开的,比一个文件描述符的最大可能值多一个。
返回值当前限制在每个进程打开的文件数。
10、getpid/getppid系统调用
功能描述:
getpid返回当前进程标识,getppid返回父进程标识。
头文件:
#include <sys/types.h>
#include <unistd.h>
用法:
pid_t getpid(void);
pid_t getppid(void);
fork()函数用来创建进程
11、unlink函数
功能:删除⼀个名字(某些情况下删除这个名字所指向的⽂件)
头⽂件:#include<unistd.h>
函数原型:
int unlink(const char* pathname);
功能详解:unlink从⽂件系统中中删除⼀个名字,若这个名字是指向这个⽂件的最后⼀个链接,并且没有进程处于打开这个⽂件的状态,则
删除这个⽂件,释放这个⽂件占⽤的空间。
如果这个名字是指向这个⽂件的最后⼀个链接,但有某个进程处于打开这个⽂件的状态,则暂时不删除这个⽂件,要等到打开这个⽂
件的进程关闭这个⽂件的⽂件描述符后才删除这个⽂件。
如果这个名字指向⼀个符号链接,则删除这个符号链接。
如果这个名字指向⼀个socket、fifo或者⼀个设备,则这个socket、fifo、设备的名字被删除,当时打开这些socke、fifo、设备的进程仍
然可以使⽤它们。
返回值:调⽤成功返回0,不成功返回-1;
12、SIGSEGV信号
SIGSEGV信号是当一个进程执行了一个无效的内存引用,或发生段错误时发送给它的信号。
13、setsid()
当进程是会话的领头进程时setsid()调用失败并返回(-1)。setsid()调用成功后,返回新的会话的ID,调用setsid函数的进程成为新的会话的领头进程,并与其父进程的会话组和进程组脱离。由于会话对控制终端的独占性,进程同时与控制终端脱离。setsid后子进程不受终端影响,终端退出,不影响子进程。
参考链接:https://blog.csdn.net/sweetfather/article/details/79457261
14、认识了解uint8_t / uint16_t / uint32_t /uint64_t
https://blog.csdn.net/liweigao01/article/details/84032933
15、%取余注意事项
在对float类型变量进行%取余时,编译出现以下错误:
invalid operands to binary % (have ‘double’ and ‘int’)
原因:double类型不能使用%操作符作取余运算。浮点数没有%运算符,%只能运用于整数。
下面代码,演示了如何使用一个u_int16_t变量的前8位和后8位:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str = "12256";
u_int8_t *byte = NULL;
u_int16_t temper = 0;
byte = (u_int8_t*)&temper;
byte[0] = atoi(str)/1000;
byte[1] = (atoi(str)%1000)/10;/*因为一个u_int8_t的类型只能存0~255的数,所以只能取两位数以内进行使用*/
printf("atoi(str):%d, integer:%d, decimal:%d\n", atoi(str), byte[0], byte[1]);
}
16、C文件开头格式
我们在看别人写的规范代码一般开头都有一个固定的程序开头,下面我们看一下STM32给我们安排的顺序,就可以大概知道到底是typedef、全局变量、函数声明、头文件的排放顺序了。
17、Linux系统中日志文件主要存放目录
日志文件的默认路径是:
/var/log:这个是登录文件放置日志的的目录。/var/log下面是几个重要的日志文件的路径及其包含的信息: /var/log/syslog:它和/etc/log/messages日志文件不同,它只记录警告信息,常常是系统出问题的信息。 /var/log/messages:包括整体系统信息。
大部分Linux发行版默认的日志守护进程为 syslog,位于 /etc/syslog 或 /etc/syslogd,默认配置文件为 /etc/syslog.conf,任何希望生成日志的程序都可以向 syslog 发送信息。
18、%d和%i的区别
C语言中 %d 与 %i 的区别 和注意事项
在 printf 格式串中使用时,没有区别
在 scanf 格式串中使用时,有点区别,如下:
在scanf格式中,%d 只与十进制形式的整数相匹配。
而%i 则可以匹配八进制、十进制、十六进制表示的整数。·
例如: 如果输入的数字有前缀 0(018、025),%i将会把它当作八进制数来处理,如果有前缀0x (0x54),它将以十六进制来处理。
19、>> 和 >>=的区别
m >> 1; // 是指把 m这个数右移一位,得到结果,当时不改变 m本身。
m >>= 1; // 是指把 m这个数右移一位,得到结果,并把结果赋值给 m 因此 m 的值被改变