简体   繁体   中英

What would be a safe and practical way to copy a string as defined by this prompt in C?

The purpose of this function is to copy a string into a "buffer" - essentially another string. However, the problem seems overly complicated than what would be practical.

"Copies at most n-1 characters of string in into the buffer pointed to by
 out. If n is reached, returns -2.  Otherwise, returns -1 for malformed
 input and 0 upon successful completion."

This is what I have:

#include <stdio.h>
#include <assert.h>

int copyStringN(register char *in, register char *out, register int n){
  //Declarations
    int i; //Dummy index
    if(!in || !out) return -1;
    for(i=0; i<n; i++){
         *out++ = *in++;
    }
    *out = '\0';
    return 0;
}

int main(void){
//Declarations
  char in[] = "I'm not trying to inject malicious code...\\x29A.";
  const int N = sizeof(in);
  char out[N];
  int err;

//Main execution
  printf("\nThis function will copy at most n-1 characters of string into\nthe buffer pointed to by out.\n\n");
  err = copyStringN(in, out, N);
  assert(!err);
  printf("%s\n", out);


  printf("\nPlease press enter to exit...");
  getchar();
  return 0;  
}

This general form was suggested, but it seems overly convoluted than what needs to be done. Why would n ever be reached? The execution should stop before n . Furthermore, wouldn't N = sizeof(in) match the length of the original string?

Personally, I would rather use a function closer to

int copyStringN(register char *in, register char *out)
{
 if((!in || !out) && (sizeof(in)<=sizeof(out))) return -1;
 else{
      while(*t++ = *from++);
      return 0;
 }

}

int main(void){
  //Declarations 
  char in[] = "I'm not trying to inject malicious code...\\x29A.";
  const int N = sizeof(in);
  char out[N];
  int err;

.
.
.

I believe it would have the same effect with less statements. Let me make this more of a question, how could I write a function that copies a string into another array with the protection defined in the prompt? Also, are the two programs that I presented somehow vulnerable in a way I don't recognize?

Constructive input is appreciated.

Your suggested alternative will not work. (sizeof(in)<=sizeof(out) will always be TRUE , because you are comparing pointers (and not arrays), and they are the same size.

If you want to make safe string copy function, you must always pass output buffer length for size checking, and have means to inform user if input was too long for output.

Edit:

Since people have suggested to use strncpy , I will present safer alternative:

int len = snprintf(output, OUTPUT_SIZE, "%s", input);
if(len < 0 || len >= OUTPUT_SIZE) {
    // Failed, handle error
}

This is a strange thing in C.

char mole[] = "mole" is not the same as char *mole = "mole"

I just tried:

char *a1 = "mole";
char a2[] = "mole";
printf ("s1: %i s2:%i\n", sizeof(a1), sizeof(a2) );

a1 is a pointer, so 4 or 8 depending on the architecture. a2 is an array of size 5.

But you can convert a2 to a char* without warnings. But you loose the size.

Fewer statements in your source does not necessarily imply that it is simpler to grasp. The while row in your alternative solution may work, but is doing too many things at the same time for my taste. You are writing code first for other human beings to read, then for a compiler to read.

I like for example making the NULL and \\0 checking explicit.

It is also unclear what you are trying to achieve with the sizeof comparison. Besides comparing size of pointers (instead of intended arrays?), I think you meant || instead of && . If either pointer is NULL it is an error, whatever the size.

int copyStringN(char *in, char *out)
{
    if((in == NULL) || (out == NULL)) {
        return -1;
    } else {
        while(*in != '\0') {
            *out++ = *in++;
        }
        *out = '\0';
        return 0;
    }
} 

The compiled code is probably not going to be much different, only the source is more human readable in my opinion.

Then if there happens to be no '\\0' in the in string you are going to have problems. I suppose this is the reason for having a length limit n .

while((*in != '\0') && (n-- > 0)) {
    *out++ = *in++;
}
*out = '\0';

Note that you would still be in trouble if n is greater than the size of your arrays and you miss a '\\0' .

A very similar interface is strncpy . Perhaps the error modes will make more sense after you read the man page.

It is always better to use strncpy to prevent buffer overflow. char * strncpy ( char * destination, const char * source, size_t num ); Also, better to use strlen rather than sizeof. So, Even if the source string is greater than the destination buffer. It will protect the destination buffer from buffer overflow. I would use n as the maximum size of the destination buffer. And In fact make n = strlen(dest_buffer) -1. To accommodate '\\0'.

a basic strncpy would look like:

char *strncpy(char *d,const char *s,int n){int i=0;while(n--&&d[i++]=*s++);return d;}

but you could force a null byte at n-1

char *sstrncpy(char *d, const char *s, int n){
  int i=0;
  while(--n&&d[i++]=*s++);
  if(!n)d[i]=0;
  return d;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM