最近因为工作需要开始重新学c语言,越学越发现c语言深不可测,当初用python轻轻松松处理的一些数据,但是c语言写起来却异常的复杂,这个板块就记录一下我的c语言复习之路
strlen
1、原型:size_t strlen(char const* string);
2、功能:返回字符串 string 的长度(不包含字符串终止符NUL)
3、注意:size_t是一个无符号整数类型
举例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* y = "abcdef";
char* x = "abcd";
if (strlen(x) >= strlen(y)) {
printf("1: strlen(x) >= strlen(y)\n");
} else {
printf("1: strlen(x) < strlen(y)\n");
}
/* 由于strlen(x)返回的是一个size_t,所以strlen(x) - strlen(y) >= 0恒成立,
* 导致出现错误的结论
*/
if (strlen(x) - strlen(y) >= 0) {
printf("2: strlen(x) - strlen(y) >= 0\n");
} else {
printf("2: strlen(x) - strlen(y) < 0\n");
}
// 将size_t转换为int类型后,可以返回正确的值
if ((int)(strlen(x)) - (int)(strlen(y)) >= 0) {
printf("3: (int)strlen(x) - strlen(y) >= 0\n");
} else {
printf("3: (int)strlen(x) - strlen(y) < 0\n");
}
return 0;
}
值得注意的是size_t是一个无符号整数类型,因此
strlen(x) - strlen(y) >= 0恒成立
因此用strlen做长度对比的时候直接使用strlen(x) >= strlen(y)
这个式子就可以了
手动实现
unsigned int my_strlen(char* str)
{
int count = 0;
while (*str++ != '\0')
{
count++;
}
return count;
}
strcpy
- 原型:
char *strcpy(char *dst, char const *src);
- 功能:将参数src字符串复制到dst参数中。如果参数src和dst在内存中出现重叠,其结果是未定义的。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针,不能使用字符串常量。返回参数dst的一份拷贝。
- 注意:
目标参数dst的以前内容将被覆盖并丢失。即使新的字符串比dst原先的内存更短,由于新字符串是以NUL字符结尾,所以老字符串最后剩余的几个字符也会被有效的删除。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。所以必须保证目标字符数组的空间足以容纳需要复制的字符串。
举例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char msg[] = "Original message";
printf("before strcpy: msg:%s\n", msg);
strcpy(msg, "Different");
printf("after strcpy: msg:%s\n", msg);
return 0;
}
手动实现
char* my_strcpy(char* str1, char* str2)
{
char* target1 = str1;
char* target2 = str2;
while((*target1++ = *target2++));
return str1;
}
strncpy
- 原型:
char *strncpy(char *dst, char const *src, size_t len);
- 功能:和strcpy一样,strncpy把源字符串的字符复制到目标数组。然而,它总是 正好向dst写入len个字符。如果strlen(src)的值小于len, dst数组就用额外的NUL字节填充到len长度。如果strlen(src)的值大于或者等于len,那么只有len个字符被复制到dst中。
- 注意:strncpy调用的结果可能不是一个字符串,它的结果将不会以NUL字符结尾, 因此字符串必须以NUL字符结尾。
举例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_CPY_LEN 5
int main()
{
char msg[] = "Original message";
printf("before strncpy: msg:%s\n", msg);
strncpy(msg, "Different", STR_CPY_LEN);
printf("after strncpy: msg:%s\n",msg);
return 0;
}
手动实现
char* my_strncpy(char* str1, const char* str2, int n)
{
char* target1 = str1;
char* target2 = str2;
while(n--)
{
if (*target1 == '\0') break;
*target1++ = *target2++;
}
*target1 = '\0';
return str1;
}
strcat
- 原型:
char *strcat(char *dst, char const *src);
- 功能:将一个字符串添加(连接)到另一个字符串的后面。
- 注意:src和dst的所指的内存区域不能重叠,如果发生重叠,其结果是未定义的,其中dst一定要分配出足够的内存空间,否则会导致溢出错误,
strcat 函数原理:dst 内存空间大小 = 目标字符串长度 + 原始字符串场地 + ‘\0’
,可以用char a[100]; char* a = (char*)malloc(100)这两种方式先分配出内存空间
使用举例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char msg[20] = "hello";
printf("before strcat: msg:%s\n", msg);
strcat(msg, ", world.");
printf("after strcat: msg:%s\n", msg);
return 0;
}
手动实现
char* my_strcat(char* str1, const char* str2)
{
char *ret = str1;
while(*++str1 != '\0');
while((*str1++ = *str2++));
return ret;
}
这里测试的时候
str1
的存储空间一定要是str2
存储空间的两倍以上
strcmp
- 原型:
int strcmp(char const *s1, char const *s2);
- 功能:比较两个字符串。如果s1小于s2,strcmp函数返回一个小于零的值。如果s1大于s2,函数返回一个大于零的值。如果两个字符串相等,函数就返回零。
- 注意:由于strcmp并不修改它的任何一个参数,所以不存在溢出字符数组的危险。但是,和其他不受限制的字符串函数(strcpy, strcat)一样,strcmp函数的字符串参数也必须以一个NUL字符结尾。如果并非如此,strcmp就可能对参数后面的字符进行比较,这个比较结果将不会有什么意义。
举例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s1 = "hello";
char *s2 = "hello, world";
int ans = strcmp(s1, s2);
if (ans > 0) {
printf("s1 > s2\n");
} else if (ans < 0) {
printf("s1 < s2\n");
} else {
printf("s1 = s2\n");
}
return 0;
}
itoa
- 原型:
char *itoa(int value, char *str, int base);
- value: 待转换的整型数值
- str:用于存放转换结果的字符串
- base:指定转换结果用多少进制数来表示,取值范围是 2~36(2 表示二进制,10 表示十进制……)
- 功能:itoa 函数将整型值转换为指定进制表示的标准字符串
- 注意:如果是十进制数,并且数值为负,那么转换后的字符串前边有一个负号(‘-’);如果是其他进制数,其值始终被认为是无符号类型。用于存放的字符串必须拥有足够的空间,以便可以容纳任何可能的数值:对于 2 进制数,需要使用
(sizeof(int)*8+1)
个字节来存放。比如在 16 位平台上,需要 17 个字节来存放;在 32 位平台上,则需要 33 个字节来存放。 - 返回值:返回值是一个指向转换结果的指针,同 str 参数。
例子:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer[33];
printf("Enter a number: ");
scanf("%d", &i);
itoa(i, buffer, 10);
printf("decimal: %s\n", buffer);
itoa(i, buffer,16);
printf("hexadecimal: %s\n", buffer);
itoa(i, buffer, 2);
printf("binary: %s\n", buffer);
return 0;
}
自我实现
char *myitoa(int num, char *str)
{
int dec = 1;
int i = 0;
int temp;
if (num < 0)
{
str[i++] = '-';
num = -num;
}
temp = num;
while (temp > 9)
{
dec *= 10;
temp /= 10;
}
while (dec != 0)
{
str[i++] = num / dec + '0';
num = num % dec;
dec /= 10;
}
str[i] = '\0';
return str;
}
恕我直言,python直接一个int函数梭哈,c语言真是花里胡哨
sprintf()
- 原型:
int sprintf(char *str, const char *format, ...)
- str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。
- format – 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化
- 功能:发送格式化输出到 str 所指向的字符串。
- 返回值:如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
- 注意:需要有足够的存储内存缓冲区,不然会报错
举例:
- 将整数转化为字符串
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* strs = (char*)malloc(30);
sprintf(strs, "python %s java %d", "cpp", 666);
puts(strs);
free(strs);
return 0;
}
其实说白了就是一个字符拼接函数类似于python的
"xxx{}".format(xx)
和f"xxx{xx}"
- 字符串拼接
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* strs = (char*)malloc(30);
sprintf(strs, "python %s java %s", "cpp", "rust");
puts(strs);
free(strs);
return 0;
}
sprintf还有其他比较细致的用法,详情可以参考https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm