0

I was trying to get an element deleted from the middle of array and then shiffting the whole content, and I had a few difficulties because my test array wasn't "right". I fixed the problem by filling the array with a string using strcpy. The commented part above strcpy is the method I used before(which didn't work). Could somebody explain me maybe why isn't it working?

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

int main(){

    char *array;
    int i=5;

    array = (char*)calloc(1024, sizeof(char));

    if(array == NULL){
        printf("Out of memory\n");
        return 0;
    }

    //array = "Just some test string";
    strcpy(array, "Just some test string");

    printf("%s\n", array);

    memmove(array+i+1, array+i, strlen(array)-i);
    array[i] = ',';

    printf("%s\n", array);

    memmove(array+i, array+i+1, strlen(array)-i);

    printf("%s\n", array);

    free(array);

return 0;
}

The printf is normally working on the commented part, but the memmove() makes my programm crash!

Jumpman
  • 429
  • 1
  • 3
  • 10
  • Please don't cast `calloc` on the right hand side of `=`. It's unnecessary and occasionally harmful. – Bathsheba Dec 15 '15 at 08:22
  • You forgot to move the null terminator, everything else is OK. Of course if you scale this toy application up, you will need to do some pre-checks that your move won't overflow the buffer, and that `i` is less than the size of the string. – M.M Dec 15 '15 at 09:16
  • @Bathsheba what do you mean exactly? That's according the standard, anyway I'll be served with a warning otherwise – Jumpman Dec 15 '15 at 10:39
  • See http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc] – Bathsheba Dec 15 '15 at 10:40
  • @M.M yeah thanks, this is just a test case :P – Jumpman Dec 15 '15 at 10:44
  • @Bathsheba yeah, I've stumbled across that link as well, but my gcc throws me a warning for explicit conversion of void* to int* or whatever pointer type. Anyway according to our standards, I'm supposed to cast... I'm actually unsure about this because gcc(one of the most famous if not the most famous c compiler throws stills warnings...) – Jumpman Dec 15 '15 at 10:51

3 Answers3

1

If you have this:

array = "Just some test string";

then

1) You have memory leak due to overwriting the calloc'ed pointer.

2) You are attempting to modify a string literal. That's probably why it crashes. Modifying a string literal is undefined behaviour. They are typically stored in read-only memory. Since strcpy() makes a copy of the string literal, it works as intended and this method fails.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • So basically my *array got converted to a pointer on a string literal on stack? – Jumpman Dec 15 '15 at 09:41
  • `array` *is* a pointer. When assign a string literal to it it gets converted into a pointer. E.g. `char *p = "Hi";` assigns the address of string literal to `p`. – P.P Dec 15 '15 at 09:46
0

In these statements

memmove(array+i+1, array+i, strlen(array)-i);
array[i] = ',';

there is an attempt to insert character ',' at the position 5 because variable i was initialized with 5.

So the part of the string including the terminating zero has to be shifted right starting with this position. The length of the part is

strlen( array ) - i + 1

because the terminating zero is also must be moved.

So these statements will look like

memmove( array + i + 1, array + i, strlen( array ) - i + 1 );
array[i] = ',';

Then in these statements

memmove( array + i, array + i + 1, strlen( array ) - i );

This statement is correct. Expression strlen( array ) - i is calculated like

( strlen( array ) + 1 ) - ( i + 1 )

As for this statement

array = "Just some test string";

then pointer array points to a string literal and though string literals in C have types of non-constant character arrays nevertheless they are immutable.

Any attempt to modify a string literal results in undefined behaviour of the program.

Also if before this statement you also initialized this pointer with the result of a call to calloc then there will be a memory leak because the pointer is reassigned and the address of the allocated memory is lost.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks for the answer. According to your logic I would then be needing +1 here at the end as well memmove( array + i, array + i + 1, strlen( array ) - i ); I counted it like this, strlen(array) = 21;//so without '\0' char, starting from 0 + 5 = 6// 6th element, moving 21-5=17 elements is including the '\0' right :) ? – Jumpman Dec 15 '15 at 09:37
  • @Maxitj Function strlen returns the number of characters before the terminating zero. But if you want to move a part of a string you need take into account the terminating zero because it also should be moved. In your original code you used calloc that initializes all the memory with zeroes. So there is no problem to shift to right. But there will be a problem to shift to left because the terminating zero will not be shifted. – Vlad from Moscow Dec 15 '15 at 09:56
0

I tried to do something like this.

I solved it by having:

    *(array+strlen(string)+1)=0;

Null terminating the string, but if the subsequent printf() is working correctly this won't help.

Otherwise see: http://www.java-samples.com/showtutorial.php?tutorialid=591

Arif Burhan
  • 507
  • 4
  • 12