C语言学习笔记(一)

本文作者分享了自己学习C语言的经历,重点介绍了数据类型(如int、char、float等),以及如何使用printf和scanf进行基本的输入输出,包括字符类型的ASCII码、转义字符和字符串处理。文章强调了实践的重要性,计划通过编写博客巩固所学知识。
摘要由CSDN通过智能技术生成

寒假时在b站上挑了个C语言的课程,花了一个多月看完了,也算是入门C语言了吧。

在看那个课时,讲师很多次强调,一定要多写博客,来记录自己的学习。

显然,以我的自制力,课程看完了,博客是一篇没写。

现在C语言算是入门了,但还是缺乏巩固。

于是乎,便打算写几篇C语言学习的总复盘,用于巩固昔日所学。

后面我会花几天,尽力去复盘学到的知识结合自己为数不多的做题经验,写成博客,并坚持更新下去。

宏观感知

先从宏观上总览一下C语言

数据类型

学习C语言,首先是了解其数据类型。

内置类型

类型

范围

字符长度(字节)

整数

整型

int

-2147483648--2147483647

0--4294967295

2

短整型

short

-32768--32767

0--65535

2

长整型

long

4

扩展长整型

long long

8

字符

字符型

char

1

小数

单精度浮点型

float

6-7位精度

4

双精度浮点型

double

15位精度

8

扩展~

long double

空类型

void

布尔类型

_Bool

1

这些类型有什么用?

1.用于定义数据

2.设置函数返回值类型

3.定义函数参数

4.强制类型转换

int a=0;
int get_num(int x,int y);

char ch='a';
ch=(int)ch;

其中最常用的,莫过于int、char、float、void。我也仅对这四种类型做解释(毕竟我学的少其它的还没太接触过哈哈哈)

int

整型,没什么好说的,可能是平日里接触最多的类型了

一般的逻辑运算,大部分都是依靠int的

int i;

数组的读取arr[i]

指针的位移*p+i

或者是自加减 ++、--

还有一个数不同的进制表示,二进制、八进制、十进制、十六进制,都是int类型

其运算逻辑,什么加减乘除、比大小,都是遵循日常的数学运算。

char

字符类型,这需要说的就比较多了。

对于单个字符和字符串是有不同处理方式的

char x='a';
char* pch="abcdef";

而在数组中,字符串可以直接放入数组,并且每个字符会在数组中依次排开

char arr[]="abcdefg";
char arr[]={'a','b','c','d','e','f','g','\0'};
ASCII码

和字符联系最紧密的莫过于ASCII码了。

从中可以看到,每个字符都对应一个十进制数字。

值得注意的是三个区域的字符:0--9、A--Z、a--z

0--9

这里的数字不同于整数的0--9,而是以字符类型存储,即赋值时应用 ‘ ’

char ch='1';
char arr[20]='123456789';
A--Z和a--z

1.小写字母比相应大写字母大32——这个可以用于大小写的转化。

char ch='A';
ch=ch+32;//这样ch就从A变为了a,实现大小写转化
A--Z和a--z

1.小写字母比相应大写字母大32——这个可以用于大小写的转化。

char ch='A';
ch=ch+32;//这样ch就从A变为了a,实现大小写转化

对于大小写的转化还有一种方式

char arr[20]="ABCDEFG";
arr[i]=arr[i]-'A'+'a';

从上面两个代码能看出来很重要的一点

就是字符是可以直接进行运算的。

char的本质

char存储的本质是字符对应的ASCII码

因为char储存的是字符的ASCII码,所以char本质上也是一种整型,可以像整数一样进行运算。

字符可以直接进行加减乘除(注意ASCII码是否溢出),也可以进行比大小。

char ch='A';
int a=10;//由于A的ASCII值为65,所以ch>a

输入输出

初学C语言最常用的,莫过于stdio.h库中的printf和scanf了

输入输出的基本格式是

scanf("%N",&x);
printf("%N",x);

现在逐一讲解以上元素

%N

%N是一种占位符,

在实际输入输出时,是输入输出" "中的内容,因此当你要输入输出一个变量的值时,你要告诉"",在它之中存在一个变量。%N这个占位符就是这个作用。

%N中N有以下类型,分别对应不同的数据类型

%d

十进制整型

int

%c

字符型

char

%s

字符串型

char*

%f

浮点型

float

%lf

双精度浮点型

double

%p

指针的值,十六进制

*

%.2f

两位小数浮点数

float

%5d

占用至少5个字符宽度整数。不足部分左边空格填充

int

%-5d

不足部分右边空格填充

int

%x

十六进制整型

int

%zu

无符号整数

size_t

值得注意的是

%N所对应的类型未必一定要与对应数据的类型相对应。

如上面提到的,char储存的实际上是字符对应的ASCII码。

因此可以这样操作

char ch='a';
printf("%d",a);//实际输出a的ascii码,97
//或者在变量前先进行整型转化,再输出
printf("%d",(int)a);//97

这就是一种"强制类型转化",在强制转化符()中会再次提到。

转义字符——\

字符

解释

\n

换行符

输出换行

\0

空字符

表示字符的结束

\r

回车符

回到当前行的开头,不开始新的一行

\t

制表符

\"

双引号

'

单引号

\nnn

八进制转意

nnn为三位八进制数,表示一个八进制编码对应的字符

\xhh

十六进制转义

hh为两个十六位进制数,表示一个十六进制编码对应的字符

\a

警告/响铃

这些转义字符虽然基本上都是有多个字符组成,但实际上为一个字符

在新手里其中最常见的应该就是\n和\0了

\n

就是输出换行,放在“”中使用

printf("\n");//单个的换行
printf("%d %d %d\n",a,b,c);//在输出abc的值后换行
printf("*******\n********\n******");//一次输出中多次换行

一般printf("\n");总是放在某一个for循环之外,例如输出二维数组时

for(int i=0;i<10;i++)
{
    for(int j=0;j<10;j++)
    {
        printf("%d ",arr[i][j])
    }
    printf("\n");
}

这样就能将数组输出为二维,不至于输出一行一整串

\0

空字符,经常和字符串搭配使用

当输入一个字符串时,往往会自动在字符串后面加上\0表示这个字符串在这里终止。

char ch1[]="abcd";//实际输入到ch1[]中的元素为abcd\0。自动补了\0
char ch2[]={'a','b','c','d'};//实际输入到ch2[]中的为abcd,无\0,不会自动补\0
//即,ch1[]储存的比ch2[]储存的多一个\0

\0在字符串中有许多作用,作为字符串结束的标志位,保证了储存空间的稳定。

有许多字符函数都是在\0的基础上操作的,如strlen、strcpy、strcmp...

这里顺便说下strlen和sizeof的区别

sizeof:

int arr[]="Hello,World!";
printf("%zu\n", sizeof(arr));  // 输出13,因为包括字符串末尾的\0

strlen:

char str[] = "Hello, World!";
printf("%zu\n", strlen(str));  // 输出:12,因为字符串不包括结尾的'\0'字符

由上可以看出,sizeof和strlen都可以计算一个字符串的长度(即字节数)(字符为char型,一个字符为一个字节)

但是srelen不会算上\0,sizeof会算上。即一般情况下,同一字符串,sizeof的值比strlen的值大一。

\nnn

即八进制转化为字符

如/072,表示八进制072,转化为十进制为50,在ASCII中对应字符’Z‘。

char nnn= '\072';
printf("%c\n", nnn;  // 输出:Z
printf("\072");//输出:Z
\xhh

即十六进制转化为字符

如\x41,表示十六进制数41,十进制65,对应ASCII中的’A‘。

char xhh= '\x41';
printf("%c\n", xhh);  // 输出:A
printf("\x41"); // 输出:A

printf

从以下几点问题展开

1.如何输出元素

确定输出几个元素、每个元素是什么类型、每个元素之间是什么格式

int a=10;        //%d
int *pa=&a;        //%p
char c='a';        //%c
char ch="abcde";    //%s
float b=1.445;    //%f
double d=1.44514    //%lf

printf("%d %p %c %s %f %lf",a,pa,c,ch,b,d);
printf("%.2f",b);//输出二位小数的b
printf("%x",a);//用十六进制输出a
printf("%e",b);//用科学记数法输出b

2.如何输出一个数组

在一个循环中嵌套printf

就是每次进入循环时输出一次

int arr[10];
for(int i=0;i<10;i++)
{
    printf("%d ",arr[i])
}

scanf

同样按照以下几点展开

1.如何输入元素

int a;
char c;
char ch[10];
scanf("%d  %c %9s",&a,&c,ch);

这里注意到,scanf比printf多一个&

&是取地址符,取出相应变量的地址,然后将你输入的数据写到地址里

而printf只是读取变量的数据,因此不需要&

那么为什么ch前没有&呢?

那是因为数组名本身就是个指针,也就是已经指向此元素的地址。因此无需&

很多时候我们不清楚要输入多少元素,或者使用数组输入可能会有些繁琐,于是可以像下面这样

while(scanf("%d",a))
{
    sum=sum+a;//循环体,每次进入循环属于一次值,并把每次输入的值相加
}

或者是做题时,题目没有说运行到什么时候停止或者是要求输入多组数字。

while(scanf("%d %d %d",&a,&b,&c)!=EOF)
{
    //循环体
}

3.如何输入一个数组/字符串

一般也是通过for循环+scanf的方式

int ch[10];
for(int i=0;i<10;i++)
{
    scanf("%c",ch[i]);
}

这个方式不足之处就是,你首先需要清楚要输入几个元素。一般题目中都会是让你先输入元素数,再输入元素。

因此可以有以下改进

int a = 0;
int arr[10] ;
int i = 0;
while (scanf("%d", &a) !=EOF)
{
        if (a == 0)
        {
                break;
        }
        arr[i] = a;
        i++;
}
for (int j = 0; j < i; j++)
{
        printf("%d ",arr[j]);
}

这里是当输入0时才截止(将0作为输入停止标志),且0不会被写入数组中

0作为停止标志仅是用于自己调试代码。

实际用电脑测试时,电脑会自动读取EOF(文件结束)然后结束输入。

或者采用动态输入的方式(但我不会哈哈哈)

代码先放上

//在C语言中,如果不确定需要输入多少个数组元素,
//可以采取动态内存分配的方式来输入数组。
//下面是一个使用malloc和realloc动态分配和扩展数组的示例:
#include <stdio.h>
#include <stdlib.h>

#define INITIAL_CAPACITY 10

int main() {
    int count = 0;
    int current_capacity = INITIAL_CAPACITY;
    int *arr = (int*)malloc(current_capacity * sizeof(int));

    printf("请输入一系列整数,输入非数字字符(如回车)结束输入:\n");

    int num;
    while (scanf("%d", &num) == 1) {  // 当成功读取到一个整数时,循环继续
        if (count == current_capacity) {
            // 当数组已满时,增大数组容量
            current_capacity *= 2;
            arr = (int*)realloc(arr, current_capacity * sizeof(int));
            if (arr == NULL) {
                printf("内存分配失败!\n");
                exit(EXIT_FAILURE);
            }
        }
        arr[count++] = num;
    }

    // 检查输入结束是因为遇到文件结束符EOF还是因为读取失败
    if (feof(stdin)) {
        // 正常结束,打印数组元素
        printf("\n输入的整数数组为:");
        for (int i = 0; i < count; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    } else {
        printf("读取输入时发生错误!\n");
    }

    free(arr);  // 释放不再需要的内存
    return 0;
}
//这段代码首先创建一个初始容量的数组,并在每次填充满数组时将其容量翻倍。
//当读取到非数字字符时(这里是通过scanf返回值判断的),
//退出循环并打印已输入的整数数组。最后,释放不再需要的内存。
//注意,realloc可能会返回NULL,
//所以在扩展内存后应检查返回值以确保分配成功

但对于字符串,往往不使用scanf+循环的方式,而是下面这些

可使用%s来输入字符串,但不推荐这样,因为大量文本输入时会导致溢出

char ch[10];
scanf("%9s",ch);//限制输入9给字符防止溢出

fgets函数

#include<string.h>//fgets需要头文件string
char str[100];
fgets(str,sizeof(str),stdin);
//美中不足是,用fgets输入字符串往往还会把 \n 也输入进去
//因此还需要以下操作
str[strcspn(str,'\n')]="\0";//将字符串数组中的\n改为\0
size_t sz=strlen(str)/strlen(str[0]);

OK,第一期就先到这里吧,毕竟自制力也不太行。

得尽早发一篇,然后让已经发出的这篇督促我继续创作。

如有问题,欢迎指正。

我努力尽早更下一期。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值