0

If we use for example:

   char* strs[2];
    strs[1] = "Hello";
    strs[2] = "World!";
    strcat(strs[1],strs[2]);

Then an access violation comes up (Access violation writing location 0x0028CC75).

So why use const char *strs[2]; since the strs1[1], strs1[2] cannot be changed?

kravi
  • 747
  • 1
  • 8
  • 13
S11
  • 15
  • 2
  • 1
    Just to be clear, You're asking why use `const` after showing a sample that *does not do so* and declaring a successful compile followed by a crash. Not that this can compile regardless: there is no `str`, only `strs`. Add the const and see if you get [something like this](http://ideone.com/hunRBv) instead (subscripts and var name fixed). – WhozCraig May 31 '15 at 05:26
  • 2
    `char* strs[2];` allows you to use only `strs[0]` and `strs[1]`. The `strs[2]` is out of range. – dlask May 31 '15 at 05:27
  • @dlask My mistake, though i still get the access violation after strcat(str[0],strs[1]); as Access violation reading location 0xCCCCCCCC. – S11 May 31 '15 at 05:30
  • 1
    The string literals like `"Hello"` are automatically `const` and you cannot write to them. If you do so you get access violation. – dlask May 31 '15 at 05:31
  • Yes that, and `str[2]` does not exists. – Iharob Al Asimi May 31 '15 at 05:32
  • English is inherently ambiguous, and this question does not parse. When you can't change the content of the pointer is precisely when you should use a 'const' qualifier. When you want to change the content, you should not use a 'const' qualifier. What exactly is the question? – William Pursell May 31 '15 at 05:50

3 Answers3

3
// string literals are non-writeable so const is appropriate here
const char* strs[2] = {"Hello", "World!"};
// let's create a target buffer with sufficient space
char buffer[20];
// copy the first string there
strcpy(buffer, strs[0]);
// add the second string there
strcat(buffer, strs[1]);
dlask
  • 8,776
  • 1
  • 26
  • 30
0

Two sources of access violation in your case

  1. String literals are read only and writing to them is undefined behavior

  2. In c arrays are 0 index based, so strs[2] does not exist, only strs[0] and strs[1].

Using const prevents you from accidentally modifying them, but it does not forbid you.

Arrays are modifiable though,

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

int
main(void)
 {
    char strs[2][11] = {"Hello", "World"};
    strcat(strs[0], strs[1]);
    return 0;
 }

the above works as you expected it.

Here it is how you would do it correctly with dynamic allocation

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

char *
autostrcat(const char *const head, const char *const tail)
 {
    char  *result;
    size_t headlen;
    size_t taillen;

    if ((head == NULL) || (tail == NULL))
        return NULL;

    headlen = strlen(head);
    taillen = strlen(tail);
    result  = malloc(1 + headlen + taillen);
    if (result == NULL)
        return NULL;
    memcpy(result, head, headlen);
    memcpy(&result[headlen], tail, taillen);

    result[headlen + taillen] = '\0';
    return result;
 }

int
main(void)
 {
    const char *strs[2] = {"Hello", "World"};
    char *result = autostrcat(strs[0], strs[1]);
    if (result != NULL)
        printf("%s\n", result);
    free(result);
    return 0;
 }

Since you used strlen() you know what the lengths of the strings are, so using strcat() would be unecessarily expensive because it would again figure out the length of the first string as strlen() does.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • What exactly does it mean "prevents", if it is not the same as "forbids"? – S11 May 31 '15 at 05:32
  • 1
    No it doesn't work. It overwrites the memory at the end of hello, and it's buffer isn't big enough. Maybe you got lucky. Thanks for the downvote by the way. – Anthony Wieser May 31 '15 at 05:33
  • It is not the same, is it? prevents means that you can cheat, my wife prevents me from seeing other women. – Iharob Al Asimi May 31 '15 at 05:33
  • @WieserSoftwareLtd you are mostly welcome, if you fix your answer I will remove the downvote, and you are welcome to downvote my answer too. – Iharob Al Asimi May 31 '15 at 05:34
  • 1
    @iharob: The target buffer `strs[0]` doesn't have enough space for both strings merged. – dlask May 31 '15 at 05:34
  • @WieserSoftwareLtd Thank you for your answer really helpful – S11 May 31 '15 at 05:37
  • @S11 , With the `const`, the compiler will issue an error, thus alerting you and preventing you from modifying the string. – Spikatrix May 31 '15 at 05:37
  • @iharob , "_but it does not forbid you_" -- I get an error. So, doesn't the compiler forbid me? – Spikatrix May 31 '15 at 05:38
  • @CoolGuy You can cast away the `const` so strictly it's not forbidden. – Iharob Al Asimi May 31 '15 at 05:38
  • @iharob VS2012 did not give me any warning though.. Just the access violation – S11 May 31 '15 at 05:39
  • @iharob Cast? How? Could you give an example here? – Spikatrix May 31 '15 at 05:39
  • @S11 I think you have to enable warnings. – Iharob Al Asimi May 31 '15 at 05:40
  • @CoolGuy `const char *strs[2] = {"Hello", "World"}; strcat((char *) strs[0], strs[1]);`, the error is gone, the problem persists. – Iharob Al Asimi May 31 '15 at 05:41
  • @iharob , I see. Thanks for the info! – Spikatrix May 31 '15 at 05:44
  • @iharob Thanks again. Though here you know the length of the "Hello", "World". If it is char * char1 = "hello", char * char2 = "world", how can you know how big to make the array for strcat?? – S11 May 31 '15 at 05:45
  • If you know how big they are you don't need `strcat()`. – Iharob Al Asimi May 31 '15 at 05:46
  • @iharob Though in your example the array you create is of specific size and then you use strcat. In the example i mentioned in the comment above you don't know the size of the char *. You just use an char [], of very big size then? – S11 May 31 '15 at 05:50
  • No, it's not like that, it's just that `strlen()` and `strcat()` both use the same technique to find the end of the first string, `strcat()` start **copying** the second string from that point, so you would iterate through the string twice! Instead you know where to start to copy from and how much, because you already have the lengts with `strlen()`. – Iharob Al Asimi May 31 '15 at 05:53
0

Wow. So much wrong.

  1. Arrays are 0 based, not 1 based in C.
  2. The strings are based in program space, most likely, so aren't writeable.

you should create a buffer, and then fill it.

char* concat = (char *) _alloca(strlen(strs[0]) + strlen(strs[1])+1);
strcpy(concat, strs[0]);
strcat(concat, strs[1]);
Anthony Wieser
  • 4,351
  • 1
  • 23
  • 25
  • 2
    wow! `_alloca()` is not even standard!, casting `void *` is retro and not a good idea, and using `strlen()` and then `strcat()` is not smart at all. – Iharob Al Asimi May 31 '15 at 05:29
  • Yeah, i know there are other ways thank you for your answer, though why use const then before it? Is it just useless here? – S11 May 31 '15 at 05:34
  • 1
    [At least remove the cast](http://stackoverflow.com/a/605858/1983495), could you suggest storing the value of `strlen()` and using `memcpy()` instead of letting `strlen()` and `strcat()` both traverse the strings? – Iharob Al Asimi May 31 '15 at 05:44