重置指向字符数组的指针

3
我正在通过UART从树莓派发送5个字节的数据,并通过dsPIC30F微控制器接收它们。我能够正确地接收数据并将MAXCNT寄存器设置为所需值。但是问题出现在我尝试发送第二个值时。在第一次数据读取后,newResBuffer[]中的值不会改变。
对于指针/数组,我是初学者,但我怀疑我的问题可能在于重置指针的方法。我已经尝试过许多不同的方法,但没有成功。请问我的步骤是否正确?
#include <string.h>

char newResBuffer[10];
char *nR = newResBuffer;
char *nRreset = NULL;
char rxRead = 0;
int newRes = 0;
int newResFlag = 0;
int j = 0;

int main(void)
{
  nRreset = nR;    // set reset point at the beginning of newResBuffer[]

  while(1)
  {
    if(U1STAbits.URXDA)  // check if there is data available
    {
      rxRead = U1RXREG & 0xFF;  //read data from UART receive register
      *nR = rxRead;    //store data to first byte of newResBuffer[]
      nR++;            // increment pointer
      j++;

      if(j > 4)
      {
        *nR = '\0';        // null terminate the string
        newResFlag = 1;    // set the flag that new value is ready to be set
        j = 0;             // reset count variable

      }//if(j>4)

    }//if(U1STAbits.URXDA)

    if(newResFlag)         // has flag been set?
    {
      sscanf(newResBuffer, "%d", &newRes);    // convert string received to an int
      MAXCNT = (newRes * 2) - 1;   // set MAXCNT register to new value
      nR = nRreset;                // reset pointer to start of newResBuffer[]
      newResFlag = 0;              // reset flag

    }//if(newResFlag)
  }//while(1)

return 0;
}//main()

我用诊断LED做了一些测试,发现newResBuffer[]始终会被重置为我发送的第一个值。即使我尝试在设置新的MAXCNT值后重新初始化数组为所有0,也无济于事。


不确定 sscanf(newResBuffer, "%d", &newRes); 是否按照您的预期执行,并且您有一个无限的 while 循环。 - sjsam
我本来想要一个无限循环的while循环。至于sscanf()函数,我希望能够将字符字符串(例如newResBuffer = {'1','2','3','4','5','\0'})转换为整数(例如12345)。这样做是错误的吗? - cjswish
1
显示变量的声明。目前您正在从newResBuffer而非nR-4进行sccanf - gudok
@gudok 我改成了 sscanf(nR-5, "%d", &newRes) ... 但仍然无法正常工作。 - cjswish
这个赋值语句 nR = nRreset; 使得 nR 指向了 NULL。这意味着当读取第二个值的第一个字节时,您正在对 NULL 指针进行解引用。我想你的意思是 nr = newResBuffer - gudok
main()函数的第一行是nRreset = nR,所以当我到达nR = nRreset这一行时,它会将其设置回新的ResBuffer。 - cjswish
1个回答

1
您重置指针的方法是正确的,尽管有一些更简单的方法可以实现。我假设您的错误与设置MAXCNT寄存器或从接收寄存器读取新数据有关。我对树莓派微控制器了解不够,无法帮助您解决问题。但也许在更新MAXCNT寄存器之前,您需要刷新或清除它?
我通过将树莓派特定的寄存器用于从stdin读取和打印到stdout的标准C函数来测试了您的代码。很容易测试并查看涉及接收单个字符数字、将其存储在字符串缓冲区中、将该缓冲区转换为int并重复使用缓冲区的代码部分都是正确的。这里是我的代码,显示了正确读取值的信息,并确认了缓冲区地址的增加和重置是正确的:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

char newResBuffer[10];
char *nR = newResBuffer;
char *nRreset = NULL;
char rxRead = 0;
int newRes = 0;
int newResFlag = 0;
int j = 0;

int main(void)
{
    nRreset = nR;

    /* Printing out initial memory addresses */
    printf("newResBuffer address: %p\n", (void *) newResBuffer);
    printf("Initial nRreset address: %p\n", (void *) nRreset);
    printf("Initial nR address: %p\n\n", (void *) nR);

    while(1)
    {
        /* Using rand() % 2 to simulate data availability */
        if(rand() % 2)
        {
            /* Using getc() instead of the register to read individual digits */
            rxRead = getc(stdin);
            printf("rxRead: %c saved to nR address %p\n", rxRead, (void *) nR);
            *nR = rxRead;
            nR++;
            j++;

            if(j > 4)
            {
                *nR = '\0';
                newResFlag = 1;
                j = 0;
            }
        }

        if(newResFlag)
        {
            sscanf(newResBuffer, "%d", &newRes);
            /* Printing newRes and MAXCNT instead of setting the register */
            printf("newRes: %d\n", newRes);
            printf("MAXCNT: %d\n", (newRes * 2) - 1);
            printf("nR address before reset: %p\n", (void *) nR);
            nR = nRreset;
            printf("nR address after reset: %p\n\n", (void *) nR);
            newResFlag = 0;
        }
    }

    return 0;
}

测试输入7594819432的输出结果是:

newResBuffer地址: 0x10779f060
初始nRreset地址: 0x10779f060
初始nR地址: 0x10779f060

rxRead: 7保存到nR地址0x10779f060
rxRead: 5保存到nR地址0x10779f061
rxRead: 9保存到nR地址0x10779f062
rxRead: 4保存到nR地址0x10779f063
rxRead: 8保存到nR地址0x10779f064
newRes: 75948
MAXCNT: 151895
重置前nR地址: 0x10779f065
重置后nR地址: 0x10779f060

rxRead: 1保存到nR地址0x10779f060
rxRead: 9保存到nR地址0x10779f061
rxRead: 4保存到nR地址0x10779f062
rxRead: 3保存到nR地址0x10779f063
rxRead: 2保存到nR地址0x10779f064
newRes: 19432
MAXCNT: 38863
重置前nR地址: 0x10779f065
重置后nR地址: 0x10779f060

我之前提到过有一些更简单的方法可以重置指针。实际上,你可以不使用nRreset来完成它;由于newResBuffer的基地址永远不会改变,因此你可以通过nR = newResBuffer来简单地重置它。
甚至更简单的方法是根本不使用移动指针,而是直接使用你代码中已经拥有的变量j来索引newResBuffer
你也可以使用atoi()或者strtol()来代替sscanf()将字符串缓冲区转换为int(或者long)。
以下是一个更简单的代码版本,它实现了相同的功能:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
    char newResBuffer[10];
    char rxRead = 0;
    int newRes = 0;
    int newResFlag = 0;
    int j = 0;

    while (1) {
        /* if (U1STAbits.URXDA) { */
        if (rand() % 2) {
            /* rxRead = U1RXREG & 0xFF; */
            rxRead = getc(stdin);
            newResBuffer[j++] = rxRead;

            if (j > 4) {
                newResBuffer[j] = '\0';
                newResFlag = 1;
                j = 0;
            }
        }

        if (newResFlag) {
            newRes = atoi(newResBuffer);
            /* MAXCNT = (newRes * 2) - 1; */
            printf("newRes: %d\n", newRes);
            printf("MAXCNT: %d\n", (newRes * 2) - 1);
            newResFlag = 0;
        }
    }

    return 0;
}

感谢您详细的回复。我完全取消了使用指针,只是用计数器变量j引用了数组位置。看起来我的原始代码按照预期工作(在我的微控制器代码中找到了另一个错误,接收缓冲区获取了1个字节过多的数据,而我从未清除溢出错误标志),但我感觉我的更新后的代码现在更加流畅。谢谢! - cjswish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接