0%

在信捷PLC编程中,LD X0LDD X0 的区别主要体现在 指令类型执行方式 上。以下是详细对比:

📌 1. LD X0(普通取指令)

  • 功能
    读取输入继电器 X0扫描周期开始时的状态(即上一个扫描周期结束时的状态)。
  • 执行特点
    • 在程序扫描周期内执行,读取的是 内部映像寄存器 的值(非实时物理输入)。
    • 响应速度较慢,适用于一般逻辑控制。
  • 应用场景
    普通开关控制、非实时性要求的逻辑。

⚡ 2. LDD X0(立即取指令)

  • 功能
    直接读取 物理输入点 X0 的实时状态,不受扫描周期影响。
  • 执行特点
    • 绕过内部映像寄存器,立即读取当前物理输入
    • 响应速度更快(一个扫描周期内可多次响应),适用于高速信号处理。
  • 应用场景
    高速计数、精确定时、脉冲捕捉等需要实时响应的场合。

📖 手册依据(附件内容)

在提供的用户手册中:

  • LD 属于基本顺控指令(第3章),定义为普通取正操作(3-2节)。
  • LDD 归类为 立即执行指令(3-6节),描述为“直接从触点上读取状态”,强调其实时性。

💡 关键区别总结

指令读取来源响应速度适用场景
LD X0内部映像寄存器较慢普通逻辑控制
LDD X0物理输入点(实时)更快高速信号、实时控制

⚠️ 注意事项

  • LDD 指令会轻微增加程序执行时间,仅在必要时使用(如高速输入)。
  • 普通输入信号(如按钮、传感器)通常用 LD 即可满足需求。

若需进一步优化高速响应,可结合手册中 高速计数功能(第5章)或 精确定时指令(第10章)使用。

本题要求实现一个函数,判断任一给定整数N是否满足条件:它是完全平方数,又至少有两位数字相同,如144、676等。

函数接口定义:

1
int IsTheNumber ( const int N );

其中N是用户传入的参数。如果N满足条件,则该函数必须返回1,否则返回0。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <math.h>
int IsTheNumber ( const int N );
int main()
{
int n1, n2, i, cnt;
scanf("%d %d", &n1, &n2);//输入两个数字,统计这两个数字之间符合要求的数字
cnt = 0;
for ( i=n1; i<=n2; i++ ) {
if ( IsTheNumber(i) )
cnt++;
}
printf("cnt = %d\n", cnt);
return 0;
}
/* 你的代码将被嵌在这里 */
int IsTheNumber ( const int N )
{
    int n = N;
    int perfect_square = 0;//是否是完全平方数
    int same = 0;//是否有2个数字相同
    //先看看这个数是不是完全平方数
    for (int i = 0; i*i <= n; i++)
    {
        if ( i * i == N)
        {
            perfect_square = 1;
            break;
        }
    }
    //得到数字的长度,看看是几位数
    int length = 0;//数字的长度
    while (n > 0)
    {
        length++;
        n = n / 10;
    }
    n = N;
    int input[5];//这个字符串用来存储输入的数字,因为输入是int型,5位已经足够
    for (int i = 0; i < length; i++)
    {
        int temp = n % 10;//得到这个数字的个位
        input[i] = temp;
        n = n / 10;//把这个数字的个位去掉
    }
    //判断这个数字是否有2个相同数字
    if (input[0]==input[1]||input[0]==input[2]||input[0]==input[3]||input[0]==input[4]||
        input[1]==input[2]||input[1]==input[3]||input[1]==input[4]||
        input[2]==input[3]||input[2]==input[4]||
        input[3]==input[4])
    {
        same = 1;
    }
   //如果两个都符合,返回1,否则返回0
    if (same == 1 && perfect_square == 1)
    {
        return 1;
    }else{
        return 0;
    }
}

改进的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int IsTheNumber ( const int N )
{
int n = N;
// 判断是否完全平方数 (优化版)
int root = (int)sqrt(N);
if(root * root != N)
return 0;

// 数字频率统计
int digitCount[10] = {0}; // 0-9的数字计数器
while(n > 0) {
int digit = n % 10;
digitCount[digit]++;
if(digitCount[digit] >= 2)
return 1; // 发现重复立即返回
n /= 10;
}
return 0;
}
1
2
3
int root = (int)sqrt(N);
if(root * root != N)
return 0;
  • 裁判程序已经有math.h了,所以应该使用 sqrt() 计算平方根整数部分
  • 检查 root*root == N 替代低效的循环
1
digitCount[digit]++;

当出现对应数字时,把这个数字的计数器直接加1,可以避免我的代码中复杂的判断逻辑。

1
2
if(digitCount[digit] >= 2) 
return 1; // 发现重复立即返回

当一个数字已经出现2次了,后面的就不用管了,已经符合条件了。

链表
本题要求实现一个函数,求单链表L结点的阶乘和。这里默认所有结点的值非负,且题目保证结果在int范围内。

函数接口定义:

1
int FactorialSum( List L );

其中单链表List的定义如下:

1
2
3
4
5
6
typedef struct Node *PtrToNode;
struct Node {
int Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <stdlib.h>
typedef struct Node *PtrToNode;//这句的意思是把指向Node这个结构体的指针起名叫PtrToNode
struct Node {
    int Data; /* 存储结点数据 */
    PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
int FactorialSum( List L );
int main()
{
    int N, i;
    List L, p;
    scanf("%d", &N);
    L = NULL;//这是表头指针L,初始时为NULL表明链表为空
    for ( i=0; i<N; i++ ) {
        p = (List)malloc(sizeof(struct Node));
        scanf("%d", &p->Data);
        p->Next = L;  L = p;
    }
    printf("%d\n", FactorialSum(L));
    return 0;
}
/* 你的代码将被嵌在这里 */
int Factorial(int n)//求阶乘
{
    if( n == 0 || n == 1 )
    {
        return 1;
    }else{
        int sum = 1;
        for (int i = 1; i <= n; i++)
        {
            sum = sum * i;
        }
        return sum;
    }
}
int FactorialSum( List L )
{
    int sum = 0;
    int temp = 0;//暂时存一下一个数字的阶乘
    while (L != NULL)
    {
        temp = Factorial(L->Data);//得到这一次循环的阶乘
        sum = sum + temp;
        L = L->Next;
    }
    return sum;
}

1
typedef struct Node *PtrToNode;
  • 定义一个新的类型别名:PtrToNode 是指向 struct Node 结构体的指针类型。
  • 后续可以直接使用 PtrToNode p; 来声明一个指向结构体的指针变量。

1
typedef PtrToNode List; /* 定义单链表类型 */
  • 再次使用 typedef,把 PtrToNode 类型(也就是指向结构体的指针)起个别名叫 List
  • 这样我们就可以直接写 List L; 来表示一个链表头指针。

1
p = (List)malloc(sizeof(struct Node)); 
  • 使用 malloc() 动态分配一个 struct Node 大小的内存空间,并将返回的指针强制转换为 List 类型,赋值给 p
  • 这就创建了一个新的链表节点。

1
p->Next = L; L = p; 
  • 将新节点插入到链表头部: - p->Next = L;:让新节点的 Next 指向原来的第一个节点;
  • L = p;:更新链表头指针 L,让它指向新插入的节点。
  • 这样做每次插入都在链表头部,形成的是逆序链表(后面输入的节点在前面)。

while (L != NULL)

只要节点存在(即指针不是 NULL),就继续处理。
这里不能写成while (L->Data != NULL),因为:

  • L->Data 是一个 int 类型,而不是指针类型。
  • NULL 是一个空指针常量(通常是 (void*)0),不能用来判断 int 是否为空。
  • 所以这个判断条件是语法错误 + 逻辑错误

逻辑结构上相邻的数据,在实际存储时,这些数据所在的内存地址并不连续,而是随机分布在内存中的各个位置,这种存储模式就是链式存储,所生成的表就是链表。

为了保持数据之间的关系,每个数据在存储时配有一个指针,指向它后面的元素,这样,数据的顺序就由指针联系起来了。

链表中每个元素由两部分构成,一是其本身存储的信息,二是指向后续的指针。

参考:【动画演示】链表详解及其底层机制 C语言

一个采购员去银行兑换一张y元f分的支票,结果出纳员错给了f元y分。采购员用去了n分之后才发觉有错,于是清点了余额尚有2y元2f分,问该支票面额是多少?

输入格式:

输入在一行中给出小于100的正整数n。

输出格式:

在一行中按格式y.f输出该支票的原始面额。如果无解,则输出No Solution

分析:

  • 采购员实际得到的金额:100f + y 分。
  • 采购员用去了 n 分,所以剩下的金额是 100f + y - n 分。
  • 剩下的金额应该等于 200y + 2f 分。
  • 这个问题的方程表示为:98f−199y=n

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
int main()
{
    int y = 0;
    int f = 0;
    int n = 0;
    int found = 0;//找到解标志
    scanf("%d",&n);
    for (f=1; f<100; f++)
    {
        for (y=0; y<=99; y++)
        {
            if (98*f-199*y==n)
            {
                found = 1;
                break;//找到了解,退出内层循环
            }
        }
        if (found)//退出外层循环
        {
            break;
        }
    }
    if (found)
    {
        printf("%d.%d",y,f);//打印
    }else
    {
        printf("No Solution");//没有解
    }
}

根据下面关系式,求圆周率的值,直到最后一项的值小于给定阈值。
π2=1+13+2!3×5+3!3×5×7++n!3×5×7××(2n+1)+

输入格式:

输入在一行中给出小于1的阈值。

输出格式:

在一行中输出满足阈值条件的近似圆周率,输出到小数点后6位。

输入样例:

1
0.01

输出样例:

1
3.132157

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
double factorial(int n);//计算阶乘
int main()
{
    float threshold = 0;//阈值
    float input = 0;//输入
    float sum = 0;//结果
    float numerator = 0;//分子
    float denominator = 1;//分母
    scanf("%f",&input);
    int i = 1;
    do {
        int x = 1;
        int j = 1;//计算分母循环用
        for (j = 1; j<=i;j++)//计算分母
        {
            denominator = denominator * x;
            x = x + 2;
        }
        numerator = factorial(i-1);//计算分子
        threshold = numerator/denominator;//计算阈值(当前的最后一项)
        sum = sum + threshold;//计算和
        i++;
        denominator = 1;
    } while (threshold > input);
    sum = sum * 2;
    printf("%.6f",sum);
}
double factorial(int n)//计算阶乘
{
    double result = 1;
    int i = 0;
    for (i = 1; i <= n; i++)
    {
        result = result * i;
    }
    return result;
}

《C程序设计语言》练习4-2
对atof函数进行扩充,使它可以处理形如
123.45e-6
的科学表示法,其中,浮点数后面可能会紧跟一个e或E以及一个指数(可能有正负号)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
double atof(char s[])
{
    double val,power;
    int i,sign;
    for (i=0; isspace(s[i]); i++)
    {
        ;//去除数字前边的空格
    }
    sign = (s[i] == '-') ? -1 : 1;//把这个数字前边的符号保存在sign里
    if (s[i] == '+' || s[i] == '-')
    {
        i++;//跳过符号位
    }
    for (val = 0.0; isdigit(s[i]); i++)
    {
        val = 10.0* val + (s[i] - '0');//得到小数点前边的数字
    }
    if (s[i] == '.')
    {
        i++;//跳过小数点
    }
    for (power = 1.0; isdigit(s[i]); i++)
    {
        val = 10.0 * val + (s[i] - '0');//得到小数点后边的数字,一并放在val中
        power *= 10.0;//之后要除掉的倍数,因为之前多乘了。
    }
    return sign * val / power;//返回符号*值/小数点后位数
}

思路

  1. 提供的atof函数已经可以处理e之前的部分,需增加对e后部分的处理。
  2. 跳过e符号,获得符号位Esign,最后得到指数j。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <ctype.h>
#include <math.h>
double atof(char s[]);
int main() {
    char s[] = "3.1415E10";
    double ret = atof(s);
    return 0;
}
double atof(char s[])
{
    double val,power;
    int i,sign;
    int Esign = 0,j = 0;
    for (i=0; isspace(s[i]); i++)
    {
        ;
    }
    sign = (s[i] == '-') ? -1 : 1;
    if (s[i] == '+' || s[i] == '-')
    {
        i++;
    }
    for (val = 0.0; isdigit(s[i]); i++)
    {
        val = 10.0* val + (s[i] - '0');
    }
    if (s[i] == '.')
    {
        i++;
    }
    for (power = 1.0; isdigit(s[i]); i++)
    {
        val = 10.0 * val + (s[i] - '0');
        power *= 10.0;
    }
    if (s[i] == 'e' || s[i] == 'E')//处理科学计数法
    {
        i++;//跳过e
        Esign = (s[i] == '-') ? -1 : 1;//获得符号位
        if (s[i] == '+' || s[i] == '-')
        {
            i++;//跳过符号
        }
        for (j=0; isdigit(s[i]); i++)
        {
            j = 10 * j + (s[i] - '0');//获得指数
        }
    }
    return sign * val / power * pow(10, Esign*j);
}

《C程序设计语言》练习4-1
编写函数strrindex(s,t),它返回字符串t在s中最右边出现的位置。如果s中不包含t,则返回-1。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
#include <string.h>
int strrindex(char s[],char t[]);
int main()
{
    char s[] = "abqqqcdqqefqgqhijkqqqqlmnopqqqqrsqqqqtqrqrqrscsdaadzcqraaaaqqqqqr";
    char t[] = "qr";
    int Locate = strrindex(s,t);
    return 0;
}
int strrindex(char s[],char t[])
{
    int i = 0;
    int ret = -1;
    int tLenth = strlen(t);//字符串t的长度
    for (i = 0; s[i] != '\0'; i++)
    {
        if (s[i] == t[0])//s[i]和字符串t的首元素相等了
        {
            int j = 0;
            for (j = 0; j < tLenth; j++)
            {
                static int Count = 0;//记录元素相等的个数,和t的长度相等时,代表找到了
                if (s[i+j] == t[j])//其他元素也相等
                {
                    Count++;
                    if (Count == tLenth)//记录的相等个数和t的长度相等
                    {
                        ret = i;
                        Count = 0;//记录清零,为了后面查找准备
                    }
                }
                else//出现了不相等的元素
                {
                    Count = 0;//记录清零
                    break;
                }
            }
        }
    }
    return ret;
}

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string.h>
int strrindex(char s[], char t[]);
int main()
{
    char s[] = "abqqqcdqqefqgqhijkqqqqlmnopqqqqrsqqqqtqrqrqrscsdaadzcqraaaaqqqqqr";
    char t[] = "qraaa";
    int Locate = strrindex(s, t);
    return 0;
}
int strrindex(char s[], char t[])
{
    int sLength = strlen(s);
    int tLength = strlen(t);
    int i, j
    for (i = sLength - tLength; i >= 0; i--) //从后往前找
    {
        for (j = 0; j < tLength; j++)
        {
            if (s[i + j] != t[j]) //不匹配的时候
            {
                break;
            }
        }
        if (j == tLength) //找到了
        {
            return i;  // 找到最后一次出现的位置
        }
    }
    return -1// 如果未找到
}

《C程序设计语言》练习3-5
编写函数itob(n,s,b),将整数n转换为以b为底的数,并将转换结果以字符的形式保存到字符串s中,例如,itob(n,s,16)把整数n格式化为十六进制整数保存在s中。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <string.h>
void itob(int n,char s[],int b);
void Reverse(char R[]);
int main()
{
    int n = 3770;
    char s[100] = {0};
    int b = 16;
    itob(n,s,b);
    return 0;
}
void itob(int n,char s[],int b)
{
    int i = 0;
    for (i=0; n != 0; i++)
    {
        int j = n % b;
        if (j<10)//小于十进制的时候,用数字就够了
        {
            s[i] = j+'0';
            n = n / b;
        }
        else if (j<16)//适用于16进制时,还要用到字母
        {
            s[i] = j+'a'-10;
            n = n / b;
        }
    }
    Reverse(s);//翻转字符串
}
void Reverse(char R[])
{
    int c,i,j;
    for (i=0,j=strlen(R)-1; i<j; i++,j--)
    {
        c = R[i];
        R[i] = R[j];
        R[j] = c;
    }
}

《C程序设计语言》练习3-3
编写函数expand(s1,s2),将字符串s1中类似于a-z一类的速记符号在字符串s2扩展为等价的完整列表abc…xyz。该函数可以处理大小写字母和数字,并且可以处理a-b-c、a-z0-9与-a-z等类似的情况。作为前导和尾随的-字符原样排印。

处理a-z这种只有中间带有一个’-‘号这种最简单的情况:

思路:

  1. 先定位到’-‘号
  2. 分别找到符号左边和右边的字符
  3. 利用大小写字母和数字在ASCII码表中是有顺序这一特点,设置一个循环。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
void expand(char s1[],char s2[]);
int main()
{
    char s1[] = "A-Z";
    char s2[100] = {0};
    expand(s1, s2);
    return 0;
}
void expand(char s1[],char s2[])
{
    int Locate = 0;//'-'号的位置
    for (Locate=0; s1[Locate] != '\0'; Locate++)
    {
        if (s1[Locate] == '-')//找到了'-'号
        {
            char Left = s1[Locate-1];//减号左边的字符
            char Right = s1[Locate+1];//减号右边的字符
            for (int i = 0; Right - Left >= 0; i++)
            {
            //让s2[i]这个字符一直等于Left,知道Right和Left相等。
                s2[i] = Left;
                Left = Left + 1;
            }
        }
    }
}

处理a-b-c 这种带有多个’-‘号的情况

思路:在之前代码的前提下,即使最内层的for循环结束,也要记录i的值,便于下次再找到’-‘时接着上次的位置赋值给s2。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
void expand(char s1[],char s2[]);
int main()
{
    char s1[] = "A-D-G-K";
    char s2[100] = {0};
    expand(s1, s2);
    return 0;
}
void expand(char s1[],char s2[])
{
    int Locate = 0;//'-'号的位置
    for (Locate=0; s1[Locate] != '\0'; Locate++)
    {
        if (s1[Locate] == '-')//找到了'-'号
        {
            int i = 0;
            static int j = 0;//记录s2字符串已经被写入的位置
            char Left = s1[Locate-1];
            char Right = s1[Locate+1];
            for (i = j; Right - Left >= 0; )
            {
                if (s2[i-1] == Left)//如果是相等的,就跳过这次对s2的写入
                {
                    Left = Left + 1;
                }
                else
                {
                    s2[i] = Left;
                    Left = Left + 1;
                    j++;
                    i++;
                }
            }
        }
    }
}

经过测试,这段代码也解决了a-z0-9的问题。

处理-a-z这种情况

思路:

  1. 对于这种情况,需要忽略最前面的’-‘号
  2. 加入判断’-‘位置的功能

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
void expand(char s1[],char s2[]);
int main()
{
    char s1[] = "-a-z";
    char s2[100] = {0};
    expand(s1, s2);
    return 0;
}
void expand(char s1[],char s2[])
{
    int Locate = 0;//'-'号的位置
    for (Locate=0; s1[Locate] != '\0'; Locate++)
    {
        if (s1[Locate] == '-' && Locate != 0)//找到了'-'号,并且这个'-'号不在数组最前面。
        {
            int i = 0;
            static int j = 0;
            char Left = s1[Locate-1];
            char Right = s1[Locate+1];
            for (i = j; Right - Left >= 0; )
            {
                if (s2[i-1] == Left)
                {
                    Left = Left + 1;
                }
                else
                {
                    s2[i] = Left;
                    Left = Left + 1;
                    j++;
                    i++;
                }
            }
        }
    }
}