[英]understanding the pointers
所以,我有下面的代码,我想了解指针的基础知识,所以我想改变里面的值/串first
,同时也保留它因此使用second
。
问题是,无论输入是什么,函数将打印0
后跟1
( i
的值)然后崩溃。 我可以清楚地看到它必须做循环,但我不明白为什么!
任何人都可以向我解释为什么会发生这种情况以及如何避免这种情况?
#include <stdio.h>
#include <string.h>
void spells( char **str ){
int i = 0, len = strlen(*str);
while( i < len ){
printf("%d\n",i); //just to check
if( ( (int)*str[i] )%3 == 0 ){// if the ascii value is divided by 3
*str[i] = '#';
}
i++;
} puts("done");
}
int main(){
char first[20];
char* second = &first;
scanf("%s", first);
spells( &second );
printf("%s", second);
printf("\n%s", first);
return 0;
}
尝试这样做:(这是一个优先级问题。提示:如果你在该函数中做了str[1]
那么它的值是什么?)
if( (*str)[i] %3 == 0 ){// if the ascii value is divided by 3
(*str)[i] = '#';
}
但是你并没有以这种方式保留任何东西,因为从spells
函数来看,你仍在修改main: char first[20]
创建的字符串的实例。
如果要保留任何内容,请复制字符串并对副本进行操作。
不要复杂化 - 在这里你会使事情复杂化(顺便说一下,你访问数组索引越界,然后你在被调用的函数中得到了seg错误)。
简单的做事方式
char* second = first;
数组衰减成指向第一个元素的指针。 然后用同样的逻辑做一件事
spells( second );
接着
void spells( char *str ){
size_t i = 0, len = strlen(str);
while( i < len ){
printf("%zu\n",i); //just to check
if( str[i] % 3 == 0 ){// if the ascii value is divided by 3
str[i] = '#';
}
i++;
}
puts("done");
}
您没有创建任何副本 - 如果您需要使用分配内存或只是将其复制到已分配的内存。
为了您的清晰度&first
是char (*)[20]
类型char (*)[20]
。 如果值相等,则指针不相同。 您将它的值分配给char*
并且您传递它的地址。 现在当你把它传递给函数时你就做了*(*(str+i))
所以,现在str
是递增的i*sizeof char**
-什么样的有史以来规模char**
也许它会导致访问内存越界,导致不确定的行为而你的情况原来是段错误。
通过做两件事可以更好地使用scanf
if( scanf("%19s", first) != 1){
fprintf(stderrm,"%s\n","Error in input");
exit(1);
}
使您免于缓冲区溢出的可能情况,并检查输入是否成功。
要清楚,我之前的编辑缺乏解释问题。 更明确的是,指针有两个方面 - 它的值和它的类型 。 第二个指示所有指针算术。
在这里,当我说增量str
将超出80
字节时,只有在相关类型信息传递给函数时才会成立。 就像是
spells(&first)
和
void spell(char(*str)[20])
但是在这里我们没有传递那些信息 - 我们将char(*)[20]
的值赋给char*
。(Ofcourse编译器抱怨)并开始使用char**
。
现在,当我说
str+i
其实我们搬家了
str+ i*sizeof(str)
更清楚
str+ i*sizeof(char**)
在这种情况下,这个str
最初包含一些char*
任意地址,它与地址没有直接关系。 现在它指向添加后的内存位置不是您关注的问题,而是您无权访问的内存。
现在使用(*str)
获取数组基址的地址。 然后你索引它。 这是正确的做法,不会创建任何非法的内存访问。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.