理解指针

时间:2017-12-25 12:30:21

标签: c pointers

所以我有以下代码,我试图理解指针的基础知识,所以我想更改first内的值/字符串,同时也保留它,因此使用second

问题是,无论输入是什么,该函数都会打印0后跟1i的值) 然后崩溃。我可以清楚地看到它必须做循环,但我不明白为什么!

任何人都可以向我解释为什么会发生这种情况以及如何避免这种情况?

#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;
}

2 个答案:

答案 0 :(得分:2)

尝试这样做: (这是一个优先级问题。提示:如果你在该函数中做了str[1]那么它的值是什么?)

if( (*str)[i] %3 == 0 ){// if the ascii value is divided by 3
            (*str)[i] = '#';
 }

但是你没有以这种方式保留任何东西,因为从spells函数你还在修改main:char first[20]中创建的字符串的实例。

如果要保留任何内容,请复制字符串并对副本进行操作。

答案 1 :(得分:1)

不要让事情变得复杂 - 在这里你会使事情变得复杂(顺便说一下你访问数组索引越界,然后你在被调用的函数中得到了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*,并且您传递了它的地址。现在,当您将其传递给函数时,请执行此操作*(*(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**。< / p>

现在我说

str+i

其实我们搬家了

str+ i*sizeof(str)

更清楚

str+ i*sizeof(char**)

在您的情况下,此str最初包含char*的任意地址,它与地址无直接关系。现在它添加后指向的内存位置不是您关心的,而是您无权访问的内存。

现在使用(*str)获取数组基址的地址。然后你索引它。这是正确的做法,并没有创建任何非法的内存访问。