C_语句结构 | 数组 | 字符串(3/10)





happysneaker.com

整理了一下SQL注入简要流程图





以下博文所截笔记均来自:http://c.biancheng.net C语言中文网,并非用于营利,如有侵权,联系删除。





一、循环


1、if  else 

① 有的时候,我们需要在满足某种条件时进行一些操作,而不满足条件时就不进行任何操作,这个时候我们可以只使用 if 语句。也就是说,if else 不必同时出现。

max=b;  // 假设b最大
if(a>b) max=a;  // 如果a>b,那么更改max的值
printf("%d和%d的较大值是:%d\n", a, b, max);


2、switch  case

① C语言虽然没有限制 if else 能够处理的分支数量,但当分支过多时,用 if else 处理会不太方便,而且容易出现 if else 配对出错的情况。

② 例如,输入一个整数,输出该整数对应的星期几的英文表示:

#include <stdio.h>
int main(){
    int a;
    printf("Input integer number:");
    scanf("%d",&a);
    if(a==1){
        printf("Monday\n");
    }else if(a==2){
        printf("Tuesday\n");
    }else if(a==3){
        printf("Wednesday\n");
    }else if(a==4){
        printf("Thursday\n");
    }else if(a==5){
        printf("Friday\n");
    }else if(a==6){
        printf("Saturday\n");
    }else if(a==7){
        printf("Sunday\n");
    }else{
        printf("error\n");
    }
    return 0;
}

等同于switch case:

#include <stdio.h>
int main(){
    int a;
    printf("Input integer number:");
    scanf("%d",&a);
    switch(a){
        case 1: printf("Monday\n"); break;
        case 2: printf("Tuesday\n"); break;
        case 3: printf("Wednesday\n"); break;
        case 4: printf("Thursday\n"); break;
        case 5: printf("Friday\n"); break;
        case 6: printf("Saturday\n"); break;
        case 7: printf("Sunday\n"); break;
        default:printf("error\n"); break;
    }
    return 0;
}

它的执行过程是:
1) 首先计算“表达式”的值,假设为 m。

2) 从第一个 case 开始,比较“整型数值1”和 m,如果它们相等,就执行冒号后面的所有语句,也就是从“语句1”一直执行到“语句n+1”,而不管后面的 case 是否匹配成功。

3) 如果“整型数值1”和 m 不相等,就跳过冒号后面的“语句1”,继续比较第二个 case、第三个 case……一旦发现和某个整型数值相等了,就会执行后面所有的语句。假设 m 和“整型数值5”相等,那么就会从“语句5”一直执行到“语句n+1”。

4) 如果直到最后一个“整型数值n”都没有找到相等的值,那么就执行 default 后的“语句 n+1”。


因此要注意break的添加。break 是C语言中的一个关键字,专门用于跳出 switch 语句。所谓“跳出”,是指一旦遇到 break,就不再执行 switch 中的任何语句,包括当前分支中的语句和其他分支中的语句;也就是说,整个 switch 执行结束了,接着会执行整个 switch 后面的代码。


由于 default 是最后一个分支,匹配后不会再执行其他分支,所以也可以不添加break;语句。

最后需要说明的两点是:
1) case 后面必须是一个整数,或者是结果为整数的表达式,但不能包含任何变量。

2) default 不是必须的。当没有 default 时,如果所有 case 都匹配失败,那么就什么都不执行。



3、C语言中唯一的三目运算符

条件运算符,语法格式为:

表达式1 ? 表达式2 : 表达式3

条件运算符是C语言中唯一的一个三目运算符,其求值规则为:如果表达式1的值为真,则以表达式2 的值作为整个条件表达式的值,否则以表达式3的值作为整个条件表达式的值。条件表达式通常用于赋值语句之中。








二、循环


1、while、do-while


2、for(完全可以取代while)

① 死循环:

for(i=1; ; i++) sum=sum+i;

for( ; ; ) 也是死循环


3、break 

① 用来调出循环

② break可以跳出 switch

③ break可以跳出 while、for ,会终止循环而执行整个循环语句后面的代码。

④ break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。

⑤ 在多层循环中,一个 break 语句只向外跳一层。


4、continue

① 作用是跳过本次循环,强制进入下一次循环。

② 只用在 while、for 中。

③ 常与 if 条件语句一起使用,判断条件是否成立。

栗子:

#include <stdio.h>
int main(){
    char c = 0;
    while(c!='\n'){  //回车键结束循环
        c=getchar();
        if(c=='4' || c=='5'){  //按下的是数字键4或5
            continue;  //跳过当次循环,进入下次循环
        }
        putchar(c);
    }
    return 0;
}


break与continue的对比:break 用来结束整个循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环。


循环、选择:两种结构均可嵌套。








三、数组


1、一维数组

一般用循环将数据放入数组中(也就是为数组元素逐个赋值),然后再使用循环结构输出(也就是依次读取数组元素的值)

#include <stdio.h>
int main(){
    int nums[10];
    int i;
    
    //将1~10放入数组中
    for(i=0; i<10; i++){
        nums[i] = (i+1);
    }
    
    //依次输出数组元素
    for(i=0; i<10; i++){
        printf("%d ", nums[i]);
    }
    
    return 0;
}

运行结果:

1 2 3 4 5 6 7 8 9 10 

读取用户输入:

#include <stdio.h>
int main(){
    int nums[10];
    int i;
    
    //从控制台读取用户输入
    for(i=0; i<10; i++){
        scanf("%d", &nums[i]);  //注意取地址符 &,不要遗忘哦
    }
    
    //依次输出数组元素
    for(i=0; i<10; i++){
        printf("%d ", nums[i]);
    }
    
    return 0;
}


「数组内存是连续的」这一点很重要。连续的内存为指针操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等)提供了便利,这使得数组可以作为缓存(临时存储数据的一块内存)使用。

存储情形:
happysneaker.com


 通过下面的形式将数组的所有元素初始化为 0:

int nums[10] = {0};
char str[10] = {0};
float scores[10] = {0.0};

由于剩余的元素会自动初始化为 0,所以只需要给第 0 个元素赋值为 0 即可。


 只能给元素逐个赋值,不能给数组整体赋值。例如给 10 个元素全部赋值为 1,只能写作:

int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

而不能写作:

int a[10] = 1;


 如给全部元素赋值,那么在定义数组时可以不给出数组长度。例如:

int a[] = {1, 2, 3, 4, 5};

等价于

int a[5] = {1, 2, 3, 4, 5};


2、二维数组


① 

int a[3][4];

定义了一个 3 行 4 列的二维数组,共有 3×4=12 个元素,数组名为 a,即:

a[0][0], a[0][1], a[0][2], a[0][3]
a[1][0], a[1][1], a[1][2], a[1][3]
a[2][0], a[2][1], a[2][2], a[2][3]

如果想表示第 2 行第 1 列的元素,应该写作 a[2][1]。


② 【实例1】一个学习小组有 5 个人,每个人有 3 门课程的考试成绩,求该小组各科的平均分和总平均分。

--MathCEnglish
张涛807592
王正华616571
李丽丽596370
赵圈圈858790
周梦真767785

对于该题目,可以定义一个二维数组 a[5][3] 存放 5 个人 3 门课的成绩,定义一个一维数组 v[3] 存放各科平均分,再定义一个变量 average 存放总平均分。最终编程如下:

#include <stdio.h>
int main(){
    int i, j;  //二维数组下标
    int sum = 0;  //当前科目的总成绩
    int average;  //总平均分
    int v[3];  //各科平均分
    int a[5][3];  //用来保存每个同学各科成绩的二维数组
    printf("Input score:\n");
    for(i=0; i<3; i++){
        for(j=0; j<5; j++){
            scanf("%d", &a[j][i]);  //输入每个同学的各科成绩
            sum += a[j][i];  //计算当前科目的总成绩
        }
        v[i]=sum/5;  // 当前科目的平均分
        sum=0;
    }
    average = (v[0] + v[1] + v[2]) / 3;
    printf("Math: %d\nC Languag: %d\nEnglish: %d\n", v[0], v[1], v[2]);
    printf("Total: %d\n", average);
    return 0;
}

运行结果:
Input score:
80 61 59 85 76 75 65 63 87 77 92 71 70 90 85↙
Math: 72
C Languag: 73
English: 81
Total: 75

③ 

二维数组的初始化可以按行分段赋值,也可按行连续赋值。

例如,对于数组 a[5][3],按行分段赋值应该写作:

int a[5][3]={ {80,75,92}, {61,65,71}, {59,63,70}, {85,87,90}, {76,77,85} };

按行连续赋值应该写作:

int a[5][3]={80, 75, 92, 61, 65, 71, 59, 63, 70, 85, 87, 90, 76, 77, 85};

这两种赋初值的结果是完全相同的。


初始化赋值

可以只对部分元素赋值,未赋值的元素自动取“零”值。例如:

int a[3][3] = {{1}, {2}, {3}};

是对每一行的第一列元素赋值,未赋值的元素的值为 0。赋值后各元素的值为:
1  0  0
2  0  0
3  0  0

再如:

int a[3][3] = {{0,1}, {0,0,2}, {3}};

赋值后各元素的值为:
0  1  0
0  0  2
3  0  0

如果对全部元素赋值,那么第一维的长度可以不给出。例如:

int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

可以写为:

int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};



3、字符数组

字符数组实际上是一系列字符的集合,也就是字符串(String)C语言中,没有专门的字符串变量,没有string类型,通常就用一个字符数组来存放一个字符串。

用来存放字符的数组就叫做字符数组 

char a[10];  //一维字符数组char 
b[5][10];  //二维字符数组
char c[20]={'c', '  ', 'p', 'r', 'o', 'g', 'r', 'a','m'};  // 给部分数组元素赋值
char d[]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm' };  //对全体元素赋值时可以省去长度

C语言规定,可以将字符串直接赋值给字符数组,例如:

char str[30] = {"c.biancheng.net"};
char str[30] = "c.biancheng.net";  //这种形式更加简洁,实际开发中常用

数组第 0 个元素为'c',第 1 个元素为'.',第 2 个元素为'b',后面的元素以此类推。


一个坑

这里需要留意一个坑,字符数组只有在定义时才能将整个字符串一次性地赋值给它,一旦定义完了,就只能一个字符一个字符地赋值了。请看下面的例子:

char str[7];
str = "abc123";  //错误
//正确
str[0] = 'a'; str[1] = 'b'; str[2] = 'c';
str[3] = '1'; str[4] = '2'; str[5] = '3';






四、字符串


1、字符数组的初始化问题 和 字符串的结束符\0

字符串是一系列连续的字符的组合,要想在内存中定位一个字符串,除了要知道它的开头,还要知道它的结尾;

 找到字符串的开头很容易,知道它的名字(字符数组名或者字符串名)就可以;

如何找到字符串的结尾呢?C语言的解决方案有点奇葩:

在C语言中,字符串总是以'\0'作为结尾,所以'\0'也被称为字符串结束标志,或者字符串结束符。

'\0'是 ASCII 码表中的第 0 个字符,英文称为 NUL,中文称为“空字符”。该字符既不能显示,也没有控制功能,输出该字符不会有任何效果,它在C语言中唯一的作用就是作为字符串结束标志。

C语言在处理字符串时,会从前往后逐个扫描字符,一旦遇到'\0'就认为到达了字符串的末尾,就结束处理。'\0'至关重要,没有'\0'就意味着永远也到达不了字符串的结尾。


" "包围的字符串会自动在末尾添加'\0'例如,"abc123"从表面看起来只包含了 6 个字符,其实不然,C语言会在最后隐式地添加一个'\0',这个过程是在后台默默地进行的,所以我们感受不到。

下图演示了"C program"在内存中的存储情形:


需要注意的是,逐个字符地给数组赋值并不会自动添加'\0',例如:

char str[] = {'a', 'b', 'c'};

数组 str 的长度为 3,而不是 4,因为最后没有'\0'

当用字符数组存储字符串时,要特别注意'\0',要为'\0'留个位置;这意味着,字符数组的长度至少要比字符串的长度大 1:

char str[7] = "abc123";

"abc123"看起来只包含了 6 个字符,我们却将 str 的长度定义为 7,就是为了能够容纳最后的'\0'。如果将 str 的长度定义为 6,它就无法容纳'\0'了。

当字符串长度大于数组长度时,有些较老或者不严格的编译器并不会报错,甚至连警告都没有,这就为以后的错误埋下了伏笔,要注意。


 有些时候,程序的逻辑要求我们必须逐个字符地为数组赋值,这个时候就很容易遗忘字符串结束标志'\0'。下面的代码中,我们将 26 个大写英文字符存入字符数组,并以字符串的形式输出:

#include <stdio.h>
int main(){
    char str[30];
    char c;
    int i;
    for(c=65,i=0; c<=90; c++,i++){
        str[i] = c;
    }
    printf("%s\n", str);
    
    return 0;
}


运行结果:

ABCDEFGHIJKLMNOPQRSTUVWXYZ口口口口i口口0 ?

表示无法显示的特殊字符。

大写字母在 ASCII 码表中是连续排布的,编码值从 65 开始,到 90 结束,使用循环非常方便。


为了避免输出时的 \0 结束问题,专业的做法是将数组的所有元素都初始化为“零”值,这样才能够从根本上避免问题。再次修改上面的代码:

#include <stdio.h>
int main(){
    char str[30] = {0};  //将所有元素都初始化为 0,或者说 '\0'
    char c;
    int i;
    for(c=65,i=0; c<=90; c++,i++){
        str[i] = c;
    }
    printf("%s\n", str);
   
    return 0;
}


2、字符串长度

所谓字符串长度,就是字符串包含了多少个字符(不包括最后的结束符'\0')。例如"abc"的长度是 3,而不是 4。


3、字符串的输入、输出

① 输出C语言中,有两个函数可以在控制台(显示器)上输出字符串,它们分别是:

  • puts():输出字符串并自动换行,该函数只能输出字符串。

  • printf():通过格式控制符%s输出字符串,不能自动换行。除了字符串,printf() 还能输出其他类型的数据。

#include <stdio.h>
int main(){
    char str[] = "http://c.biancheng.net";
    printf("%s\n", str);  //通过字符串名字输出
    printf("%s\n", "http://c.biancheng.net");  //直接输出
    puts(str);  //通过字符串名字输出
    puts("http://c.biancheng.net");  //直接输出

    return 0;
}

运行结果:
http://c.biancheng.net
http://c.biancheng.net
http://c.biancheng.net
http://c.biancheng.net


② 输入

在C语言中,有两个函数可以让用户从键盘上输入字符串,它们分别是:

  • scanf():通过格式控制符%s输入字符串。除了字符串,scanf() 还能输入其他类型的数据。

  • gets():直接输入字符串,并且只能输入字符串。

但是,scanf() 和 gets() 是有区别的:

  • scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。

  • gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。


就目前学到的知识而言,int、char、float 等类型的变量用于 scanf() 时都要在前面添加&,而数组或者字符串用于 scanf() 时不用添加&,它们本身就会转换为地址。

大部分初学者都认为 scanf() 不能读取包含空格的字符串,不能替代 gets()。其实不然,scanf() 的用法还可以更加复杂和灵活,它不但可以完全替代 gets() 读取一整行字符串,而且比 gets() 的功能更加强大。比如,以下功能都是 gets() 不具备的:

  • scanf() 可以控制读取字符的数目;

  • scanf() 可以只读取指定的字符;

  • scanf() 可以不读取某些字符;

  • scanf() 可以把读取到的字符丢弃。



4、字符串处理函数——连接、复制、比较

① strcat()  strcat 是 string catenate 的缩写,意思是把两个字符串拼接在一起

#include <stdio.h>
#include <string.h>
int main(){
    char str1[100]="The URL is ";
    char str2[60];
    printf("Input a URL: ");
    gets(str2);
    strcat(str1, str2);
    puts(str1);
   
    return 0;
}

运行结果:
Input a URL: http://c.biancheng.net/cpp/u/jiaocheng/↙
The URL is http://c.biancheng.net/cpp/u/jiaocheng/


② strcpy() strcpy 是 string copy 的缩写,意思是字符串复制,也即将字符串从一个地方复制到另外一个地方,strcpy() 会把 arrayName2 中的字符串拷贝到 arrayName1 中,字符串结束标志'\0'也一同拷贝。请看下面的例子:

#include <stdio.h>
#include <string.h>
int main(){
    char str1[50] = "《C语言变怪兽》";
    char str2[50] = "http://c.biancheng.net/cpp/u/jiaocheng/";
    strcpy(str1, str2);
    printf("str1: %s\n", str1);

    return 0;
}

运行结果:
str1: http://c.biancheng.net/cpp/u/jiaocheng/


③ strcmp()  : strcmp 是 string compare 的缩写,意思是字符串比较

字符本身没有大小之分,strcmp() 以各个字符对应的 ASCII 码值进行比较。strcmp() 从两个字符串的第 0 个字符开始比较,如果它们相等,就继续比较下一个字符,直到遇见不同的字符,或者到字符串的末尾。

返回值:若 arrayName1 和 arrayName2 相同,则返回0;若 arrayName1 大于 arrayName2,则返回大于 0 的值;若 arrayName1 小于 arrayName2,则返回小于0 的值。

对4组字符串进行比较:

#include <stdio.h>
#include <string.h>
int main(){
    char a[] = "aBcDeF";
    char b[] = "AbCdEf";
    char c[] = "aacdef";
    char d[] = "aBcDeF";
    printf("a VS b: %d\n", strcmp(a, b));
    printf("a VS c: %d\n", strcmp(a, c));
    printf("a VS d: %d\n", strcmp(a, d));
   
    return 0;
}

运行结果:
a VS b: 32
a VS c: -31
a VS d: 0




Web安全技术分享
请先登录后发表评论
  • 最新评论
  • 总共0条评论