[学习][记录] c语言:从放弃到入门(上)

简介: [学习][记录] c语言:从放弃到入门

【常用函数列表】

字符串常用函数

c/c++中宽窄字符串函数对应关系

【新手常见问题】

1.二级指针与二维数组

2.char* pText[] 和 char** ppText

【9-3 变量生命周期和修饰符】

生命周期

函数的声明周期

起于调用,结束于调用结束

局部变量的生命周期

起于调用,结束于调用结束

main函数的生命周期

main开始  == 进程的开始   main函数的结束  == 进程的结束

全局变量的生命周期

起于main调用,结束于main调用结束

修饰符

auto

含义:只能用于修饰局部变量,表示该变量存储于栈stack
      特点: 随用随开,用完消失
      C中默认的局部变量,就是auto类型,所以通常将其省略   c++ auto自动类型

register

含义:只能修饰局部变量,原则上,将内存中的变量升级到CPU寄存器中存储,这样访问速度会更快,但由于CPU寄存器数量有限,通常会在程序优化阶段,被优化为普通auto类型,可以通过汇编代码来查看,优化过程(与平台和编译有关)
    特点:可以避免cpu与内存的频繁交互 
    一般程序从内存读取数据 放到寄存器 进行运算 运算结果写入到内存

关于各个存储部件中读写速度

硬盘:7200转
      内存:频率1333MHZ 1600MHZ  带宽 = 频率*64/8
      缓存:
      CPU:

extern

含义:只能用于修饰全局变量,全局变量本身是全局可用的,但是由于文件是单个完成编译,
  并且编译是自上而下的,
  所以说,对于不是在本范围内定义的全局变量,要想使用必须用extern 进行申明,
  如果不加上可能会造成重定义。
    特点:
  1.可以省略,声明在前,定义在后,不论局部还是全局。  
     main.c  :   int a;  other.c : int a =200;编译不会报错
   2.外延性 某文件定义的全局变量 可在其他文件使用
c语言编译是跨文件的
编译过程:单文件编译 单文件每个编译成xxx.o
                链接所有.o文件和lib.so文件
                生成可执行文件xxx.out

【9-4 static】

修饰局部变量
特点:1.初始化值为0,且只初始化一次
         2.生命周期等同于程序
修饰全局变量
特点:1.全局的外延性消失,变成文件内部的全局变量  也适用于函数
         2.存储在data段

小结问题:

  1. extern int a;
    int a= 200;
    是不是同一个a?
  2. 局部变量和全局变量储存的位置有什么不同?
  3. static修饰的变量值所保存的位置在哪里 才导致是累计变化的?
    保存在data段中

【9-5 字符串常量——9-7字符串的输入输出】

定义

是双引号括起的任意字符序列

字符串大小

看到的大小,比我们实际字面量要多一个,
  最后的字符’\0’,我们称为字符串结束字符,是系统对双引号引起的字符串自动加设 的,而非手动干预。

字符串存储

字符串的存储,不像其它普通类型的常量自变量的存储一样,普通类型自变量通常存储 在代码段(text),
   而字符串,则存储在数据段,且是只读数据段。
    也就是通常意义上的常量区,但是常量区这种说法,是不太精确的,也不提倡。 

拓展

栈区(stack):临时变量,局部变量,生命周期结束即销毁
   堆区(heap):一些new出来的变量 存储的地方 特定销毁时间统一销毁,析构函数
   数据段(data):用来存放程序中已初始化的全局变量的一块内存区域,属于静态内存分配。
   代码段(text):用来存放程序执行代码的一块内存区域,只读,且不可修改。可能包含一些只读的常数变量,例如字符串常量等。 
   bbs段:bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域

字符数组和字符串区别

1.字符串数组(栈区)是将text区的常量字符串 拷贝到栈区 字符串值的改变实际上是栈的值改变
     字符串指针 是直接指向 text区常量字符串地址 故不能改变text区的值
  2.相同点:字符数组长度大于等于字符串长度

字符串的输入输出

puts函数:printf的自带换行
    scanf函数:默认遇到空格结束输入,scanf("%[\n]s")遇到回车结束输入,但不检查输入长度,不安全
    gets函数:空格也可以读入,但不检查输入长度,不安全。
    fgets函数:参数列表(接收变量,长度,输入流)

tips

1.printf(“”) 空串有换行功能
    2.gets();不检查预留存储区是否能够容纳实际输入的数据,
    换句话说,如果输入的字符数目大于数组的长度,gets 无法检测到这个问题,就会发生内存越界,所以编程时建议使用 fgets()。
    char *fgets(char *s, int size, FILE *stream);
    fgets() 虽然比 gets() 安全,但安全是要付出代价的,
    代价就是它的使用比 gets() 要麻烦一点,有三个参数。
    它的功能是从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。它的返回值是一个指针,指向字符串中第一个字符的地址。
  3. c中允许 c++不允许 
   char a[2] = "china";
     printf("%s",a);
     输出结果:ch
     4.char * p = "china";
     printf("p = %p  p+1 = %p  p[0]=%c 0[p] =%c\n", p, p + 1, p[0], 0[p]);
     printf("  = %p      = %p      =%c      =%c\n", "china", "china"+1, "china"[0], 0["china"]);
     输出结果:地址不相等 与视频不符合

问题?

1.视频说   " 字符串,则存储在数据段"
• 1

这篇文章说了

在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等

2.字符串指针和字符数组的区别?
    字符数组可修改内容,有个拷贝过程,data段常量区拷贝到栈区,字符数组实际是栈区
    字符串指针如果指向data段字符串常量 是不可修改地址的,若是指向字符数组反而可以

【10-2 从字符串常量到字符数组】

【10-3 原生字符串处理】

strlen(char *) 字符串长度

strcat(char *head,char *tail) 连接两个字符串

注意:被连接的串必须有足够空间

but vs 可行…

char firstName[] = "jim";
char familyName[30] = "tim";
strcat(firstName, familyName);
printf("%s", firstName);
输出:jimtim

优化操作:

原本代码

while(*p) p++;
   char *p,*q;
   while(1){
     p * =q*;
     if(p* == '\0'){
    break;  
   }
   p++;q++;
   }
   优化后:
   while(*p) p++;
   while(*p++ = *q++);

Tip

  1. int* 和 char* ,float * 长度 是多少?
    指针统一长度为4byte
int a = 1;
    int* ap = &a;
    printf("%d \n", sizeof(ap));
    char * c = "123";
    printf("%d \n", sizeof(c));
    float d = 1.0f;
    float * dp = &d;
    printf("%d \n", sizeof(dp));
输出:4
       4
       4   
  1. char *ac = “123”;
    printf("%p \n", &ac);
    printf("%p \n", “123”);
    为什么输出地址不同?

3.字符串长度和大小是不同的

长度是指字符长度且不包含\0,大小是指字节大小包含\0

【10-7 字符串指针数组入门】

指针数组的本质是数组,数组指针的本质是指针。

Tips

1.运行这段代码 设置字符串池优化

char * pa = "china"; char *pb = "america"; char*pc = "canada"; char*pd = "japan";
    char * cpArr[4] = { pa,pb,pc,pd };
    printf("pa =  %p \n", pa);
    printf("pb =  %p \n", pb);
    printf("pc =  %p \n", pc);
    printf("pd =  %p \n", pd);
    for (int i = 0; i < 4; i++)
    {
      printf("%p \n",cpArr[i]);
    }
    printf("----------------\n", pd);
    char * cpArr2[4] = {"china","america","canada", "japan" };
    for (int i = 0; i < 4; i++)
    {
      printf("%p \n", cpArr2[i]);
    }
  1. NULL ,nullptr,0区别

【11-1 栈内存和堆内存的基本概念】

概念

源程序:源代码

程序:可执行文件

进程:时间概念可执行性文件被拉起,到结束的这一段过程,称为进程

进程空间:可执行文件 被拉起以后 在内存中的分布情况

栈内存

栈存储的特点

栈中存放任意类型的变量,但必须是 **auto** 类型修饰的,即自动类型的局部变量,随用随开,用完即消。
    内存的分配和销毁系统自动完成,不需要人工干预。
    分配顺序,由高地址到低地址。

栈的大小

栈的大小并不大,他的意义并不在于存储大数据,而在于数据交换。

常见栈溢出

局部变量申请过多,过大,char[1024*1024*10];
  递归层数太多 例如10000层递归

堆内存

栈存储的特点

堆内存可以存放任意类型的数据,但需要自己申请与释放。
  分配顺序,由低地址到高地址。

堆大小

堆大小,想像中的无穷大,对于栈来说,大空间申请,唯此,无它耳。但实际使用中,受限于实际内存的大小和内存是否连续性。(基本最大为用户空间大小)

Tips

1.memset(pm,1,10*sizeof(int);

为每个字节赋值为1;一个int 实际4个字节 4个0x01
   printf("%#x");
   %#表示的输出提示方式,如果是8进制,在前面加0,如果是十进制,不加任何字符,如果是十六进制,会加上0x 

2.calloc和malloc

calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不做初始化,分配到的空间中的数据是随机数据

3.realloc

void *realloc(void *ptr, size_t size);

功能:扩容(缩小)原有内存的大小。通常用于扩容,缩小会会导致内存缩去的部分数据丢失。

参数:

void *ptr:ptr 表示待扩容(缩小)的指针, ptr 为之前用 malloc 或 者 calloc 分配的内存地址。或 ptr==NULL,则该函数等同于 malloc。

size_t:size 表示扩容(缩小)后内存的大小。

返回值:

成功返回非空指针指向申请的空间 ,失败返回 NULL。返回的指针,可能与 ptr 的值相同,也有可能不同。若相同,则说明在原空间后面申请,否则,则可能后续空间不足,重新申请的新的连续空间,原数据拷贝到新空间,原有空间自动释放。

原理:先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

malloc 使用流程 申请 判空 使用 释放 置空

问题1:指针接收 创建的内存空间(malloc),释放时怎么知道释放(free)多少内存空间的

heap的每个块儿头有保存本块的大小以及本块分配的大小。

free并不知道那个指针所指空间的大小,它要先查找当前heap的头部,然后整个块儿释放掉。

问题2:如何用malloc/new 定义一维,二维,三维数组?用free/delete销毁呢?malloc/free和new/delete区别?

问题3:malloc/calloc/realloc 区别与不同?

问题4:常见的内存泄露和检测内存泄露的常见方式?内存泄漏和野指针?

相关文章
|
4月前
|
安全 编译器 C语言
C++入门1——从C语言到C++的过渡
C++入门1——从C语言到C++的过渡
93 2
|
1月前
|
存储 编译器 C语言
【C语言程序设计——入门】C语言入门与基础语法(头歌实践教学平台习题)【合集】
本文档介绍了C语言环境配置和编程任务,主要内容包括: - **C语言环境配置**:详细讲解了在Windows系统上配置C语言开发环境的步骤。 - **第1关:程序改错**:包含任务描述、相关知识(如头文件引用、基本语法规则)、编程要求、测试说明及通关代码。 - **第2关:scanf函数**:涉及`scanf`和`printf`函数的格式与使用方法,提供编程要求、测试说明及通关代码。 文档结构清晰,涵盖从环境搭建到具体编程任务的完整流程,适合初学者学习和实践。
50 4
|
1月前
|
C语言
【C语言程序设计——入门】基本数据类型与表达式(头歌实践教学平台习题)【合集】
这份文档详细介绍了编程任务的多个关卡,涵盖C语言的基础知识和应用。主要内容包括: 1. **目录**:列出所有关卡,如`print函数操作`、`转义字符使用`、`数的向上取整`等。 2. **各关卡的任务描述**:明确每关的具体编程任务,例如使用`printf`函数输出特定字符串、实现向上取整功能等。 3. **相关知识**:提供完成任务所需的背景知识,如格式化输出、算术运算符、关系运算符等。 4. **编程要求**:给出具体的代码编写提示。 5. **测试说明**:包含预期输入输出,帮助验证程序正确性。 6. 文档通过逐步引导学习者掌握C语言的基本语法和常用函数,适合初学者练习编程技能。
45 1
|
2月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
124 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
4月前
|
存储 Java 编译器
初识C语言1——C语言入门介绍
初识C语言1——C语言入门介绍
56 1
|
4月前
|
C语言
教你快速理解学习C语言的循环与分支
教你快速理解学习C语言的循环与分支
27 0
|
4月前
|
C语言
回溯入门题,数据所有排列方式(c语言)
回溯入门题,数据所有排列方式(c语言)
|
6月前
|
C语言
C语言------程设设计入门
这篇文章是C语言程序设计的入门教程,涵盖了C程序的实现过程、VC集成开发环境的使用、基本数据类型的使用、格式控制字符的作用,以及通过示例代码演示了如何使用printf()函数输出不同类型的数据。
C语言------程设设计入门
|
7月前
|
存储 Java C语言
【C语言入门】初识C语言:掌握编程的基石
【C语言入门】初识C语言:掌握编程的基石
87 4
【C语言入门】初识C语言:掌握编程的基石
|
6月前
|
NoSQL Java 编译器
C语言从入门到精通该怎样学?
持续学习与实践:编程是一门需要不断学习和实践的技能,要保持对新技术和新知识的敏感性,并持续进行编程实践。
75 1

热门文章

最新文章