在 C 中标记 phone 数字

Tokenizing a phone number in C

我正在尝试标记一个 phone 数字并将其拆分为两个数组。它以“(515) 555-5555”形式的字符串开始。我希望标记区号、前 3 位数字和后 4 位数字。我将存储在一个数组中的区号,将其他 7 位数字存储在另一个数组中。两个数组都只保存数字本身。

我的代码似乎工作...有点。问题是当我打印两个存储阵列时,我发现了一些怪癖;

  1. 我的数组 aCode; 它按照我的要求存储了前 3 位数字,但随后它也打印了一些末尾缺口的垃圾值。我在调试器中遍历了它,数组只存储了我要求它存储的内容——515。那么它为什么会打印这些垃圾值呢?给出了什么?

  2. 我的数组aNum;我可以将我需要的标记附加到它的末尾,唯一的问题是我最终在前面有一个额外的 space (这是有道理的;我正在添加到一个空数组,即添加到空 space)。我将代码修改为仅包含 7 个变量只是为了乱七八糟,我进入调试器,它告诉我数组包含并为空 space 和我需要的 6 个数字 - 最后一个没有空间.然而,当我打印它时, space 和所有 7 位数字都被打印出来了。这是怎么发生的?

我如何设置我的 strtok 函数,以便它首先复制“-”之前的 3 位数字,然后附加到我需要的最后 4 位数字?我见过的所有标记化示例都使用 while 循环,这意味着我必须选择 strcatstrcpy 来完成我的任务。我可以设置一个 "if" 语句来每次检查当前令牌的大小,但这对我来说太粗糙了,我觉得有一个更简单的方法。谢谢大家!

int main() {

    char phoneNum[]= "(515) 555-5555";
    char aCode[3];
    char aNum[7];

    char *numPtr;

    numPtr = strtok(phoneNum, " ");

    strncpy(aCode, &numPtr[1], 3);
    printf("%s\n", aCode);  

    numPtr = strtok(&phoneNum[6], "-");

    while (numPtr != NULL) {
        strcat(aNum, numPtr);
        numPtr = strtok(NULL, "-");
    }
    printf("%s", aNum);  
}

我主要看到两个错误,

  1. 作为 3 char 的数组,aCode 在这里不是空终止的。将它用作 printf()%s 格式说明符的参数会调用 undefined behaviouraNum 也有不同的方式。

  2. strcat() 期望两个参数都有一个以 null 结尾的数组。 aNum 不是空终止的,第一次使用时,也会导致 UB。总是初始化你的局部变量。

此外,请参阅其他答案以获得完整的无错误代码。

您的代码有多个问题

  1. 您为aCode分配了错误的大小,您应该为nul终止符字节加1并将整个数组初始化为'\0'以确保行结束.

    char aCode[4] = {'[=10=]'};
    
  2. 你不检查是否 strtok() returns NULL.

    numPtr = strtok(phoneNum, " ");
    strncpy(aCode, &numPtr[1], 3);
    
  3. 点 1,适用于 strcat(aNum, numPtr) 中的 aNum 这也会失败,因为 aNum 在第一次调用时尚未初始化。

  4. strtok() 的后续调用必须将 NULL 作为第一个参数,因此

    numPtr = strtok(&phoneNum[6], "-");
    

    错了,应该是

    numPtr = strtok(NULL, "-");
    

您的代码中最大的问题是未定义的行为:由于您正在将一个三字符常量读入一个三字符数组,因此您没有为空终止符留下 space。

由于您以固定长度的非常特定的格式对值进行标记,因此您可以使用 sscanf:

的非常简洁的实现
char *phoneNum = "(515) 555-5555";
char aCode[3+1];
char aNum[7+1];
sscanf(phoneNum, "(%3[0-9]) %3[0-9]-%4[0-9]", aCode, aNum, &aNum[3]);
printf("%s %s", aCode, aNum);

此解决方案将格式 (###) ###-#### 直接传递给 sscanf,并告诉函数每个值需要放置的位置。上面使用的唯一 "trick" 是为最后一个参数传递 &aNum[3],指示 sscanf 将第三段的数据放入与第二段相同的存储中,但从位置 3 开始。

Demo.

其他答案已经提到了主要问题,即aCodeaNum中space对于终止NUL字符的不足。 sscanf 的答案也是解决问题的最干净的方法,但考虑到使用 strtok 的限制,这里有一种可能的解决方案可供考虑:

char phone_number[]= "(515) 555-1234";
char area[3+1] = "";
char digits[7+1] = "";
const char *separators = " (-)";
char *p = strtok(phone_number, separators);
if (p) {
    int len = 0;
    (void) snprintf(area, sizeof(area), "%s", p);
    while (len < sizeof(digits) && (p = strtok(NULL, separators))) {
        len += snprintf(digits + len, sizeof(digits) - len, "%s", p);
    }
}
(void) printf("(%s) %s\n", area, digits);