【问题标题】:Why am I getting UB when printing a 2D array of char types in C?为什么在 C 中打印 char 类型的二维数组时会得到 UB?
【发布时间】:2017-12-05 10:42:18
【问题描述】:

我只是尝试使用指针打印一串字符,但输出不正确。有人能告诉我为什么吗?方法 display_chunks() 用于打印数组中除第一个字符之外的每个字符串。但是,尽管我在打印字符串中的最后一个字符后递增指针变量,但似乎打印同一行。

#include <stdio.h>
#include <string.h>

//macros: constants
#define CHUNK_LENGTH (20+1)  //each chunk has twenty characters, we add 1 so
                           //there is space for the null terminator.
#define NUMBER_OF_CHUNKS 4 //the message is spread across 4 chunks.
void display_chunks();

char chunks[NUMBER_OF_CHUNKS][CHUNK_LENGTH];

int main(){
strcpy(chunks[0], "2i1%fsi%fs%jstwrtzx%");
strcpy(chunks[1], "1'H%nx%vznwp~1%kqf|j");
strcpy(chunks[2], "4R3%Wnyhmnj%%%%%%%%%");
strcpy(chunks[3], "3xzhhjxx3'%2%Ijssnx%");
    display_chunks();
}

void display_chunks() {
    int i, j;
    char *arr = chunks[0];
    for(i = 0; i < NUMBER_OF_CHUNKS; i++){
        for(j = 1; j < CHUNK_LENGTH-1; j++){
            printf("%c", *(arr+j));
        }
        ++arr;
        printf("\n");
    }
}

这是我的输出:

i1%fsi%fs%jstwrtzx%
1%fsi%fs%jstwrtzx%
%fsi%fs%jstwrtzx% 1
fsi%fs%jstwrtzx% 1'

根据克雷格的回答编辑;我似乎不明白指针和双指针之间的区别。我之前尝试的是递增 arr 因为我认为它会指向块中的下一个数组。看起来我错了,我花了一段时间才弄清楚。

抱歉,C 新手:)

【问题讨论】:

  • 阅读minimal reproducible example。提供一个工作示例。缺少定义。
  • 什么是chunks声明?
  • 返回并再次阅读minimal reproducible example。再次编辑。什么是chunksNUMBER_OF_CHUNKSCHUNK_LENGTH。做一个工作的例子。
  • 这仍然无法编译,但是如果您在调用函数之前将 strcpy 行移到 main 中,它将给出您所说的输出。真的,制作可以编译的东西然后将其粘贴到问题中有多难?
  • 您的代码按照所写的完全符合预期的方式运行。它的行为没有什么异常。但是您声称“输出不正确”。我们怎么知道你认为这里“不正确”的地方?你期望什么输出?你必须在你的问题中解释这一点。

标签: c arrays string multidimensional-array char


【解决方案1】:

你有两个问题。

j 的 for 循环从 1 开始,而不是 0

而且,arr 始终是 chunks[0] 而不是 chunks[i]

这是更正后的代码:

strcpy(chunks[0], "2i1%fsi%fs%jstwrtzx%");
strcpy(chunks[1], "1'H%nx%vznwp~1%kqf|j");
strcpy(chunks[2], "4R3%Wnyhmnj%%%%%%%%%");
strcpy(chunks[3], "3xzhhjxx3'%2%Ijssnx%");

void display_chunks() {
    int i, j;
    for(i = 0; i < NUMBER_OF_CHUNKS; i++){
        char *arr = chunks[i];
        for(j = 0; j < CHUNK_LENGTH-1; j++){
            printf("%c", *(arr+j));
        }
        printf("\n");
    }
}

更新:

根据您的原始代码 [没有 显示 chunks 的声明],arr = chunks[i] 的使用是必要的,因为其中任一个可能已经使用:

char *chunks[NUMBER_OF_CHUNKS];
char chunks[NUMBER_OF_CHUNKS][CHUNK_LENGTH];

既然知道使用后者,那么您的原始代码的变体可能会使用arr 的增量:

strcpy(chunks[0], "2i1%fsi%fs%jstwrtzx%");
strcpy(chunks[1], "1'H%nx%vznwp~1%kqf|j");
strcpy(chunks[2], "4R3%Wnyhmnj%%%%%%%%%");
strcpy(chunks[3], "3xzhhjxx3'%2%Ijssnx%");

void display_chunks() {
    int i, j;
    char *arr = chunks[0];
    for(i = 0; i < NUMBER_OF_CHUNKS; i++){
        for(j = 0; j < CHUNK_LENGTH-1; j++){
            printf("%c", arr[j]));
        }
        arr += CHUNK_LENGTH;
        printf("\n");
    }
}

样式清理可能是:

strcpy(chunks[0], "2i1%fsi%fs%jstwrtzx%");
strcpy(chunks[1], "1'H%nx%vznwp~1%kqf|j");
strcpy(chunks[2], "4R3%Wnyhmnj%%%%%%%%%");
strcpy(chunks[3], "3xzhhjxx3'%2%Ijssnx%");

void display_chunks() {
    int i, j;
    char *arr = chunks[0];
    for(i = 0; i < NUMBER_OF_CHUNKS; i++, arr += CHUNK_LENGTH){
        for(j = 0; j < CHUNK_LENGTH-1; j++){
            printf("%c", arr[j]));
        }
        printf("\n");
    }
}

【讨论】:

  • 假设chunks 的定义是合理的,也许。
  • 在这种情况下重要吗? arr 是一个指针,通过递增它,它应该指向下一个字符数组。我说的对吗?
  • @MarkTolonen 或多或少。 OP 的原始行为是沿着chunks[0] 爬行并跳过第一个字符,所以它有点理智
  • 不,仅仅增加arr 是不正确的,因为它是char * 而不是char **
  • @N Tesfai:不,你不是。您的arr 是指向char 的指针。因此,当您增加它时,它指向下一个 char,而不是您错误地认为的“指向下一个字符数组”。
【解决方案2】:

要增加arr 以指向下一个字符数组,它必须是正确的类型,即char (*arr)[CHUNK_LENGTH]

#include <stdio.h>
#include <string.h>

//macros: constants
#define CHUNK_LENGTH (20+1)  //each chunk has twenty characters, we add 1 so
//there is space for the null terminator.
#define NUMBER_OF_CHUNKS 4 //the message is spread across 4 chunks.
void display_chunks();

char chunks[NUMBER_OF_CHUNKS][CHUNK_LENGTH];

int main() {
    strcpy(chunks[0], "2i1%fsi%fs%jstwrtzx%");
    strcpy(chunks[1], "1'H%nx%vznwp~1%kqf|j");
    strcpy(chunks[2], "4R3%Wnyhmnj%%%%%%%%%");
    strcpy(chunks[3], "3xzhhjxx3'%2%Ijssnx%");
    display_chunks();
}

void display_chunks() {
    int i;
    char (*arr)[CHUNK_LENGTH] = chunks;
    for(i = 0; i < NUMBER_OF_CHUNKS; i++)
    {
        printf("%s\n", *arr);
        ++arr;
    }
}

【讨论】:

  • 不幸的是,有时 UB 仍然有效……可变参数函数的危险。
【解决方案3】:

这是 Craig 使用%s 的答案的变体:

void display_chunks() {
    int i;
    for(i = 0; i < NUMBER_OF_CHUNKS; i++){
        char *arr = chunks[i];
        printf("%s\n", arr);
    }
}

并从第二个字符开始打印:

void display_chunks() {
    int i;
    for(i = 0; i < NUMBER_OF_CHUNKS; i++){
        char *arr = chunks[i];
        arr++;
        printf("%s\n", arr);
    }
}

https://repl.it/JKHB

【讨论】:

    猜你喜欢
    • 2020-10-10
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    相关资源
    最近更新 更多