You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取打印字符串数组:类型不匹配与段错误问题排查

问题描述

需要读取如下格式的输入:

2
string1
string2

第一行代表后续字符串的数量,且所有字符串长度相同。尝试编写代码读取并打印这些字符串,初始代码如下:

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

void print_string_array(char** a, int size){
    for (int i=0; i<size; i++){
        printf("%s\n", a[i]);
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    char* s;
    scanf("%s", s);
    int l = strlen(s);
    char input[n][l];
    strcpy(s, input[0]);
    for (int i = 1; i < n; i++) {
        scanf("%s", s);
        strcpy(s, input[i]);
    }
    print_string_array(input, n);
}

运行时出现警告和错误:

main.c: In function ‘main’:
main.c:24:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
   24 |     print_string_array(input, n);
      |                        ^~~~~
      |                        |
      |                        char (*)[(sizetype)(l)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(l)]’
    5 | void print_string_array(char** a, int size){
      |                         ~~~~~~~^

Segmentation fault (core dumped)

疑问:

  1. 为什么数组input不被识别为char**类型?
  2. 如何在保留程序适配任意长度输入字符串特性的前提下修复问题?

之后修改了代码:

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

void print_string_array(char** a, int size){
    for (int i=0; i<size; i++){
        printf("%s\n", a[i]);
    }
}

int main(){
    int n;
    scanf("%d", &n);
    char s[100]; // 足够大的缓冲区
    scanf("%s", s);
    int l = strlen(s);
    char input[n][l+1]; // +1 给 '\0' 留空间?
    strcpy(input[0], s);
    for (int i=1; i<n; i++){
        scanf("%s", input[i]);
    }
    print_string_array(input, n);
    for (int i=0; i<n; i++){
        free(input[i]);
    } 
    free(input);
}

仍存在错误和警告:

main.c: In function ‘main’:
main.c:22:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
   22 |     print_string_array(input, n);
      |                        ^~~~~
      |                        |
      |                        char (*)[(sizetype)(n)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
    5 | void print_string_array(char** a, int size){
      |                         ~~~~~~~^

Segmentation fault (core dumped)

新增疑问:

  • 针对警告,是否要把a的类型改为char (*)[(sizetype)(n)]?
  • for循环中的段错误如何解决?

问题解答

1. 为什么char input[n][l]不是char**?

char**是指向字符指针的指针,它指向一块存储多个char*的内存,每个char*又指向独立分配的字符串内存,内存结构是分散的。而char input[n][l]是二维栈数组,内存是连续的:先存input[0]的所有字符,紧接着是input[1]的所有字符,以此类推。当二维数组名传入函数时,会退化为指向一维数组的指针(即char (*)[l]类型),和char**的内存结构完全不同,因此编译器会报类型不匹配警告。

2. 修复方案

方案一:适配二维数组,修改打印函数参数

既然使用了变长二维数组(VLA),可以直接修改打印函数的参数类型,同时修正段错误的根源:

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

// 参数改为指向字符数组的指针,适配二维数组类型
void print_string_array(char (*a)[], int size){
    for (int i=0; i<size; i++){
        printf("%s\n", a[i]);
    }
}

int main(){
    int n;
    scanf("%d", &n);
    // 用栈上的固定长度数组作为缓冲区,避免野指针
    char s[100];
    scanf("%s", s);
    int l = strlen(s);
    // 字符串需要存储'\0'终止符,所以数组长度要+1
    char input[n][l+1];
    strcpy(input[0], s);
    for (int i=1; i<n; i++){
        // 直接读入二维数组的对应元素,无需中间缓冲区
        scanf("%s", input[i]);
    }
    print_string_array(input, n);
    // 注意:栈上的数组不需要手动free,之前的错误就是释放了栈内存
    return 0;
}

段错误的根源:

  • 初始版本中char* s;未初始化,是野指针,scanf("%s", s)会往随机内存写入数据,直接触发段错误;
  • 修改版本中free(input)和free(input[i])完全错误,input是栈上分配的变长数组,只有malloc/calloc分配的堆内存才需要free,释放栈内存会导致非法内存访问。

方案二:改用char**动态分配内存

如果想保留print_string_array的char**参数,可以用动态分配实现:

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

void print_string_array(char** a, int size){
    for (int i=0; i<size; i++){
        printf("%s\n", a[i]);
    }
}

int main(){
    int n;
    scanf("%d", &n);
    char s[100];
    scanf("%s", s);
    int l = strlen(s);
    // 先分配存储n个char*的指针数组
    char** input = malloc(n * sizeof(char*));
    if (!input) { // 检查内存分配是否成功
        perror("malloc failed");
        return 1;
    }
    // 为每个字符串分配内存(+1存储'\0')
    input[0] = malloc((l+1) * sizeof(char));
    strcpy(input[0], s);
    for (int i=1; i<n; i++){
        scanf("%s", s);
        input[i] = malloc((l+1) * sizeof(char));
        strcpy(input[i], s);
    }
    print_string_array(input, n);
    // 释放内存:先释放每个字符串,再释放指针数组
    for (int i=0; i<n; i++){
        free(input[i]);
    }
    free(input);
    return 0;
}

此方案中input是标准的char**类型,和打印函数参数完全匹配,无类型警告,且所有内存均为堆分配,需按顺序释放。

关于警告的补充说明

不需要把参数改成char (*)[(sizetype)(n)],因为n是运行时变量,函数声明时无法直接使用。可以用char (*a)[](指向字符数组的指针),或者在C99及以后版本中,把字符串长度作为参数传入,写成void print_string_array(int str_len, char (*a)[str_len], int size),这样类型匹配更严谨。

内容的提问来源于stack exchange,提问作者J. Schmidt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:15:52