简体   繁体   中英

Truncating a string to certain length, and then adding characters to the end in C

If a string is greater than a certain length, I want to truncate it to a certain length, and replace the last 3 characters with a period ("."). What I have right now causes a segmentation fault:

#define NAME_LENGTH 36

name is of type, char*. 

if (strlen(name) > NAME_LENGTH){
    //we need to truncate the name
    printf("NAME IS TOO LONG.. TRUNCATING\n");
    char *nCpy = NULL; //the truncated name
    strncpy(nCpy, name, NAME_LENGTH); //copy NAME_LENGTH number of characters from name into nCpy
    printf("Truncated name, now adding ...\n");
    strcat(name, "..."); //append "..." to end of name
    printf("... added, now copying to struct\n");
    strcpy(record->name, nCpy); //assign our name in our record
    printf("NAME IS NOW: %s\n", record->name);
}

Upon running, if a name that is longer than NAME_LENGTH, I get a segmentation fault.

Enter name > jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
NAME IS TOO LONG.. TRUNCATING
Segmentation fault (core dumped)

You are segfaulting because you didn't allocate memory to store where nCpy is pointing at.

char *nCpy = NULL; //the truncated name

Should be something like

char *nCpy = malloc(sizeof(char) * NAME_LENGTH + 1); //the truncated name

What you're trying now is to write to some junk value in memory, who knows, which almost always leads to a segmentation fault.

As Paul points out, you need to allocate space for NAME_LENGTH characters, plus one since a character string is null terminated with the special /0 character. This specific error is called dereferencing a null pointer

You are really doing far too many string copies, and not freeing the copies afterwards, so you're going to end up with a lot of leaked memory. Also, it's not clear whether record->name is actually long enough to hold the returned string, but if it is, you might as well build the name in place.

Here's one possibility, which assumes that record->name already points to at least NAME_LENGTH + 1 bytes of storage:

if (strlen(name) > NAME_LENGTH)
  snprintf(record->name, NAME_LENGTH + 1, "%.*s...", NAME_LENGTH - 3, name);
else
  strncpy(record->name, name, NAME_LENGTH + 1);

Here's another, possibly simpler or possibly more mysterious way of doing it:

if (snprintf(record->name, NAME_LENGTH + 1, "%s", name) > NAME_LENGTH))
  strcpy(record->name + NAME_LENGTH - 3, "...");

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