user9138715
user9138715

Reputation: 43

understanding the pointers

So I have the following code, I am trying to understand the basics of pointers, so I want to change the value/string inside first, while also preserving it hence using second.

Problem is, whatever the input is, the function will print 0 followed by 1 (the value of i) then crash. I can clearly see it has to do the with loop, but I can't understand why!

Can anyone explain to me why this is happening and how I can avoid this?

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

Upvotes: 0

Views: 104

Answers (2)

user2736738
user2736738

Reputation: 30936

Don't complicate things - here you are complicating things (By the way you accessed array index out of bound and then you got seg fault in the called function).

Easy way to do things

 char* second = first;

Array decays into pointer to the first element. Then with the same logic you do one thing

spells( second );

And then

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");
}

You are not creating any copy - well if you need to use allocate memory or just copy it to some already allocated memory.

Explanation of what might have gone wrong in your case

For your clarity &first is of type char (*)[20]. pointers are not same if the values are equal. You are assigning the value of it to char* and the you pass it's address. Now when you pass it to the function you do this *(*(str+i))

So now str is being incremented by i*sizeof char** - what ever the size of char** maybe it will result in the accessing the memory out of bound, resulting in undefined behavior which in your case turns out to be segmentation fault.


scanf use can be way better by doing two thing

if( scanf("%19s", first) != 1){
    fprintf(stderrm,"%s\n","Error in input");
    exit(1);
}

saving you from possible case of buffer overrun and also checking whether the input got successful or not.


To be clear, my earlier edit was lacking in explaining the problem. To be more explicit, the pointers have two aspect to it - it's value and it's type. The second dictates all the pointer arithmetic.

Here when I said incrementing str would be out of bound by 80 Bytes that will be true only if relevant type information is passed to the function. Something like

spells(&first)

and

void spell(char(*str)[20])

But here we didn't pass that information - we instead assigned the value of char(*)[20] to a char*.(Ofcourse compiler complained) And started working with char**.

Now when I say

str+i
    

Actually we move

str+ i*sizeof(str)

more clearly

str+ i*sizeof(char**)

Here in your case this str originally contains some arbitrary address of a char*, it has no relation with address directly. This memory location now it points to after addition is not your concern and that is some memory to which you have no permission to access.

With (*str) now you get the address of the base of the array. Then you index into it. That's a right thing to do and doesn't create any illegal memory access.

Upvotes: 1

Giorgi Moniava
Giorgi Moniava

Reputation: 28685

Try doing this: (it is a precedence problem. Hint: if you did str[1] inside that function what had to be its value?)

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

But you are not preserving anything this way because from spells function you are still modyfing the instance of the string created inside main: char first[20].

If you want to preserve anything make a copy of the string and operate on the copy.

Upvotes: 2

Related Questions