C语言字符串函数,字符函数,内存操作函数

简介: C语言字符串函数,字符函数,内存操作函数

提示: 本篇文章涉及到以下内容:

求字符串长度

strlen

长度不受限制的字符串函数(被VS认为不安全,就像scanf)–>非法也要完成任务

strcpy 拷贝(将原字符串内容和\0全拷贝过去)

strcat 追加(先找到目标空间中的\0,然后把原字符串中的内容直到\0全拷贝过去,原字符串中的\0也会被追加过去)

strcmp 字符串内容比较

长度受限制的字符串函数介绍

strncpy 拷贝(字符不够,0来凑)

strncat 追加(追加不够,不追了)

strncmp 字符串比较(可控制比较字符的个数)

字符串查找

strstr

strtok

错误信息报告

strerror

字符分类函数

iscntrl

isspace

isdigit

isxdigit

islower

isupper

isalpha

isalnum

ispunct

isgraph

isprint

字符转换函数

tolower

toupper

内存操作函数

memcpy

memmove

memset

memcmp


文章目录

1.strlen 求字符串的长度

头文件 #include<string.h>

注意要点:

(1)字符串已经以\0作为结束标志,strlen函数返回的是在字符串中\0前面出现的字符个数(不包含\0)

char arr[]="abc\0def";
int len=strlen(arr);
printf("%d\n",len);  //3

(2)函数指向的字符串必须要以\0结束

char arr[3] = { 'a','b','c' };
  int len = strlen(arr);
  printf("%d\n", len);   //随机值

(3)注意函数的返回值为size_t,实物符号的(易错)

const char* str1 = "abcdef";
  const char* str2 = "bcd";
  if (strlen(str2) - strlen(str1) > 0) {
    printf("str2>str1\n");
  }
  else {
    printf("str2<str1\n");
  }
  return 0;

运行结果

明明看着str2的长度比str1的长度短,为什么这里是str2>str1呢?

因为strlen函数的返回类型是size_t(无符号整型)

按说是3-6=-3,但是在内存中把-3这个结果当做无符号整型,也就是默认它为正数,正数的原码也就是它的补码,所以直接把它的补码当做原码打印出来(正数的原码反码补码全都一样,如果是负数要先转换成原码打印出来),所以结果一定是个>0的数字

三种方法模拟实现strlen函数

(1)计数器

//1.计数器
#include<assert.h>
#include<stdio.h>
#include<string.h>
//这里将my_strlen自定义函数的返回类型定义为int,当遇到strlen("abdcf")-strlen("shfudgfu")这种情况计算结果时不容易出错
int my_strlen(const char* str) {  //求长度时只需要遍历字符串,不需要修改它,所以用const来保护指针所指向的内容
  int count = 0;
  assert(str);  //担心str是空指针,用assert()来断言一下str是不是空指针,保证指针的有效性
  while (*str != '\0') {
    count++;
    str++;
  }
  return count;
}
int main() {
  char arr[] = "bit";
  int len = my_strlen(arr);
  printf("%d\n", len);
  return 0;
}

(2)递归

int my_strlen(const char* str) {
  if (*str != '\0')
  {
    return 1 + my_strlen(str+1);
  }
  else {
    return 0;
  }
}
int main() {
  char arr[] = "bit";
  int len = my_strlen(arr);
  printf("%d\n", len);
  return 0;
}

(3)指针-指针

int my_strlen(char* s) {
  char* p = s;
  while (*p != '\0') {
    p++;
  }
  return p - s;
}
int main() {
  char arr[] = "bit";
  int len = my_strlen(arr);
  printf("%d\n", len);
  return 0;
}

2.strcpy 字符串拷贝

头文件#include<string.h>

注意要点

(1)源字符串必须以\0结束

比如char arr1[ ]=“abc\0def”;

将arr1拷贝到一个数组里面的时候,拷贝的是abc

(2)会将源字符串中的\0拷贝到目标空间

比如char arr2[3]={‘a’,‘b’,‘c’}; 无法正确拷贝

(3)目标空间必须足够大,以确保能存放源字符串(不够大时事实上也可以拷贝,运行之后程序会崩溃,非法也要完成任务)

(4)目标空间必须可变

(注意数组可以被改变,变量也可以被改变)

不能写成

char arr3[20]=arr1;//error

也不能写成

arr4=arr5;//error

注意是把数组的内容放到地址所指向的空间里面去,而不是放地址

正确示范

#include<stdio.h>
#include<string.h>
int main() {
  char arr1[] = "abcdef";
  char arr2[20] = {0};
  strcpy(arr2, arr1);
  printf("%s\n", arr2);
  return 0;
}

错误示范—>目标空间必须是可以修改的

int main() {
  char* p = "abcdefghi";  //p指向的是常量字符串,不能被修改
  char arr2[20] = "hehe";
  strcpy(p, arr2);
  printf("%s\n", p);
  return 0;
}

strcpy的模拟实现

模拟实现的功能:

(1)希望源头拷贝到目的地,目的地发生变化,感知它的变化,应返回目标空间的起始地址

(2)目的地里面数据发生变化,源头里数据不发生变化,所以用const保护起来

#include<assert.h>
char* my_strcpy(char* dest, const char* src) {
  char* ret = dest;         //在最开始的时候把目的地址保存起来
  assert(dest && src);  //断言保证这两个指针的有效性
  while (*dest++ == *src++) {       // \0的ASCII值是0,就不执行*dest=*src这条指令了
    ;
  }
  return ret;
}
int main() {
  char arr1[] ="hehe";
  char arr2[20] = {0}; 
  my_strcpy(arr2,arr1);
  printf("%s\n", arr2); //printf("%s\n", my_strcpy(arr2,arr1););
  return 0;
}

3.strcat 字符串追加

追加的时候是在目的地\0处,把\0覆盖,源头中的\0也会被追加过去–>所以目标空间内必须有\0(知道从哪里开始追加

注意要点

(1)源字符串必须以\0结束

(2)目标空间必须足够大,能容纳下源字符串的内容

(3)目标空间必须可修改

(4)字符串自己给自己追加,用strcat不适合

简单的应用

int main()
{
  char arr1[20] = "hello";
  char arr2[] = "world";
  strcat(arr1, arr2);
  printf("%s\n", arr1);
  return 0;
}

模拟实现strcat

my_strcat 实现思路:

先找到目的空间的第一个\0,然后拷贝字符串

#include<assert.h>
char* my_strcat(char* dest, const char* src) {
  assert(dest && src);        //assert断言保证两个指针的有效性
  char* ret = dest;     //最开始把目的地址保存起来
  while (*dest != '\0') {
    dest++;
  }
  while (*dest++ = *src++) {  //拷贝
    ;
  }
  return ret;
}

主函数:(一个字符串在另一个字符串后面追加,追加成功)

int main() {
  char arr1[20] = "hello";
  char arr2[] = "world";
  my_strcat(arr1, arr2);
  printf("%s\n", arr1);
  return 0;
}

主函数:(自己给自己追加,追加失败)

int main() {
  char arr1[20] = "bit";
  my_strcat(arr1, arr1);
  printf("%s\n", arr1);
  return 0;
}  //error

在自己给自己追加的时候用strcat是有问题的,因为在追加的时候原字符串中的\0被覆盖,指针在原字符串中找不到\0,会一直陷入死循环追加,停不下来

4.strcmp 字符串内容比较

注意比较两个字符串的内容时不能用==,应使用strcmp

if(“abcdef”==“bcdefg”) //这里比较的是两个字符串首字符的地址,并不是字符串的内容

标准规定

第一个字符串大于第二个字符串,则返回大于0的数字

第一个字符串等于第二个字符串,则返回0

第一个字符串小于第二个字符串,则返回小于0的数字

所以strcmp函数返回的结果要用有符号整型int来接收

如何判断两个字符串?

比的是对应位置上的ASCII值大小如果发现有一个不相等的,就可以比较出来了

a < b (a的ASCII值小于b的ASCII值)

模拟实现strcmp

#include<assert.h>
int my_strcmp(const char* str1, const char* str2) {
  assert(str1&&str2); //保证两个指针非空
  while (*str1 == *str2) {    //2个字符串相等的情况在while循环里面
    if (*str1 == '\0') {
      return 0;
    }
    str1++;
    str2++;
  }
  if (*str1 > *str2)
    return 1;
  else
    return -1;
  //上面的if...else...太啰嗦,可以改为return *str1-*str2;
}
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "acdf";
  int ret = my_strcmp(arr1, arr2);
  printf("%d\n", ret);
  return 0;
}

注意:

不要固定思维,函数返回的是大于0,小于0,0的数字,strcmp并不是只返回1,-1,0

5.strncpy 字符串拷贝( 控制拷贝个数)

(字符不够,0来凑)

注意要点

(1)拷贝num个字符从原字符串到目标空间

(2)如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加0.直到num个

简单应用

int main() {
  char arr1[] = "abcdef";
  char arr2[20] = "xxxx";
  strncpy(arr2, arr1, 3);
  printf("%s\n", arr2);
  return 0;
}

6.strncat 追加(控制追加几个字符)

追加不够个数,就不追加了

可以自己给自己追加

简单应用

int main() {
  char arr1[20] = "hello";
  char arr2[] = "abcdef";
  strncat(arr1, arr2, 3);//将arr2中的3个字符追加到arr1后面
  printf("%s\n", arr1);
  return 0;
}

int main() {
  char arr1[20] = "hello \0xxxxxxxx";
  char arr2[] = "abcdef";
  strncat(arr1, arr2, 8); 
  printf("%s\n", arr1);
  return 0;
}

追加不够个数就不追加了

7. strncmp 字符串比较(控制比较的字符个数)

如果num大于要比较的2个字符串的长度,实际上根本不用比到num个就比出大小了

注意要点

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完

strcat_s函数

定义

strcat_s(char* destination,size_t num,const char* source)

8.strstr 在一个字符串中找另一个字符串第一次出现的位置

在str1字符串中找str2字符串出现的位置

如果在str1中没有找到str,那么返回的就是空指针

简单应用

int main(){
  char arr1[] = "abcdef";
  char arr2[] = "bcd";
  char* p = strstr(arr1, arr2);
  if (p == NULL) {
    printf("找不到\n");
  }
  else {
    printf("%s\n", p);
  }
  return 0;
}

模拟实现strstr

char* my_strstr(const char* str1, const char* str2) { //在查找的过程中不会修改str1,str2字符串,用const保护起来
  char* s1 = NULL;//用来维护遍历第一个字符串
  char* s2 = NULL;//用来维护遍历第二个字符串
  char* cp = (char*)str1;  //cp用来记录每次开始匹配的位置
              //str1是const修饰的指针`,是一个相对安全的指针.cp是char*类型,将相对安全的指针交给不安全的指针,权限被放大,编译器报警告,因此这里需要将str1进行强制类型转换一下
  while (*cp) {   //*cp指向被遍历的串,当*cp不是\0说明这个串还没完
    s1 = cp;    //将开始匹配的位置交给s1,让s1从这里开始遍历
    s2 = (char*)str2; //将arr2的起始地址交给s2;str2这里也需要进行强制类型转换
    while (*s1 && *s2 && *s1 == *s2) {//当*s1指向\0会停下来,*s2指向\0也会停下来
                     //s1,s2指向的内容相等那么遍历指针同时++
      s1++;
      s2++;
    }
    if (*s2 == '\0') {    //当*s2指向\0说明子串匹配完
      return cp;      //返回最开始匹配的位置
    }
    cp++; //s1内容和s2内容不相等,说明当前位置匹配是失败的,cp++,从下一个位置再开始匹配
  }
  //上面的循环结束说明第一个字符串里面的字符全都匹配了一遍也没有找到第二个字符串,那么此时结果就是找不到
  return NULL;    //如果在循环中始终没有找到子串,没有返回cp,return空指针说明找不到
}
int main() {
  char arr1[] = "abcdef";
  char arr2[] = "bcd";
  char* p = my_strstr(arr1, arr2);
  if (p == NULL) {
    printf("找不到\n");
  }
  else {
    printf("%s\n", p);
  }
  return 0;
}

思路分析:

(1)

1次匹配成功的情况:

首先看str2指向的内容和str1指向的内容是否相等,发现不相等,被查找的字符串str1中的指针++,继续查找,相等的情况下,两个指针同时往后走

(2)

多次匹配成功的情况:

在这种情况下,当第一个b匹配相等时,指针各自往后走.此时不相等,但是不意味着在后面就找不到arr2,而是说明从arr1中当前指针所在位置找不到arr2,但并不代表他的后面没有.所以应该从arr1当前指针所在位置的下一个位置处开始再匹配.arr1中的指针应回到刚才开始匹配的位置,arr2中的指针应回到arr2字符串的起始位置.

注意点(要记住的位置)

(1)arr1:要记住上一次是从哪里开始匹配的,如果匹配不相等,应从上一次开始匹配的位置的下一个位置开始匹配 -->设置cp指针记住这个位置

(2)arr2:当指针不断往后走应该记住这个字符串的起始位置,一旦匹配失败了,让它直接返回起始位置重新开始匹配 -->str2就是arr2字符串的起始位置,将它的地址赋值给遍历指针s2

9.strtok 切割有标记符的字符串

注意要点

(1)sep参数是个字符串,定义了用作分隔符的字符集合

(2)第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分隔的标记

(3)strtok函数找到str中的下一个标记,并将其用\0结尾(也就是说将标记符改为\0),返回一个指向这个标记的指针

(注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)

(4)第一次调用:

strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置

(5)第二次到第n次调用:

strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记

(注意:NULL空指针要包含头文件#include<stdio.h>)

(6)最后一次调用的时候,字符串中不存在更多的标记,则返回NULL指针

(7)strtok函数特殊的地方在于:

它具有记忆的功能.调用之后还记得原字符串位置等信息

使用场景

例如:

(1)IP地址:192.168.10.5

能否将192和168和10和5这四个部分提取出来呢?

(2)邮箱:zhuimin@yeah.net

这里的@ 和. 叫做分隔符.

能否将被分割开的三部分提取出来呢?

简单应用

int main() {
  char  arr[] = "zhuimin@yeah.net";
  char buf[30] = { 0 };
  strcpy(buf, arr);  //拷贝一份
  const char* p = "@."; //标记符集合的字符串
  char* str = strtok(buf, p);        //第一次分割:在buf中找到p中的第一个标记符,将其修改为\0,保存并记住这个标记符的位置,函数返回标记段的起始位置
  printf("%s\n", str);
  str = strtok(NULL, p);       //第二次分割:strtok从第一次切割时保存的标记符位置处查找下一个标记
  printf("%s\n", str);
  str = strtok(NULL, p);      //第三次分割:strtok从第二次分割后保存的位置处查找下一个标记,发现此时字符串中没有更多的标记,结果返回空指针
  printf("%s\n", str);
  return 0;
}

如果是n次,也要写n次调用函数太麻烦了

优化一下

int main() {
  char  arr[] = "zhuimin@yeah.net";
  char buf[30] = { 0 };
  strcpy(buf, arr);  //拷贝一份
  const char* p = "@."; //标记符集合的字符串
  char* str = NULL;
  for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p)) {
    printf("%s\n", str);
  }
  return 0;
}

错误示范

因为这里的buf是常量字符串,有const修饰不能被修改,所以调用strtok时会出错.

10.strerror 把错误码翻译成错误信息,返回的是错误信息的起始地址

注意要点

其实:

(1)C语言的库函数在调用失败的时候,会将一个错误码存放在一个叫errno的变量中,当我们想知道调用哪个函数的时候发生了什么错误信息,就可以将errno中的错误码翻译成错误信息

(2)调用多个库函数的时候,大家是共用errno的,要及时去观察errno,下一次调用它的值会被修改

比如说:

库函数1调用失败//errno:3

库函数2调用成功//errno:0

简单应用

int main() {
  char* p = strerror(0);
  printf("%s\n", p);
  p = strerror(1);
  printf("%s\n", p);
  p = strerror(2);
  printf("%s\n", p);
  p = strerror(3);
  printf("%s\n", p);
  p = strerror(4);
  printf("%s\n", p);
  return 0;
}

int main() {
  //打开文件
  //打开文件的时候,如果文件的打开方式是"r"  (读)
  //文件存在则打开成功,文件不存在则打开失败
  //打开失败的时候,会返回NULL
  FILE* pf = fopen("text.txt", "r");
  if (pf == NULL) {
    printf("打开文件失败,原因是%s\n", strerror(errno));
    return 1;
  }
  //读写文件
  //....
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}

注意:新建一个文本文档时看一下有没有有开启文件扩展名,又饿能创建成test.txt.txt

11.字符分类函数

头文件 <ctype.h>

函数 判断一个字符是不是

iscntrl 任何控制字符

isspace 空白字符:空格’ ‘;换页’\f’;换行’\n’;回车’\r’,制表符’\t’或者垂直制表符’\v’

isdigit 十进制数字’0’~‘9’(是数字字符的话,返回非0数字,不是数字字符,返回0)

isxdigit 十六进制数字,包括所有十进制数字,小写字母a~ f,大写字母A~F

islower 小写字母a~z

isupper 大写字母A~Z

isalpha 字母a~z或者A ~Z

isalnum 字母或者数字,a~ z,A ~ Z,0~9

ispunct 标点符号,任何不属于数字或者字母的图形字符

isgraph 任何图形字符

isprint 任何可打印字符,包括图形字符和空白字符

字符转换

tolower 转换成小写字符

toupper 转换成大写字符

例如:

printf(“%c\n”,tolower(‘X’)); //x

printf(“%c\n”,toupper(‘x’)); //X

字符转换函数的简单使用

#include<stdio.h>
#include<ctype.h>
void test() {
  char arr[120] = { 0 };
  gets(arr);
  int i = 0;
  while (arr[i]){
    if (isupper(arr[i])) {
      arr[i] = tolower(arr[i]);
  }
    printf("%c", arr[i]);
    i++;
    }
}
int main() {
  test();
  return 0;
}

12.memcpy 内存拷贝(仅两个不重叠的内存空间可用)

注意要点

(1)函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置

(2)这个函数在遇到’\0’的时候并不会停下来

(3)如果source和destination有任何的重叠,复制的结果都是未定义的

(4)void* 通用类型指针,可以接受任意类型数据的地址,但是这种指针不能直接解引用和±操作

简单应用

将arr1中的前五个元素拷贝到arr2中

void test1() {
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr2[8] = { 0 };
  //将arr1中的前五个元素拷贝到arr2中
  //元素类型是int类型,五个元素总共是20字节
  memcpy(arr2, arr1, 20);
  int i = 0;
  while (arr2[i]){
    printf("%d ",arr2[i]);
    i++;
    }
}
int main() {
  test1();
  return 0;
}

将arr1中的前3个元素拷贝到arr2中

void test2() {
  float arr1[] = { 1.0f,2.0f,3.0f,4.0f,5.0f,6.0f,7.0f,8.0f,9.0f,10.0f };
  float arr2[8] = { 0 };
  //将arr1中的前3个元素拷贝到arr2中
  memcpy(arr2, arr1, 12);
  int i = 0;
  while (arr2[i]){
    printf("%f ",arr2[i]);
    i++;
    }
}
int main() {
  test2();
  return 0;
}

模拟实现memecpy

#include<assert.h>
void* my_memcpy(void* dst, const void* src, size_t count)
{
  void* ret = dst;  //临时变量保存dst地址
  assert(dst && src);  //断言两个指针不能为空指针
  while (count--) {   //每次处理一个字节,将指针强制类型转换成char*
    *(char*)dst = *(char*)src;  //一个字节一个字节的拷贝(注意:强制类型转换是临时的,转换完解引用dst还是void*类型
    dst = (char*)dst + 1;  //跳过一个字节后的地址给dst,dst是void类型,可以接收
    src = (char*)src + 1;
  }
  return ret;
}

想将1,2,3,4,5拷贝到3,4,5,6,7的位置

#include<assert.h>
void* my_memcpy(void* dst, const void* src, size_t count)
{
  void* ret = dst;  //临时变量保存dst地址
  assert(dst && src);  //断言两个指针不能为空指针
  while (count--) {   //每次处理一个字节,将指针强制类型转换成char*
    *(char*)dst = *(char*)src;  //一个字节一个字节的拷贝(注意:强制类型转换是临时的,转换完解引用dst还是void*类型
    dst = (char*)dst + 1;  //跳过一个字节后的地址给dst,dst是void类型,可以接收
    src = (char*)src + 1;
  }
  return ret;
}
void test3() {
  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memcpy(arr1 + 2, arr1, 20);  //想要把1,2,3,4,5拷贝到3,4,5,6,7的位置
  int i = 0; for (i = 0; i < 10; i++) {
    printf("%d ", arr1[i]);
  }
}
int main() {
  test3();
  return 0;
}

预想效果: 1 2 1 2 3 4 5 8 9 10

实际效果: 1 2 1 2 1 2 1 8 9 10

为什么会是现在这样的效果呢?

在拷贝3到5的位置时的时候,其实原来3位置已经被之前拷贝的数据覆盖修改过了,变成1了

所以,我们发现在内存重叠的时候,使用memcpy会出现意想不到的效果

13.memmove 内存拷贝(两个重叠内存和不重叠内存都可以使用)

注意要点

(1)和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的

(2)如果源空间和目标空间出现重叠,就得使用memmove函数处理

memmove的功能包含memcpy

总的来说,mommove的功能100分,memcpy功能有60分

但是在vs编译器上二者都做到了100分的程度(也就是说在vs上二者功能一致)

模拟实现memmove

实现思路

(1)首先我们应该清楚:

(2)然后我们固定源数据位置,根据上面的图讨论dst在不同位置时应该是从前往后拷贝还是从后往前拷贝?

(3)分情况讨论:

方案A:

1,3区域:前–>后拷贝

2区域:后–>前拷贝

方案B:

1区域:前–>后拷贝

2,3区域:后–>前拷贝

上面两个方案,显然方案B比较简单

方案B代码规划:

if(dst<src)

{

前–>后拷贝; //==偷懒小技巧:my_memcpy模拟函数就是从前往后拷贝,可以把代码直接拿过来使用

}

else{

后–>前拷贝;

}

(4)代码实现

void my_memmove(void* dst,void* src,size_t num) {
  void* ret = dst;
  assert(dst && src);
  if (dst < src) {  //从前往后拷贝
    while (num--) {
      *(char*)dst = *(char*)src;
      dst = (char*)dst+1;
      src = (char*)src+1;
    }
  }
  else {      //从后往前拷贝
    while (num--) {
      *((char*)dst + num) = *((char*)src + num);
    }
  }
  return ret;
}

14.memcmp 内存比较

(任意给两块内存,就可以比较这两块内存中放的数据是否一样)

注意要点

(1)比较从ptr1和ptr2指针开始的num个字节

(2)返回值如下:

ptr1指针处的数据<ptr2指针处的数据 返回<0的数字

ptr1指针处的数据=ptr2指针处的数据 返回0

ptr1指针处的数据>ptr2指针处的数据 返回>0的数字

简单应用

void test5() {
  int arr1[] = { 1,2,3,4,5 };
  int arr2[] = { 1,2,3,4,6 };
  int ret1 = memcmp(arr1, arr2, 16);
  int ret2 = memcmp(arr1, arr2, 17);
  printf("%d\n", ret1);
  printf("%d\n", ret2);
}
int main() {
  test5();
  return 0;
}

15.memset 内存设置函数

把ptr指向的后面num个字节每个的内存块设置为value

简单应用

//将hello改为xxxxx
void* test6() {
  char arr[] = "hello world";
  memset(arr, 'x', 5);
  printf("%s\n", arr);
}
int main() {
  test6();
  return 0;
}

//将数组的10个元素全改为1
void* test7() {
  int arr[10] = { 0 };
  memset(arr, 1, sizeof(arr));
  int i = 0;
  for (i = 0; i < 10; i++) {
    printf("%s\n", arr[i]);
  }
}
int main() {
  test7();
  return 0;
}

这种写法是错误的,无法将数组的每个元素设置为1

因为arr中每个元素是整型(4字节),将每个字节的数据改为01,该元素(int类型)不是1

验证一下

(以%p打印2进制数字,8个一组;

以%x打印2进制数字,二进制数字前面的0不打印)


总结

本篇内容就介绍到这里啦,如果对大家有帮助的话,记得点赞收藏博客,关注后续的C语言学习内容哦~😉😉

相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
24天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
36 3
|
1月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
26天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
22 0
|
1月前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
19 0
|
1月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
10天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
27 6
|
30天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
35 10
|
23天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。