为什么它没有保存在双指针内?

时间:2017-02-09 20:15:55

标签: c

我有下一个代码,我对这两行代码有问题, printf("Ingrese una palabra: "); scanf("%s",(vector+1)); 如果他们不是,它工作正常,但如果我想修改单词" perro"并询问用户是否给出错误。

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

int main()
{
    int i,j,a;
    char **vector;

    vector = (char**)malloc(2*sizeof(char*));

    *(vector) = "hola";
    *(vector + 1) = "perro";

    //HERE IS THE PROBLEM
    printf("Ingrese una palabra: ");
    scanf("%s",(vector+1));
    //

    puts("\nImprimiendo caracter a caracter:");
    for(i=0;i<2;i++) 
    {
        for(j=0; j<strlen(*(vector+i)) ; j++)
        {
            printf("%c",*(*(vector+i)+j));
        }
        puts("");
    }

    puts("\nImprimiendo completo:");
    printf("%s\n",*vector);
    printf("%s",*(vector+1));

    free(vector);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

*(vector + 1)这样的东西不必要地难以阅读。你可以写vector[1]。也许你是把它作为一个练习,但我不是,所以我要将所有内容翻译成数组语法。

你有两个问题。首先是:

scanf("%s",(vector+1));

这会产生编译器警告:

test.c:17:16: warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat]
    scanf("%s",(vector+1));
           ~~  ^~~~~~~~~~

(如果您没有收到编译器警告,请使用-Wall启用它们并修复所有这些警告。)

scanf想要一个char *,一个字符串。但是你已经给它vector,一个字符串列表,并转移了一个指针。

无论如何,

scanf会尝试在那里推一根弦。 vector仅在64位计算机上分配了2 * sizeof(char*),即8个字节。您将它移动了1 char *或4个字节,因此只剩下4个字节。所以它可以“安全地”在那里填充3个字符,加上一个空字节。但是C很草率,所以scanf可能会在没有操作系统停止的情况下更多地推进它。

$ ./test
Ingrese una palabra: 123

Imprimiendo caracter a caracter:
hola
Segmentation fault: 11

当您尝试将vector[1]用作字符串时会出现段错误,因为char *指向perro的内容已被字符123覆盖并且为空字节。它试图将其用作指向内存的指针并炸毁。

相反,您需要传入char *。这是*(vector+1)或简称vector[1]

scanf("%s", vector[1]);

这将我们带到下一个问题:你只为vector分配内存,这是一个字符串列表。你从来没有为字符串本身分配内存!将常量分配给列表不是替代。一旦我运行了更正的代码,我就会收到总线错误。

$ ./test
Ingrese una palabra: adlskfj
Bus error: 10

这是因为vector[1]包含一个常量字符串perro。你也收到了警告。

test.c:13:19: warning: assigning to 'char *' from 'const char [6]' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
    *(vector + 1) = "perro";
                  ^ ~~~~~~~

这意味着“嘿,这是一个恒定的字符串,但你正在使用它,好像它不是恒定的!”

scanf尝试覆盖它并失败。它不能覆盖那个“内存”,因为它实际上指向已编译二进制文件的一部分。如果你打印出指针,你会看到它与他休息时的情况截然不同。

printf("%p\n", vector[1]);
printf("%p\n", vector);

$ ./test
0x109ce7f51
0x7ff664c08d90

当我使用十六进制编辑器查看二进制文件时,我在位置perro找到00000f51以及程序中的其他字符串常量(您的位于不同的位置)。

00000f40: ffff 6841 0000 00e9 b4ff ffff 686f 6c61  ..hA........hola
00000f50: 0070 6572 726f 0025 700a 0049 6e67 7265  .perro.%p..Ingre
00000f60: 7365 2075 6e61 2070 616c 6162 7261 3a20  se una palabra:
00000f70: 0025 7300 0a49 6d70 7269 6d69 656e 646f  .%s..Imprimiendo
00000f80: 2063 6172 6163 7465 7220 6120 6361 7261   caracter a cara
00000f90: 6374 6572 3a00 2563 0000 0a49 6d70 7269  cter:.%c...Impri
00000fa0: 6d69 656e 646f 2063 6f6d 706c 6574 6f3a  miendo completo:
00000fb0: 0025 730a 0000 0000 0100 0000 1c00 0000  .%s.............

您可以在0xf51中看到0x109ce7f51。这是一个神奇的内存位置告诉C从二进制文件中读取,加上偏移量0xf51。而0x7ff664c08d90指向堆上的读/写内存。

要存储字符串数组,您必须为列表 和字符串 分配内存。

vector = malloc(2*sizeof(char*));
for( i = 0; i < 2; i++ ) {
    vector[i] = malloc( 256 * sizeof(char*) );
}

printf("Ingrese una palabra: ");
scanf("%s",vector[1]);

请注意,vector[1] = "perro"将使用常量字符串替换指向已分配内存的指针,并且您将返回到总线错误。

另请注意I don't cast malloc

答案 1 :(得分:-1)

你正在访问2个pointeurs而没有初始化它们。 你需要为2个向量预留一些空间,因为它们将包含字符。