2
    char sentence2[10];

    strncpy(sentence2, second, sizeof(sentence2));  //shouldn't I specify the sizeof(source) instead of sizeof(destination)?

    sentence2[10] = '\0';                       //Is this okay since strncpy does not provide the null character.

    puts(sentence2);
//////////////////////////////////////////////////////////////

    char *pointer = first;
    for(int i =0; i < 500; i++)                 //Why does it crashes without this meaningless loop?!
    {
        printf("%c", *pointer);
        if(*pointer == '\n')
            putchar('\n');
        pointer++;
    }

So here's the problem. When I run the first part of this code, the program crashes. However, when I add the for loop that just prints garbage values in memory locations, it does not crash but still won't strcpy properly.

Second, when using strncpy, shouldn't I specify the sizeof(source) instead of sizeof(destination) since I'm moving the bytes of the source ?

Third, It makes sense to me to add the the null terminating character after strncpy, since I've read that it doesn't add the null character on its own, but I get a warning that it's a possible out of bounds store from my pelles c IDE.

fourth and most importantly, why doesn't the simply strcpy work ?!?!

////////////////////////////////////////////////////////////////////////////////////

UPDATE:

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

void main3(void)
{
    puts("\n\n-----main3 reporting for duty!------\n");
    char *first = "Metal Gear";
    char *second = "Suikoden";
    printf("strcmp(first, first)  = %d\n", strcmp(first, first));   //returns 0 when both strings are identical.
    printf("strcmp(first, second) = %d\n", strcmp(first, second));  //returns a negative when the first differenet char is less in first string.  (M=77  S=83)
    printf("strcmp(second, first) = %d\n", strcmp(second, first));  //returns a positive when the first different char is greater in first string.(M=77  S=83)

    char sentence1[10]; 
    strcpy(sentence1, first);
    puts(sentence1);
    char sentence2[10];
    strncpy(sentence2, second, 10); //shouldn't I specify the sizeof(source) instead of sizeof(destination).
    sentence2[9] = '\0';                        //Is this okay since strncpy does not provide the null character.

    puts(sentence2);
    char *pointer = first;
    for(int i =0; i < 500; i++)                 //Why does it crashes without this nonsensical loop?!
    {
        printf("%c", *pointer);
        if(*pointer == '\n')
            putchar('\n');
        pointer++;
    }
}

This is how I teach myself to program. I write code and comment all I know about it so that the next time I need to look up something, I just look at my own code in my files. In this one, I'm trying to learn the string library in c.

Mustafa
  • 177
  • 1
  • 2
  • 10
  • Most likely, `sizeof` is entirely inappropriate here, whether the sizeof the source or the destination. – user2357112 May 02 '14 at 00:40
  • 1
    Can you give a [complete, minimal example](http://stackoverflow.com/help/mcve) rather than just this snippet? In particular, it'd be useful to know what `second` looks like. – user2357112 May 02 '14 at 00:41
  • 5
    `sentence2[10] = '\0';` is out of bounds, and causes **undefined behavior**. – Beta May 02 '14 at 00:41
  • I tried replacing that part with just the size of bytes of the destination (10 bytes) and still won't work. I've also tried removing the null character assignment and nothing changed. – Mustafa May 02 '14 at 00:43
  • @alvits tried that too .. Nothing changed. – Mustafa May 02 '14 at 00:45
  • second is a simple c string. I defined as "char *second = "suikoden" and it was only involved in strcmp statements. – Mustafa May 02 '14 at 00:47

3 Answers3

3

Your problems start from here:

char sentence1[10]; 
strcpy(sentence1, first);

The number of characters in first, excluding the terminating null character, is 10. The space allocated for sentence1 has to be at least 11 for the program to behave in a predictable way. Since you have already used memory that you are not supposed to use, expecting anything to behave after that is not right.

You can fix this problem by changing

char sentence1[10]; 

to

char sentence1[N]; // where N > 10.

But then, you have to ask yourself. What are you trying to accomplish by allocating memory on the stack that's on the edge of being wrong? Are you trying to learn how things behave at the boundary of being wrong/right? If the answer to the second question is yes, hopefully you learned from it. If not, I hope you learned how to allocate adequate memory.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • @R Sahu: +1 Thanks man that fixed it. The reason I've only allocated 10 chars is that I thought that counting from 0, there's space for 11 chars. sentence2 is 11 including the null character. I don't understand how sentence1 isn't enough for first. – Mustafa May 02 '14 at 01:33
3
char *first = "Metal Gear";
char sentence1[10]; 
strcpy(sentence1, first);

This doesn't work because first has 11 characters: the ten in the string, plus the null terminator. So you would need char sentence1[11]; or more.

strncpy(sentence2, second, sizeof(sentence2));  

//shouldn't I specify the sizeof(source) instead of sizeof(destination)?

No. The third argument to strncpy is supposed to be the size of the destination. The strncpy function will always write exactly that many bytes.

If you want to use strncpy you must also put a null terminator on (and there must be enough space for that terminator), unless you are sure that strlen(second) < sizeof sentence2.

Generally speaking, strncpy is almost never a good idea. If you want to put a null-terminated string into a buffer that might be too small, use snprintf.

This is how I teach myself to program.

Learning C by trial and error is not good. The problem is that if you write bad code, you may never know. It might appear to work , and then fail later on. For example it depends on what lies in memory after sentence1 as to whether your strcpy would step on any other variable's toes or not.

Learning from a book is by far and away the best idea. K&R 2 is a decent starting place if you don't have any other.

If you don't have a book, do look up online documentation for standard functions anyway. You could have learnt all this about strcpy and strncpy by reading their man pages, or their definitions in a C standard draft, etc.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    +1 .. I do have K&R but that book never ceases to piss me off :). I know it's one of the best if not the best book on C, but it expects too much. The example codes are too hard for a newbie like me. So I'm currently studying from online documentations just like you've suggested. Thank you for taking the time to answer my question. – Mustafa May 02 '14 at 02:58
1

this is an array bounds write error. The indices are only 0-9

sentence2[10] = '\0';

it should be

sentence2[9] = '\0';

second, you're protecting the destination from buffer overflow, so specifying its size is appropriate.

EDIT:

Lastly, in this amazingly bad piece of code, which really isn't worth mentioning, is relevant to neither strcpy() nor strncpy(), yet seems to have earned me the disfavor of @nonsensicke, who seems to write very verbose and thoughtful posts... there are the following:

char *pointer = first;
for(int i =0; i < 500; i++)
{
    printf("%c", *pointer);
    if(*pointer == '\n')
        putchar('\n');
    pointer++;
}

Your use of int i=0 in the for loop is C99 specific. Depending on your compiler and compiler arguments, it can result in a compilation error.

for(int i =0; i < 500; i++)

better

int i = 0;
...
for(i=0;i<500;i++)

You neglect to check the return code of printf or indicate that you are deliberately ignoring it. I/O can fail after all...

printf("%c", *pointer);

better

int n = 0;
...
n = printf("%c", *pointer);
if(n!=1) { // error! }

or

(void) printf("%c", *pointer);

some folks will get onto you for not using {} with your if statements

if(*pointer == '\n') putchar('\n');

better

if(*pointer == '\n') {
    putchar('\n');
}

but wait there's more... you didn't check the return code of putchar()... dang

better

unsigned char c = 0x00;
...
if(*pointer == '\n') {
    c = putchar('\n');
    if(c!=*pointer) // error
}

and lastly, with this nasty little loop you're basically romping through memory like a Kiwi in a Tulip field and lucky if you hit a newline. Depending on the OS (if you even have an OS), you might actually encounter some type of fault, e.g. outside your process space, maybe outside addressable RAM, etc. There's just not enough info provided to say actually, but it could happen.

My recommendation, beyond the absurdity of actually performing some type of detailed analysis on the rest of that code, would be to just remove it altogether.

Cheers!

maha
  • 605
  • 6
  • 13
  • 1
    That's not all that is wrong with his code. Please address the other issues as well... – nonsensickle May 02 '14 at 00:45
  • @Mustafa, I completely agree regarding the loop not being important, hence I didn't address it originally. I answered the original questions succinctly with my pre-EDIT post and was rewarded with down votes for my troubles. While a bit more direct perhaps, look beyond the cheekiness of the post and there are tid-bits in there that will genuinely improve your programming. Cheers! – maha May 02 '14 at 02:36
  • @nonsensickle, I almost always stop with the first error that stops things from working. The person asking the question can fix that problem, and should then be encouraged to look at the remainder of their code more carefully and fix other problems themselves. maha's first four lines give the additional information that using an array index >= 10 is bad, which the poster should be able to take into account themselves. – gnasher729 Jun 03 '14 at 16:45
  • @gnasher729 I have no problem with that philosophy. In fact I have done the same in some of my answers. I would only ask that you write a footnote explaining that that is what you're doing and I will be happy to upvote. – nonsensickle Jun 03 '14 at 22:01
  • @gnasher729 Thank you for updating your post and sorry for not upvoting as promised until now. +1 – nonsensickle Jul 02 '14 at 21:37