我有下一个代码,我对这两行代码有问题,
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;
}
答案 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个向量预留一些空间,因为它们将包含字符。