96760
  
  
スペース区切りの整数の配列を読み込むコードを書きたいのですが、  
Segmentation fault (core dumped)  
というエラーになります。  
以下のコードです。(nの入力の部分は省略していますが、  
これは正しく行われていることを確認しています。)

[code]

    void input_iarray(char* s,int* a,int n,int imax);
    #include<stdio.h>
    #include<stdlib.h>
    #define N 1000000100
    int main(void){
        char* s=(char*)malloc(sizeof(char)*N);
        fgets(s,N,stdin);
    // nの入力
        int* a=(int*)malloc(sizeof(int)*n);
        input_iarray(s,a,n,sizeof(char)*N);
        return 0;
    }
    void input_iarray(char* s,int* a,int n,int imax){
        int aidx=0,i=0; 
        while(*(s+i)!=0 && i<imax){
            if (*(s+i)<48 || *(s+i)>57){i++;}
            else{
                int bidx=i;
                while(*(s+i)>=48 && *(s+i)<=57){
                    i++;
                }
                int t=0;
                for(int j=bidx;j<i;j++){
                    t*=10;
                    t+=*(s+j)-48;
                }
            *(a+aidx++)=t;
            }
        }
        if (aidx!=n)printf("n!=aidx\n");
    }
    
[/code]


CC BY-SA 4.0
2023-11-10T13:55:44.610
96740
2023-11-12T06:35:17.237
2023-11-10T14:24:54.860
3060
54984
question
c
配列読み込みのためのコードを書いたのですが、エラーになります。


`input_iarray()`関数は文字列`s`に入ってる数字とその個数を数え、数字を`a`に、個数を`aidx`に記録し、`aidx`と`n`を比べる関数ですね。一応コメント等を読んでコードを次のように書き直してみました。

[code]

    void input_iarray(char* s,int* a,int n,int imax);
    #pragma warning(disable:4996) // scanf()を使うため
    #include <stdio.h>
    #include <stdlib.h>
    #define N 1000000100
    int main()
    {
        char* s=(char*)malloc(sizeof(char)*N);
        if(!s)return -1; // sの例外処理
        fgets(s,N,stdin);
        int n;
        scanf("%d",&n); // nの入力
        int* a=(int*)malloc(sizeof(int)*n);
        if(!a) // aの例外処理
        {
            free(s);
            return -1;
        }
        input_iarray(s,a,n,N);
        free(s),free(a);
        return 0;
    }
    void input_iarray(char* s,int* a,int n,int imax){
        int aidx=0,i=0; 
        while(*(s+i)!=0 && i<imax){
            if (*(s+i)<48 || *(s+i)>57){i++;}
            else{ // 数字
                int bidx=i;
                while(*(s+i)>=48 && *(s+i)<=57){
                    i++;
                }
                int t=0;
                for(int j=bidx;j<i;j++){
                    t*=10;
                    t+=*(s+j)-48;
                }
            *(a+aidx++)=t;
            }
        }
        if (aidx!=n)printf("n!=aidx\n");
    }
    
[/code]

いまのエラー`Segmentation fault (core dumped)`は、配列等の範囲外の部分へのアクセスをするとき発生します。

たとえ、入力が`s="---555-23-4--12---44-"`, `n=3`のときは、  
`a`は大きさ`sizeof(int)*3`のメモリしか確保してないのに  
関数`input_iarray()`が`555, 23, 4, 12, 44`をそれぞれ`a[0], a[1], a[2], a[3],
a[4]`にアクセスして記録しようとします。  
`aidx`が`3`になって`a+aidx`にアクセスするとき問題になります。

したがって、`sに入ってる数字の個数 > n`のときそのエラーが出ると思います。  
`a`に`s`のすべての数字を記録しなくてもいいなら`input_iarray()`の`else{}`を次のように改変するとエラーが出ないと思います。

[code]

    else{ // 数字
        int bidx=i;
        while(*(s+i)>=48 && *(s+i)<=57){
            i++;
        }
        if(n>=aidx) // aが満杯なら
        {
            aidx++; // a+aidxにアクセスせずにaidx++
            continue;
        }
        int t=0;
        for(int j=bidx;j<i;j++){
            t*=10;
            t+=*(s+j)-48;
        }
        *(a+aidx++)=t;
    }
    
[/code]

`a`に`s`のすべての数字を記録したいときは`realloc()`関数で確保したいメモリを増やす必要があると思います。


CC BY-SA 4.0
2023-11-11T06:33:37.600
96750
2023-11-11T06:33:37.600
60230
96740
answer


再現できずエラーの原因は特定できなかったので御参考です。

いずれにせよ，確保したメモリー領域外へのアクセスは回避したいので，以下のような方法も考えられます。

  * 入力文字列（`s`）から入力された数値（整数）の個数を得る（`input_icount()`）

  * その結果（`n`）を基に配列（`a`）の領域を確保する

  * 入力文字列（`s`）から配列（`a`）に数値を読み込む（`input_iarray()`）

記述例を下記に示します。

（追記）

ふたつの関数をひとつの関数（`int input_iarray(char *, int *,
int)`）にまとめました。数値の個数を返すように変更し，2番目の引数に `NULL`
を設定した場合は数値を配列へ読み込む処理をスキップするようにしました。

[code]

    #include <stdio.h>
    #include <stdlib.h>
    
    #define N 1000000
    
    int input_iarray(char *, int *, int);
    
    int main(void)
    {
        char *s;
        int *a, n, i;
    
        if ((s = (char *)malloc(N)) == NULL)
            return 1;
    
        fgets(s, N, stdin);
    
        n = input_iarray(s, NULL, N);
        printf("n = %d\n", n);
    
        if ((a = (int *)malloc(sizeof(int) * n)) == NULL)
            return 1;
    
        input_iarray(s, a, N);
    
        for (i = 0; i < n; i++)
            printf("%d: %d\n", i, a[i]);
    
        return 0;
    }
    
    int input_iarray(char *s, int *a, int imax)
    {
        int aidx = 0, i = 0;
        int bidx, t, j;
    
        while (i < imax && s[i] != 0) {
            if (s[i] < 48 || 57 < s[i]) {
                i++;
            } else {
                bidx = i;
                while (i < imax && 48 <= s[i] && s[i] <= 57) {
                    i++;
                }
                if (a == NULL) {
                    aidx++;
                    continue;
                }
                for (t = 0, j = bidx; j < i; j++) {
                    t *= 10;
                    t += s[j] - 48;
                }
                a[aidx++] = t;
            }
        }
    
        return aidx;
    }
    
[/code]


CC BY-SA 4.0
2023-11-12T01:40:02.873
96760
2023-11-12T06:35:17.237
2023-11-12T06:35:17.237
54588
54588
96740
answer