Related
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 1 year ago.
I'm trying to 'deep copy' a string so that I can perform operations on one copy, while retaining the original copy. This is the base example that I've got and for some reason the strncpy call causes a segfault. Please help
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
char* stringB = malloc(sizeof(char) * strlen(stringA));
printf("A: %s, B: %s\n", stringA, stringB);
for (int i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
printf("A: %s, B: %s\n", stringA, stringB);
strncpy(stringA, stringB, strlen(stringA) - 1);
printf("A: %s, B: %s\n", stringA, stringB);
}
Easiest fix is to make a local copy of that string literal:
char stringA[] = "someVeryinTeresTingString";
Everything else works just the same.
Note that in the original code you have a pointer to immutable memory, while in this version you have a local (stack) array that is initialized with a copy of that string.
Another thing to note is if you're copying and manipulating C strings, do things like this:
char* stringB = strdup(stringA);
for (int i = 0; i < strlen(stringB); ++i) {
stringB[i] = tolower(stringB[i]);
}
Or even more efficiently by avoiding all these expensive strlen() calls:
char* stringB = strdup(stringA);
for (char* p = stringB; *p; ++p) {
*p = tolower(*p);
}
This line:
char* stringB = malloc(sizeof(char) * strlen(stringA));
shuld be like this:
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
then you will able to copy the \0 in the end of stringA
also, you want to copy to literal string - that is segmentation fault
char *strncpy(char *dest, const char *src, size_t n)
I'll try to comment and correct in your own code the mistakes I've seen:
(I will not correct things that can be eliminated or better done in another way, but are correct or not harmful, so you'll see only what must be corrected because of programming errors, and not questions about style or programming uses)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
/* you need to consider the space for the final null character in the malloc() call */
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
/* you don't need to use sizeof(char) as it is always equal to one.
* Multiplying by one is not necessary, but you'll probably know.
* char is warranteed by C standard that its sizeof is one. */
/* you need to copy the string *before* printing, or you will print an
* uninitialized string. Or at least initialize stringB to zeros, so you can
* use it with printf like functions (I do initialize the first char position to
* zero to make it appear as a length zero "" string)
* You will incurr in undefined behaviour if you don't do this. */
stringB[0] = '\0';
printf("A: %s, B: %s\n", stringA, stringB);
/* you need to copy the strings, so you can do it better if you test when
* stringA[i] == '\0', so you don't calculate the length of a string that is
* not going to change at every loop iteration. I will not change your
* code, because this is not an error. But strlen() searches from the
* beginning of the string for the '\0' char, character by character,
* and this test is done at every loop iteration. With the expression
* stringA[i] == 0 you do only a test per loop iteration to see if
* the char at position i in stringA is the null character. */
int i;
for (i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
/* you have not copied the final '\0', so I do it now. I need to move the
* declaration of i outside of the loop to be able to use it's value. */
stringB[i] = 0; /* you can use 0 or '\0' interchangeably */
printf("A: %s, B: %s\n", stringA, stringB);
/* nope. you need to copy the strings with a normal strcpy() as you know that
* both are the same length (better, you know that the space in stringB
* is the same as the length of stringA plus one). If you do this, you will not copy the last '\0' char, so wee need to append it.
* well, I don't know if that is what you want, so I don't actually touch anything here. */
strncpy(stringA, stringB, strlen(stringA) - 1);
/* stringB should be one char shorter than stringA */
printf("A: %s, B: %s\n", stringA, stringB);
}
by the way, you have been recommended to use strdup(3). This is a good idea, you don't need to be thinking on final nulls in this case, because strdup() takes care of it. Just remember that strdup(3) is not included in many C standard revisions, so you can get in trouble if you
move your program to a place lacking it (that should be very strange, anyway)
I'm try to concatenate to char * rv with the result of a function call that will return an int. fib() returns an int. The main problem I'm running into is that strcat()'s signature requires a const char * as it's second arg:
char * strcat ( char * destination, const char * source );
Here is a small sample of my code. fib() calculates the nth fibonacci number - in this case, the 7th fibonacci number.
char * rv;
int num;
rv = (char*)malloc(2048*sizeof(char));
num = 7;
...
strcat(rv, (const char *)itoa(fib(num), rv,10));
Obviously this is wrong and won't compile. What is the cleanest way to do this? Do I need another char * var to store the results of itoa() first, instead of using rv?
Thank you for any help you can provide!
Use snprintf() to construct a buffer containing the int and then concatenate it to your rv buffer. Do not attempt to concatenate the existing content of rv in the same call to snprintf():
snprintf(rv, 2048, "%s%d", rv, itoa(fib(num), rv,10)));
as this means the input and output buffers overlap which is undefined behaviour.
Also:
sizeof(char) is guaranteed to be 1
see Do I cast the result of malloc?
So the malloc() call would be:
rv = malloc(2048);
if (rv)
{
}
You need either an intermediate char array to print the number to before strcating, or you can directly sprintf the number to rv, but for that you need a pointer to the end,
char *rv = malloc(2048);
char *rv_end = rv;
...
rv_end += sprintf(rv_end, "%d", fib(num));
and also update the rv_end pointer when appending other things to the buffer.
(Thanks to jthill for the improvement using the return value of sprintf.)
You could do this
sprintf(dest,"%s %d",rv,num);
char * strcat ( char * destination, const char * source );
The "const" on source simply tells the compiler that the strcat function will not modify "source". Otherwise,
strcat(buffer, "hi");
would not be allowed.
This does not mean that your source must be constant, nor should it have the const modifier.
strcat(rv, (char *)itoa(fib(num), rv,10));
(no "const") is perfectly legal and should not generate any compiler warnings.
The only issue is that if you don't know the length of the source, you're opening yourself up to a buffer overflow. In this particular case, you can figure out how long the itoa return can be and size the destination accordingly. However, it's probably safer to us snprintf to control how large it is.
I am trying to remove first semicolon from a character arrary whose value is:
Input: ; Test: 876033074, 808989746, 825766962, ; Test1:
825766962,
Code:
char *cleaned = cleanResult(result);
printf("Returned BY CLEAN: %s\n",cleaned);
char *cleanResult(char *in)
{
printf("Cleaning this: %s\n",in);
char *firstOccur = strchr(in,';');
printf("CLEAN To Remove: %s\n",firstOccur);
char *restOfArray = firstOccur + 2;
printf("CLEAN To Remove: %s\n",restOfArray); //Correct Value Printed here
char *toRemove;
while ((toRemove = strstr(restOfArray + 2,", ;"))!=NULL)
{
printf("To Remove: %s\n",toRemove);
memmove (toRemove, toRemove + 2, strlen(toRemove + 2));
printf("Removed: %s\n",toRemove); //Correct Value Printed
}
return in;
}
Output (first semicolon still there): ; Test: 876033074,
808989746, 825766962; Test1: 825766962;
Regarding sizeof(cleaned): using sizeof to get the capacity of an array only works if the argument is an array, not a pointer:
char buffer[100];
const char *pointer = "something something dark side";
// Prints 100
printf("%zu\n", sizeof(buffer));
// Prints size of pointer itself, usually 4 or 8
printf("%zu\n", sizeof(pointer));
Although both a local array and a pointer can be subscripted, they behave differently when it comes to sizeof. Thus, you cannot determine the capacity of an array given only a pointer to it.
Also, bear this in mind:
void foo(char not_really_an_array[100])
{
// Prints size of pointer!
printf("%zu\n", sizeof(not_really_an_array));
// Compiles, since not_really_an_array is a regular pointer
not_really_an_array++;
}
Although not_really_an_array is declared like an array, it is a function parameter, so is actually a pointer. It is exactly the same as:
void foo(char *not_really_an_array)
{
...
Not really logical, but we're stuck with it.
On to your question. I'm unclear on what you're trying to do. Simply removing the first character of a string (in-place) can be accomplished with a memmove:
memmove( buffer // destination
, buffer + 1 // source
, strlen(buffer) - 1 // number of bytes to copy
);
This takes linear time, and assumes buffer does not contain an empty string.
The reason strcpy(buffer, buffer + 1) won't do is because the strings overlap, so this yields undefined behavior. memmove, however, explicitly allows the source and destination to overlap.
For more complex character filtering, you should consider traversing the string manually, using a "read" pointer and a "write" pointer. Just make sure the write pointer does not get ahead of the read pointer, so the string won't be clobbered while it is read.
void remove_semicolons(char *buffer)
{
const char *r = buffer;
char *w = buffer;
for (; *r != '\0'; r++)
{
if (*r != ';')
*w++ = *r;
}
*w = 0; // Terminate the string at its new length
}
You are using strcpy with overlapping input / output buffer, which results in undefined behavior.
You're searching for a sequence of three characters (comma space semicolon) and then removing the first two (the comma and the space). If you want to remove the semicolon too, you need to remove all three characters (use toRemove+3 instead of toRemove+2). You also need to add 1 to the strlen result to account for the NUL byte terminating the string.
If, as you say, you just want to remove the first semicolon and nothing else, you need to search for just the semicolon (which you can do with strchr):
if ((toRemove = strchr(in, ';')) // find a semicolon
memmove(toRemove, toRemove+1, strlen(toRemove+1)+1); // remove 1 char at that position
I am having trouble concatenating strings in C, without strcat library function. Here is my code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
char *b1=(char*)malloc(100);
strcpy(b1,"Ratnavel");
int i;
int len=strlen(a1);
for(i=0;i<strlen(b1);i++)
{
a1[i+len]=b1[i];
}
a1[i+len]='\0';
printf("\n\n A: %s",a1);
return 0;
}
I made corrections to the code. This is working. Now can I do it without strcpy?
Old answer below
You can initialize a string with strcpy, like in your code, or directly when declaring the char array.
char a1[100] = "Vivek";
Other than that, you can do it char-by-char
a1[0] = 'V';
a1[1] = 'i';
// ...
a1[4] = 'k';
a1[5] = '\0';
Or you can write a few lines of code that replace strcpy and make them a function or use directly in your main function.
Old answer
You have
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|0|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_]
b1 [R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_|_|_|_|_|_]
and you want
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_]
so ...
a1[5] = 'R';
a1[6] = 'a';
// ...
a1[12] = 'l';
a1[13] = '\0';
but with loops and stuff, right? :D
Try this (remember to add missing bits)
for (aindex = 5; aindex < 14; aindex++) {
a1[aindex] = b1[aindex - 5];
}
Now think about the 5 and 14 in the loop above.
What can you replace them with? When you answer this, you have solved the programming problem you have :)
char a1[] = "Vivek";
Will create a char array a1 of size 6. You are trying to stuff it with more characters than it can hold.
If you want to be able to accommodate concatenation "Vivek" and "Ratnavel" you need to have a char array of size atleast 14 (5 + 8 + 1).
In your modified program you are doing:
char *a1=(char*)malloc(100); // 1
a1 = "Vivek"; // 2
1: Will allocate a memory chunk of size 100 bytes, makes a1 point to it.
2: Will make a1 point to the string literal "Vivek". This string literal cannot be modified.
To fix this use strcpy to copy the string into the allocated memory:
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
Also the for loop condition i<strlen(b1)-1 will not copy last character from the string, change it to i<strlen(b1)
And
a1[i]='\0';
should be
a1[i + len]='\0';
as the new length of a1 is i+len and you need to have the NUL character at that index.
And don't forget to free your dynamically allocated memory once you are done using it.
You cannot safely write into those arrays, since you have not made sure that enough space is available. If you use malloc() to allocate space, you can't then overwrite the pointer by assigning to string literal. You need to use strcpy() to copy a string into the newly allocated buffers, in that case.
Also, the length of a string in C is computed by the strlen() function, not length() that you're using.
When concatenating, you need to terminate at the proper location, which your code doesn't seem to be doing.
Here's how I would re-implement strcat(), if needed for some reason:
char * my_strcat(char *out, const char *in)
{
char *anchor = out;
size_t olen;
if(out == NULL || in == NULL)
return NULL;
olen = strlen(out);
out += olen;
while(*out++ = *in++)
;
return anchor;
}
Note that this is just as bad as strcat() when it comes to buffer overruns, since it doesn't support limiting the space used in the output, it just assumes that there is enough space available.
Problems:
length isn't a function. strlen is, but you probably shouldn't call it in a loop - b1's length won't change on us, will it? Also, it returns a size_t, which may be the same size as int on your platform but will be unsigned. This can (but usually won't) cause errors, but you should do it right anyway.
a1 only has enough space for the first string, because the compiler doesn't know to allocate extra stack space for the rest of the string since. If you provide an explicit size, like [100], that should be enough for your purposes. If you need robust code that doesn't make assumptions about what is "enough", you should look into malloc and friends, though that may be a lesson for another day.
Your loop stops too early. i < b1_len (assuming you have a variable, b1_len, that was set to the length of b1 before the loop began) would be sufficient - strlen doesn't count the '\0' at the end.
But speaking of counting the '\0' at the end, a slightly more efficient implementation could use sizeof a1 - 1 instead of strlen(a1) in this case, since a1 (and b1) are declared as arrays, not pointers. It's your choice, but remember that sizeof won't work for pointers, so don't get them mixed up.
EDIT: New problems:
char *p = malloc(/*some*/); p = /* something */ is a problem. = with pointers doesn't copy contents, it copies the value, so you're throwing away the old pointer value you got from malloc. To copy the contents of a string into a char * (or a char [] for that matter) you'd need to use strcpy, strncpy, or (my preference) memcpy. (Or just a loop, but that's rather silly. Then again, it may be good practice if you're writing your own strcat.)
Unless you're using C++, I wouldn't cast the return value of malloc, but that's a religious war and we don't need one of those.
If you have strdup, use it. If you don't, here is a working implementation:
char *strdup(const char *c)
{
size_t l = strlen(c);
char *d = malloc(l + 1);
if(d) memcpy(d, c, l + 1);
return d;
}
It is one of the most useful functions not in the C standard library.
You can do it using strcpy() too ;)
char *a = (char *) malloc(100);
char *b = (char *) malloc(100);
strcpy(a, "abc"); // initializes a
strcpy(b, "def"); // and b
strcpy((a + strlen(a)), b); // copy b at end of a
printf("%s\n",a); // will produce: "abcdef"
i think this is an easy one.
#include<stdio.h>
int xstrlen(char *);
void xstrcat(char *,char *,int);
void main()
{
char source[]="Sarker";
char target[30]="Maruf";
int j=xstrlen(target);
xstrcat(target,source,j);
printf("Source String: %s\nTarget String: %s",source,target);
}
int xstrlen(char *s)
{
int len=0;
while(*s!='\0')
{
len++;
s++;
}
return len;
}
void xstrcat(char *t,char *s,int j)
{
while(*t!='\0')
{
*t=*t;
t++;
}
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
}
It is better to factor out your strcat logic to a separate function. If you make use of pointer arithmetic, you don't need the strlen function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* To completely get rid of this,
implement your our strcpy as well */
static void
my_strcat (char* dest, char* src)
{
while (*dest) ++dest;
while (*src) *(dest++) = *(src++);
*dest = 0;
}
int
main()
{
char* a1 = malloc(100);
char* b1 = malloc(100);
strcpy (a1, "Vivek");
strcpy (b1, " Ratnavel");
my_strcat (a1, b1);
printf ("%s\n", a1); /* => Vivek Ratnavel */
free (a1);
free (b1);
return 0;
}
I have a string:
char * someString;
If I want the first five letters of this string and want to set it to otherString, how would I do it?
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Generalized:
char* subString (const char* input, int offset, int len, char* dest)
{
int input_len = strlen (input);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, input + offset, len);
return dest;
}
char dest[80];
const char* source = "hello world";
if (subString (source, 0, 5, dest))
{
printf ("%s\n", dest);
}
char* someString = "abcdedgh";
char* otherString = 0;
otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;
UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):
Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!
So char* someString; => "someString is a pointer to char".
Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.
That works with anything .. give it a go:
char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char
Some links:
How to interpret complex C/C++ declarations and
How To Read C Declarations
You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)
char *subString(char *someString, int n)
{
char *new = malloc(sizeof(char)*n+1);
strncpy(new, someString, n);
new[n] = '\0';
return new;
}
This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().
You can use snprintf to get a substring of a char array with precision:
#include <stdio.h>
int main()
{
const char source[] = "This is a string array";
char dest[17];
// get first 16 characters using precision
snprintf(dest, sizeof(dest), "%.16s", source);
// print substring
puts(dest);
} // end main
Output:
This is a string
Note:
For further information see printf man page.
You can treat C strings like pointers. So when you declare:
char str[10];
str can be used as a pointer. So if you want to copy just a portion of the string you can use:
char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);
This will copy 6 characters from the str1 array into str2 starting at the 11th element.
I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:
someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';
This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.
The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:
Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...
Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.
The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.
Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:
The strncpy function
strncpy was initially introduced into the C library to deal with fixed-length name fields in
structures such as directory entries. Such fields are not used in the same way as strings: the
trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter
5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded
strcpy,” and the Committee preferred to recognize existing practice rather than alter the function
to better suit it to such use.
The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.
I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.
char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
strncpy(substr, buff+start, len);
substr[len] = 0;
return substr;
}
strncpy(otherString, someString, 5);
Don't forget to allocate memory for otherString.
#include <stdio.h>
#include <string.h>
int main ()
{
char someString[]="abcdedgh";
char otherString[]="00000";
memcpy (otherString, someString, 5);
printf ("someString: %s\notherString: %s\n", someString, otherString);
return 0;
}
You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.
Doing it all in two fell swoops:
char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
char largeSrt[] = "123456789-123"; // original string
char * substr;
substr = strchr(largeSrt, '-'); // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size)
char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters
newStr[substringLength] = '\0'; // close the new string with final character
printf("newStr=%s\n", newStr);
free(newStr); // you free the memory
Try this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* substr(const char *src, unsigned int start, unsigned int end);
int main(void)
{
char *text = "The test string is here";
char *subtext = substr(text,9,14);
printf("The original string is: %s\n",text);
printf("Substring is: %s",subtext);
return 0;
}
char* substr(const char *src, unsigned int start, unsigned int end)
{
unsigned int subtext_len = end-start+2;
char *subtext = malloc(sizeof(char)*subtext_len);
strncpy(subtext,&src[start],subtext_len-1);
subtext[subtext_len-1] = '\0';
return subtext;
}