关于<C专家编程>的笔记

若依ruoyi框架实现单点登录或者接入统一认证 log.info("单点登录用户[{}]不存在, 需要创建.", loginName);log.info("单点登录用户[{}]已存在.", loginName);jsonObjectData.put("nickName","单点1");if (code.equals("0")) {//验证成功需要自动登录。jsonObject.put("msg","验证成功");ajax.put("msg", "登录成功"); 阅读详情
重新阅读<C专家编程>, 以下是一些笔记,觉得要重点掌握的。


1. 关于const的变量的赋值
foo(const char** p) { }
main(int argc, char** argv)
{
    foo(argv);  // ***
}

上面代码段中//***会产生编译错误。原因在于
const char** p = argv;
赋值是不被允许的。

C标准规定,两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。
正是这个条件,使得函数调用中实参char*能够与形参const char*匹配。
  • 左操作数是一个指向有const限定符的char的指针 (const是用来修饰char类型的,并不是修饰*指针类型的)
  • 右操作数是一个指向没有限定符的char的指针
  • char类型与char类型是相容的,左操作数所指向的类型具有右操作数所指向类型的限定符(其实没有),在加上自身的限定符(const)
类似地,const char**也是一个没有限定符的指针类型(const并不是修饰指针)。它的类型是“指向有const限定符的char类型的指针(const用来修饰char)的指针。
由于char**和const char**都是没有限定符的指针类型,但它们所指向的类型不一样(前者指向char*,后者指向const char*),因此它们是不相容的。

2. 整形转换
    if (-1 < (unsigned int)1) {
        fprintf(stderr, "-1 < (unsigned int)1)\n");
    } else {
        fprintf(stderr, "-1 > (unsigned int)1)\n");
    }

    if (-1 < (unsigned char)1) {
        fprintf(stderr, "-1 < (unsigned char)1)\n");
    } else {
        fprintf(stderr, "-1 > (unsigned char)1)\n");
    }
ANSI C给出的答案:
-1 > (unsigned int)1)  // -1被提升到(unsigned int)类型,所以就是(unsigned int)-1
-1 < (unsigned char)1) // -1类型不动,仍然是int类型,(unsigned char)1被提升到int类型

3. C语言的数组和函数声明
1) 函数的返回值允许是一个函数指针,如:
int (* func())();  // 函数名字是func,参数是空,返回值是一个声明为int (*f)()的函数类型;
int (* func(double)) (const char*); // 函数名字是func,参数为double,返回值是一个声明为int (*f)(const char*)的函数类型;
2) 函数的返回值允许是一个指向数组的指针,如: 
int (* foo())[]; // 函数名字是foo,参数为空,返回值为一个元素为int类型的数组的指针
3) 数组里面允许有函数指针,如int (* foo[])();
看到标志符后面紧跟[],那就表明是一个数组。最后面是一个用()括起来的东西,那就表明数组的元素是一个函数指针,括起来的列表是函数的参数列表,最前面的就是函数的返回值类型。
4) 数组里面允许有其它数组,所有你经常能看到int foo[][N] (但是必须声明列的大小)。
typedef int (*array[])[];
int a[] = {1, 2}; 
int b[] = {3, 4};
array ab = {&a, &b};

typedef int (array1[])[2];
array1 ab1 = {0, 1, };

关于上面的判断法则,作者专门写了一个C程序来自动识别,以下是完整的代码:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define MAXTOKENS 100
#define MAXTOKENLEN 64

enum type_tag { IDENTIFIER, QUALIFIER, TYPE };

struct token {
    char type;
    char string[MAXTOKENLEN];
};

int top = -1;
struct token stack[MAXTOKENS];
struct token this;

#define pop stack[top--]
#define push(s) stack[++top] = s

enum type_tag classify_string()
{
    char* s = this.string;
    if (!strcmp(s, "const")) {
        strcpy(s, "read-only");
        return QUALIFIER;
    }

    if (!strcmp(s, "volatile")) return QUALIFIER;
    if (!strcmp(s, "void")) return TYPE;
    if (!strcmp(s, "char")) return TYPE;
    if (!strcmp(s, "signed")) return TYPE;
    if (!strcmp(s, "unsigned")) return TYPE;
    if (!strcmp(s, "short")) return TYPE;
    if (!strcmp(s, "int")) return TYPE;
    if (!strcmp(s, "long")) return TYPE;
    if (!strcmp(s, "float")) return TYPE;
    if (!strcmp(s, "double")) return TYPE;
    if (!strcmp(s, "struct")) return TYPE;
    if (!strcmp(s, "union")) return TYPE;
    if (!strcmp(s, "enum")) return TYPE;
    return IDENTIFIER;
}

void gettoken()
{
    char* p = this.string;
    while ((*p = getchar()) == ' ') ;

    if (isalnum(*p)) {
        while (isalnum(*++p = getchar()));
        ungetc(*p, stdin);
        *p = '\0';
        this.type = classify_string();

        return ;
    }

    if (*p == '*') {
        strcpy(this.string, "pointer to");
        this.type = '*';
        return ;
    }
    this.string[1] = '\0';
    this.type = *p;
    return;
}

void read_to_first_identifier()
{
    gettoken();
    while (this.type != IDENTIFIER) {
        push(this);
        gettoken();
    }

    printf("%s is ", this.string);
    gettoken();
}

void deal_with_arrays()
{
    while (this.type == '[') {
        printf("array ");
        gettoken();
        if (isdigit(this.string[0])) {
            printf("0..%d ", atoi(this.string) - 1);
            gettoken();
        }
        gettoken();
        printf("of ");
    }

}

void deal_with_function_args()
{
    while (this.type != ')') {
        gettoken();
    }
    gettoken();
    printf("function returning ");
}

void deal_with_pointers()
{
    while (stack[top].type == '*')
    {
        printf("%s ", pop.string);
    }
}

void deal_with_declarator()
{
    switch (this.type) {
        case '[' :
        deal_with_arrays(); break;
        case '(' :
        deal_with_function_args(); break;
    }

    deal_with_pointers();

    while (top >= 0) {
        if (stack[top].type == '(') {
            pop;
            gettoken();  // read chars after ')'
            deal_with_declarator();
        } else {
            printf("%s ", pop.string);
        }
    }
}

int main(int argc, char** argv)
{
    read_to_first_identifier();
    deal_with_declarator();
    printf("\n");
    return 0;
}

譬如输入“const char* (*p[])(int);”, 它会告诉你:“p is array of pointer to function returning pointer to char read-only”。(cute?)

4. 数组和指针
char* p = "abcedfgh"; p[i];
编译器将会:(进行2次解引用)
1) 取得符号表中p的地址,提取存储于此处的指针;
2) 把下标所表示的偏移量与指针的值相加,产生一个地址;
3) 访问上面这个地址,取得字符
char p[] = "abcdefg"; p[i];
编译器符号表具有一个p的地址,取i的值,将它与这个地址相加,然后将相加的结果再取地址对应的值。

所以如果声明extern char* p;而原先的定义是char p[10]; 这种情形。编译器会把p当作一个指针,而且把对应位置上ascii字符解释为地址。
指针数组
保存数据的地址保存数据
间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。
如果指针有一个下标[i],就把指针的内容加上i作为地址,从中提取数据
直接访问数据,a[i]只是简单的以a+i为地址取得数据
通常用于动态数据结构通常用于存储固定数据且数据类型相同的元素
通常指向匿名数据自身即为数据名

数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码。对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。

1) 用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+i)这样的指针访问。
2)指针始终就是指针。它绝不可以改写成数组。你可以用下标形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。
3)在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为数组第一个元素的指针。
4)因此,当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义指针。不管选择哪种方法,在函数内部事实上获得都是一个孩指针。
5)在其他所有情况中,定义和声明必须匹配。如果定义了一个数组,在其他文件对它进行声明时也必须把它声明为数组,指针也是如此。

只有字符串常量才可以初始化指针数组。指针数组不能由非字符串的类型直接初始化:
int* weights[] = { {1, 2, 3, 4, 5}, {6, 7}, {8, 9, 10} }; // failed to compile
如果想初始化非指针数组,可以先创建小维的数组,然后用小维的数组进行初始化更高维度的数组。

当这样引用时:squash[i][j] 可以被声明为:
int squash[23][12];
或是
int* squash[23];
或是
int** squash;
或是
int (*squash)[12];  // 类型是int数组长度为12的指针

实参所匹配的形式参数
数组的数组 char c[8][10]char (*)[10]; 数组指针
指针数组 char *c[15];char **c; 指针的指针
数组指针(行指针) char (*c)[64]char (*)[64]; 不改变
指针的指针 char** c;char** c; 不改变
之所以能在main()函数中看到char** argv这样的参数,是因为argv是个指针数组(即char* argv[])。这个表达式被编译器改写为指向数组第一个元素的指针,也就是一个指向指针的指针。如果argv参数事实上被声明为一个数组的数组(也就是char argv[10][15]),它将被编译器改写为char (*argv)[15] (也就是一个字符数组指针),而不是char** argv。

5. 链接
查找某一个特定的符号在哪个库定义
cd /usr/lib
foreach i (lib?*)
    echo $i
    nm $i | grep $(symbol) | grep -v UNDEF
end

在动态链接和静态链接的链接语义还存在一个额外的巨大区别,它经常会迷惑不够仔细的用户。在动态链接中,所有的库符号进入输出文件的虚拟地址空间中,所有的符号对于链接在一起的所有文件都是可见的。相反,对于静态链接,在处理archive时,它只是在archive中查找载入器当时所知道的为定义的符号。
简而言之,在编译器命令行中各个静态链接库出现的顺序是非常重要的。

编译器设计者采用一种稍微灵活的方法。我们从顶部增加或拿掉盘子,但我们也可以修改位于堆栈中部的盘子的值。函数可以通过参数或全局指针访问它所调用的函数的局部变量。堆栈段有3个主要的用途,其中两个跟函数有关,另一个跟表达是计算有关。
1. 堆栈为函数内部声明的局部变量提供存储空间;
2. 进行函数调用时,堆栈存储与此有关的一些维护性信息,通常称为堆栈帧,或者过程活动记录;
3. 堆栈也可以被用作暂时存储区。譬如一些临时变量,会被压倒堆栈中,然后再取出。通过alloca()函数来分配。

6. 内存管理
堆内存的回收不必与它所分配的顺序一致(它甚至可以不回收),所以无序的malloc/free最终会产生堆碎片。堆对它的每块区域都需要密切留心,那些是已经分配了的,哪些是尚未分配的。其中一种策略就是建立一个可用块(“自由存储区”)的链表,每块由malloc分配的内存块都在自己的前面表明自己的大小。有些人用arena这个术语描述由内存分配器管理的内存块的集合。
被分配的内存总是经过对齐,以适合机器上最大尺寸的原子访问,一个malloc请求申请的内存大小为方便起见一般被圆整为2的乘方。回收的内存可供重新使用,但并没有办法把它从你的进程移出交还给操作系统。
堆的末端由一个称为break的指针来标识。当堆管理器需要更多内存时,它可以通过系统调用brk和sbrk来移动break指针。一般情况下,不必由自己显示地调用brk,如果分配的内存容量很大,brk最终会被自动调用。
你的程序可能无法同时调用malloc/brk。如果你使用malloc,malloc希望当你调用brk和sbrk时,它具有唯一的控制权。由于sbrk向进程提供了唯一的方法将数据段内存返回给系统内核,所以如果使用了malloc,就有效地防止了程序的数据段缩小的可能性。要想获得以后能够返回给系统内核的内存,可以使用mmap系统调用来映射/dev/zero文件。需要返回这种内存时,可以使用munmap系统调用。

ANSI标准第7.7.1.1节指出,在我们现在这种情况下,当信号处理程序调用任何标准库函数时(printf),程序是行为是未定义的。

7. 类型提升
一个会发生隐式类型转换的地方就是参数传递。在K&R C中,由于函数的参数也是表达式,所以也会发生类型提升。在ANSI C中,如果使用了适当的函数原型,类型提升便不会发生,否则也会发生,在被调用函数的内部,提升后的参数被裁减为原先声明的大小。
这就是为什么单个的printf格式符字串%d能使用于几个不同类型,short,char或int,而不论实际传递的是上述类型的哪一个。函数从堆栈(或寄存器中)取出的参数总是int类型,并在printf或其他被调用函数里按统一的格式处理。如果使用printf来打印比int长的类型,就可以发现这个问题。

C语言也执行这项任务,但它同时也提升比规范类型int或double更小的数据类型,即使它们类型匹配。在隐式类型转换方面,有三个重要的地方需要注意:
隐式类型转换是语言中的一种临时手段,起源于简化最初的编译器的想法。把所有操作数转换为统一的长度极大的简化了代码的生成。这样,压到堆栈中的参数都是同一长度的,所有运行时系统只需要知道参数的数目,而不需要知道它们的长度。

如果判断一个数是无符号数? 可以根据类型提升来判断
if (a < 0) { "无符号数" }
else if (-1 - a >= 0) { "无符号数" }  // 如果a是无符号数,-1和0将会被提升到无符号数,-1变成最大的无符号数,相减a肯定是个非负数
else { "有符号数“ } 

随机选取文件中的一个字符串。字符串的个数是已知的。

网上的一个实现:

#define random(x) (rand() % x) //产生x内的随机函数
#define RAND_N 1000

//自定义随机器
void my_random(char *buf1, char *buf2, int count)
{
     //判断范围
     if(random(RAND_N) < RAND_N / count)
     {
          strcpy(buf1, buf2);
     }
}

//主函数
int main()
{
     FILE *fp;
     int count = 0;
     char buf1[100], buf2[100];
     
     if ((fp = fopen("d:/test.txt", "r")) == NULL) {
          fprintf(stderr, "open error");
          exit(0);
     }
     
     if(fscanf(fp, "%s", buf1) == EOF)
     {
          printf("file is null\n");
          return 0;
     }

     count++;
     
     srand((int)time(0));//设置随机数种子,srand不能调用两次以上
     for(count++; fscanf(fp, "%s", buf2) != EOF; count++)
     { 
          my_random(buf1, buf2, count);  
     }
     
     fclose(fp);
     printf("随即读取的字符串为 : %s\n", buf1);
     
     return 0;
}


基于STM32、HAL库的W25Q01JVZEIQ TR FLASH存储器驱动应用程序设计 1Gb (128MB),分为512个可擦除块(block),每个块256KB。:块擦除约30-50ms,芯片擦除约30s。:标准SPI (支持1/2/4线模式)// 初始化CS引脚为高电平。// 擦除扇区(4KB)// 初始化Flash。/* 状态寄存器位 *//* 指令定义 *//* 超时定义 *//* 函数声明 */ 阅读详情

相关推荐

使用MLP解决OCR问题(OpenCV)(下)

分类模型:        分类模型涉及的一个比较关键的问题就是输出的10维向量是如何与具体的类别挂钩的。实际上:10维向量的每一位都代表一类,在对于训练集的表达中,如果输入数据是0,则10维向量的第一位赋值为1,其余均为0。即0对应[1,0,0,0,0,0,0,0,0,0]。MLP模型训练完成后,就需要对用户输入的数据所属类别进行判定。这时得到的输出数据基本不可能是正好的所属类为1,其他位置为0

qq_18515405的专栏 1906

01 C:穿越时空的迷雾(const关键字,算术类型的转换,以及有符号无符号类型转换常见的错误)...

1.讨论关于编程中代码移植的相关概念 不可移植的代码:   编译器定义的:由编译器设计者决定的行为,这就导致不同的编译器采取的行为不同。如:整型数右移位时,是否扩展符号位。   未确定的:C标准中未明确规定应该怎样做的行为。如:参数求值的顺序 坏代码:   未定义:在一些不正确的情况下出现时,标准未规定应该怎样做。如:有符号整数溢出是该采取何种行为。   约束条件:C标准中提出的...

weixin_30835933的博客 161

计算机组成与系统结构(第三版) 袁春风主编 课后习题答案讲解 第一、二章 计算机系统概述 数据的机器级表示

计算机组成与系统结构(第三版) 袁春风主编 课后习题答案讲解 第一、二章 计算机系统概述 数据的机器级表示

qq_73523062的博客 2089

PTA 广轻 6-5 【0715】百分制转换等级制

函数to_grade( )的功能是按照给定的百分制整数分数score计算出相应的等级,并把该等级返回。如果整数变量score不满足条件 “0 ≤ score ≤ 100”,则函数to_grade( )返回值是’ ’(即空格)。函数to_grade( )不允许从键盘读取数据,也不允许输出数据到屏幕。

splendid_rainbow的博客 520

手把手教你用示波器实测CAN总线波形:快速区分高速、低速及常见故障

本文详细介绍了如何使用示波器实测CAN总线波形,快速区分高速CAN总线和低速CAN总线,并诊断常见故障。通过实战案例和波形分析,帮助工程师掌握CAN总线信号特征,提升故障排查效率,适用于汽车电子和工业控制领域。

weixin_33217202的博客 410

人工智能——框架表示法

1975年美国明斯基在“A framework for representing knowledge”提出了框架理论。 1. 框架及框架的一般表示形式 框架:一种描述对象属性的数据结构。 框架的一般表示形式 <框架名> 槽名1: 侧面名1:值1,值2…,值p1 侧面名2:值1,值2…,值p2 侧面名2:值1,值2…,值pm1 槽名2: 侧面名...

weixin_33759269的博客 1642

关于const char*和char*、const char** 和char** 赋值问题

根据ANSI C标准的赋值约束条件:     1. 两个操作数都是指向有限定符或无限定符的相容类型的指针。     2. 左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。 一、const char*和char*     const char*的类型是:“指向一个具有const限定符的char类型的指针”。(不能修改其值)     char*的类型是:“指向一个char类型的指

baizhengbiao的专栏 2万+

Ubuntu22.04下3分钟搞定GitHub加速:SwitchHosts+小鱼工具保姆级配置指南

本文提供Ubuntu22.04下快速解决GitHub下载超时问题的保姆级教程,通过SwitchHosts图形化工具和小鱼一键换源工具实现高效加速。详细步骤包括环境准备、工具安装配置及验证方法,帮助开发者轻松优化GitHub访问速度,提升工作效率。

weixin_29258297的博客 564

C语言函数操作大全----(超详细)

fopen(打开文件) 相关函数 open,fclose 表头文件 #include 定义函数 FILE * fopen(const char * path,const char * mode); 函数说明 参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。 mode有下列几种形态字符串: r 打开只读文件,该文件必须存在。 r+ 打开可读写的文件,该

独旅天涯 6万+

别再硬编码了!Flowable工作流动态审批人配置全解析(Spring Boot集成版)

本文深入解析Flowable工作流在Spring Boot中的动态审批人配置技术,通过角色、部门等变量实现审批流程的灵活设计。文章详细介绍了架构原理、前端配置映射、动态候选组解析及查询优化方案,帮助企业提升审批流程的适应性和维护效率。

weixin_30919571的博客 135

GB9706.1-2020应用部分如何理解?

医用电气设备对应用部分的温度限制,绝缘考核,漏电流限制要求相对设备的其他部分来说都会要求比较严格。所以,划分设备的应用部分显得非常重要。现实中,医疗器械种类繁多,形状各异,比如大家熟悉的,小的如血压计,大的设备如CT。有些时候,我们应该如何根据应用部分的定义来确定ME设备的哪些部分是应用部分呢?还有GB 9706.1-2020中关于“应用部分”的定义中注2我们又该如何理解? 看过GB 9706.1-2020的朋友应该都已经注意到,相比老版也就是07版的9706.1,应用部分的定义是相对变...

喵叫兽的博客 8294

C/C++小问题大杂烩

http://cplusplus.com http://en.cppreference.com/ http://www.cprogramming.com/

鸟窝 4900

Qt + windows + Linux+QtInstallerFramework打包教程

本文介绍了使用Qt Installer Framework在Windows和Linux系统下打包Qt应用程序的完整教程。Windows部分详细说明了从下载安装框架、配置环境变量、生成release版本,到创建安装包目录结构和修改配置文件的完整流程。Linux部分则重点讲解了环境变量设置、桌面应用配置(.desktop文件)以及两种打包方案:一种使用linuxdeployqt生成AppImage文件,另一种采用类似Windows的安装包方式。教程提供了关键配置文件(config.xml、package.xml

Qt历险记,专注Qt技术,三年医疗设备研发经验,1年机器视觉研发经验,半年柔性传感研发经验。 516

<C专家编程>读书笔记

一、序        应该是每位程序员的第二本学习的C语言的书; 但是确实我第五本; 1、几个问题: 这五个问题,我只明白三个,有一个是模糊,一个是不懂,希望看完本书我能都明白; 2、为了避免在需要进行比较时误用赋值符号,最好在比较式中先写常数,如: if(3 == i) 这样,如果不小心误用了赋值符号,编译器就会发出“

录事参军 1943

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

JSTL 基本标签二<c:if> <c:choose><c:set > <c:remove><c:url>

2.判断 c:if 语法     ${s } + ${v }   页面输出的结果为true + zhangsan0  说明 1. var="" 为判断的结果  2.EL 表达式中使用 == 和 eq 是一样的结果 但是在JSTL中是没有else的如果你想使用else那么请使用"c:otherwise", 3.选择 c:choose

declare_r的专栏 1117

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

<c:choose/>、<c:when/>、<c:otherwise/>标签

<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transit...

101

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

关于别人反映<c:if> 在<c:forEach>标签在jsp里不起作用问题

<c:if> 在<c:forEach>标签在jsp里不起作用问题

不抛弃、不放弃:Aaron莫言 6239

jstl标签====核心标签<c: >

输出:  例:         pageContext.setAttribute("info","");   %>     属性存在:     属性不存在:     属性不存在:没有此内容! 设置: 主要用来将属性保存在四种范围之中,语法如下:  1=设置属性:  属性内容 2=设置对象: 例:

afdnlw的专栏 4116

JSTL <c:forEach >的使用

一、整数 , 二、计算x的平方 Value Square 三、字符串"47,52,53,55,46,22,16,2" 分隔. 四、使用步长 ...

zanetest的博客 589

<c:forTokens/>标签

<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transit...

150

<c语言编程>读书笔记

用数字1代表真, 数字0代表假, 与计算机里面的“位”的概念相关。正好是1或0; C语言的编译器默认假定函数的返回值是int 类型 数组作为函数参数时传递的是数组所在的内存位置,所以如果传递整个数组作为参数的话对数组元素的改变会影响到数组本身。 所有的全局变量的初始值都为0 ?? 局部变量默认...

chenjuzhuo7141的博客 199

<c:choose>与<c:when>的一定要配合使用

JSTL标签中的与的配合使用:      String path = request.getContextPath();      String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>     String to

Vleyong 5887

jstl中<c:if > 和<c:choose>的区别

在IE浏览器上面 <c:if test="empty list"> some thing </c:if> <c:if test=" not empty list"> some thing </c:if>不显示。<c:choose> <c:when test=""> something </c:when> <c:otherwise> some thing </c:otherwise> </c:choo

qq_21006731的博客 707

jstl中<c:forEach>的用法

在JSP的开发中,迭代是经常要使用到的操作。例如,逐行的显示查询的结果等。在早期的JSP中,通常使用Scriptlets来实现Iterator或者Enumeration对象的迭代输出。现在,通过JSTL的迭代标签可以在很大的程度上简化迭代操作。          JSTL所支持的迭代标签有两个,分别是c:forEach>和c:forTokens>。在这里介绍的是c:forEach>标签。

honey_Claire的专栏 23万+

JSTL <c:if >标签的使用

${fl.username} ============================================                                                         有效             被删除             无效                            

别在熬夜了! 1820

<c:import/>导入网络资源

<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transit...

230
上一篇: [Happy DSA] 如何对单链表进行快速排序
下一篇: 技术书籍推荐
zero_lee
博客等级 码龄21年 94粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值