Why sprintf appends characters just before char array again? - c

int main () {
char str1[121];
char str2[4];
unsigned char x=255;
unsigned char y=2;
memset(str1, 0, 121);
memset(str2, 0, 4);
strncpy(str2, "jyot",4);
sprintf(str1,"%d-%d-%s", x,y,str2);
printf("%s",str1);
return(0);
}
Why is it printing 255-2-jyot-255-2?? Should sprintf automatically not append null character after writing last char array?

You are very lucky that your computer did not explode when it had to run this code.
This program is one huge UB. Your str2 is too short. Even if you copy (using strncpy only 4 chars the array does not have enough space to accommodate the trailing zero and strncpy does not copy the last zero.
Change it to:
char str2[5];
strcpy(str2, "jyot");
and delete the memset calls as they are not needed here.
Do not ignore warnings!!!! And compile using more modern standard which does not allow to call functions with no prototypes

Related

How to copy the string that remains after using strncpy

I am learning C and want to learn how I can copy the remaining characters leftover in the string after using strncpy. I would like to have the string Hello World broken down into two separate lines.
For example:
int main() {
char someString[13] = "Hello World!\n";
char temp[13];
//copy only the first 4 chars into string temp
strncpy(temp, someString, 4);
printf("%s\n", temp); //output: Hell
}
How do I copy the remaining characters (o World!\n) in a new line to print out?
The one thing you should learn about strncpy is never use this function.
The semantics of strncpy are counter-intuitive and poorly understood by most programmers. It is confusing and error prone. In most cases, it does not do the job.
In your case, it copies the first 4 bytes and leaves the rest of temp uninitialized. You might have known this, but still invoked undefined behavior by passing temp to printf as a string argument.
If you want to manipulate memory, use memcpy and memmove and be careful about null terminators.
As a matter of fact, the string "Hello world!\n" has 13 characters and a null terminator, requiring 14 bytes in memory. Defining char someString[13] = "Hello World!\n"; is legal but it makes someString not a C string.
#include <stdio.h>
#include <string.h>
int main() {
char someString[14] = "Hello World!\n";
char temp[14];
memcpy(temp, someString, 4); //copy only the first 4 chars into string temp
temp[4] = '\0'; // set the null terminator
printf("%s\n", temp); //output: Hell\n
strcpy(temp + 4, someString + 4); // copy the rest of the string
printf("%s\n", temp); //output: Hello World!\n\n
memcpy(temp, someString, 14); //copy all 14 bytes into array temp
printf("%s\n", temp); //output: Hello World!\n\n
// Note that you can limit the number of characters to output for a `%s` argument:
printf("%.4s\n", temp); //output: Hell\n
return 0;
}
You can read more about strncpy here:
https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html
https://devblogs.microsoft.com/oldnewthing/?p=36773
What is the best alternative to strncpy()?
First of all, char someString[13] , you don't have enough space for the string Hello World\n, since you have 13 characters but you need at least size of 14, one extra byte for the NULL byte, '\0'. You better off let the compiler decide the size of the array, wouldn't be prone to UB that way.
To answer your question, you can just use printf() to display the remaining part of the string, you only need to specify a pointer to the element you want to start at.
In addition, strncpy() doesn't NULL terminate tmp, you are gonna have to do that manually if you want functions like printf() or puts() to function properly.
#include <stdio.h>
#include <string.h>
int main(void)
{
char someString[] = "Hello World!\n";
char temp[14];
strncpy(temp,someString,4);
temp[4] = '\0'; /* NULL terminate the array */
printf("%s\n",temp);
printf("%s",&someString[4]); /* starting at the 4th element*/
return 0;
}
In your case you could try something like:
char temp2[13];
strncpy(temp2, &someString[4], 9);
By the way you are missing a semicolon:
char someString[13] = "Hello World!\n";
The think you can do is to push your pointer of n character and copy the size - n caractere:
size_t n = 4; // nunmber caractere to copy first
size_t size = 13; // string length
char someString[size] = "Hello World!\n";
char temp[size];
char last[size - n]; // the string that contain the reste
strncpy(temp, someString, n); // your copy
strncpy(last, someString + n, 13 - n); // copy of reste of the string

C program -special characters in output

Output of this program gives a special character in the beginning.Wat is the reason?
#include<stdio.h>
#include<conio.h>
#include<string.h>
main() {
int i, j,count=0,nl;
char str2[100];
char str1[100];
char str[100];
char init[8];
char final[8];
//clrscr();
printf("enter the bit string: ");
gets(str);
puts(str);
strcat(init,"10101010");
strcat(final,"10101010");
strcpy(str1,(strcat(init,str)));
strcpy(str2,(strcat(str1,final)));
puts(str2);
printf("%d",(strlen(str2)));
getch();
}
You can't use strcat() on init because it's uninitialized, you need at least the nul terminator, example
init[0] = '\0';
but I would recommend strcpy() instead,
strcpy(init, "10101010");
would not require the initialization metioned above, but would require an extra character.
But then you need one extra character for the nul terminator, i.e.
char init[9];
instead of char init[8].
Also, gets() is a deprecated function, because it has potential to overflow the buffer, you should be using fgets() instead, like
fgets(str, sizeof(str), stdin);
You need a NUL terminated string to use strcat
Change
char init[8];
char final[8];
to
char init[8] = "";
char final[8] = "";
And note that gets is deprecated, change to
fgets(str, sizeof str, stdin);
/* remove the trailing newline */
char *ptr = strchr(str, '\n');
if (ptr) *ptr = '\0';
strcat() must be used on initialized strings because before it can do its thing it must find the current string's end. Since init and final are supposed to be empty, its best if you use strcpy() instead.
Also, strings in C are null-terminated, which means theres always an additional symbol \0 at the end. Storing the string 10101010 actually takes 9 bytes. init and final can only take 8 bytes.
Also, you are trying to strcat(init, str). init is already full at this point, so any additional char you are trying to append to it is out of bound and overwriting the stack. This application will invoke undefined behaviour and probably crash. init must be big enough to hold the content of str plus 9 bytes.

C strcat() gives wrong appended string

I am appending a string using single character, but I am not able to get it right. I am not sure where I am making mistake. Thank you for your help in advance. The original application of the method is in getting dynamic input from user.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
int j;
char ipch=' ';
char intext[30]="What is the problem";
char ipstr[30]="";
printf("Input char: ");
j=0;
while(ipch!='\0'){
//ipch = getchar();
ipch = intext[j];
printf("%c", ipch);
strcat(ipstr,&ipch);
j++;
}
puts("\n");
puts(ipstr);
return;
}
Following is the output I am getting.
$ ./a.out
Input char: What is the problem
What is h e
p
oblem
change
strcat(ipstr,&ipch);
to
strncat(ipstr, &ipch, 1);
this will force appending only one byte from ipch. strcat() will continue appending some bytes, since there's no null termination character after the char you are appending. as others said, strcat might find somewhere in memory \0 and then terminate, but if not, it can result in segfault.
from manpage:
char *strncat(char *dest, const char *src, size_t n);
The strncat() function is similar to strcat(), except that
it will use at most n characters from src; and
src does not need to be null-terminated if it contains n or more characters.
strcat requires its second argument to be a pointer to a well-formed string. &ipch does not point to a well-formed string (the character sequence of one it points to lacks a terminal null character).
You could use char ipch[2]=" "; to declare ipch. In this case also use:
strcat(ipstr,ipch); to append the character to ipstr.
ipch[0] = intext[j]; to change the character to append.
What happens when you pass &ipch to strcat in your original program is that the function strcat assumes that the string continues, and reads the next bytes in memory. A segmentation fault can result, but it can also happen that strcat reads a few garbage characters and then accidentally finds a null character.
strcat() is to concatenate strings... so passing just a char pointer is not enough... you have to put that character followed by a '\0' char, and then pass the pointer of that thing. As in
/* you must have enough space in string to concatenate things */
char string[100] = "What is the problem";
char *s = "?"; /* a proper '\0' terminated string */
strcat(string, s);
printf("%s\n", string);
strcat function is used to concatenate two strings. Not a string and a character. Syntax-
char *strcat(char *dest, const char *src);
so you need to pass two strings to strcat function.
In your program
strcat(ipstr,&ipch);
it is not a valid statement. The second argument ipch is a char. you should not do that. It results in Segmentation Fault.

Why am I getting stack smashing detected when doing memcpy?

char test[]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,3);
printf("%s",test);
I'm trying to grasp how exactly memcpy works and this is the example I've written so far.
This gives output as abcdexyz&vjunkcharacters
and the following message.
*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]
What are the reasons behind this situation?
Root Cause:
char test[]={"abcde"};
Allocates enough memory space to store 5 characters only.
memcpy(test+5,test1,3);
Copies the data pointed by test1 beyond the allocated memory space.
Technically, writing beyond the bounds of an allocated memory in this fashion is Undefined Behavior, which means anything can happen.
What actually happens?
What actually happens here is memcpy copies characters beyond the allocated memory thus overwritting the NULL terminator which marks ends of your character array test.
Further, printf reads the contents from starting address of test till it encounters a random NULL thus printing out junk characters.
Solution:
You should ensure that destination buffer has enough memory allocated before you perform the memcpy. Since you intend to copy 3 characters, Your destination buffer test should be atleast:
5 + 3 + 1 byte for NULL terminator = 9 bytes
You can simply use:
char test[9]="abcde";
Your memcpy call does smash the stack, which is why you see that message. You're copying data past the end of your test array, which isn't allowed.
Doing it without an additional buffer
The most straight-forward approach, indeed, would be to avoid the copy:
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
printf("%s%s\n", a, b);
return 0;
}
Doing it with memcpy
memcpy copies n bytes from src to dest. You need to keep track of copying null termination bytes of the strings correctly yourself.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
memcpy(c, a, sizeof(a));
/* copy the content of b to where a ends (concatenate the strings) */
memcpy(c + sizeof(a) - 1, b, sizeof(b));
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
Doing it with strcpy and strcat
Note that there's a lot of pitfalls dealing correctly with the null termination of the strings when using memcpy. To simplify this procedure for strings you should do the following.
If these are indeed strings and not random bytes you should stick to the string functions of the standard library. This is how it's done.
#include <string.h>
#include <stdio.h>
int main() {
char a[] = "abcde";
char b[] = "xyz";
/* note that both strings add a '\0' termination */
char c[sizeof(a) + sizeof(b) - 1];
/* copy the content of a to c */
strcpy(c, a);
/* copy the content of b to where a ends (concatenate the strings) */
strcat(c, b);
/* note that the '\0' termination of the string is necessary to let
* functions like printf know where the string is over
*/
printf(c);
return 0;
}
On knowing the size of the strings
Concerning knowing the size of the buffer, note that you can usually not simply do sizeof(a_string). If you pass a character array to a function it decays to a pointer and this operation no longer returns the expected size of the array but the size of the pointer.
For strings you need to issue strlen(a_string) which scans for the occurance of the null termination and returns the length of the string (not including the termination).
As for character buffers containing random data (or empty buffers that need to be written to) this approach doesn't work either. You always need to pass the size of the buffer as an additional parameter.
Variable test1 is in memory 4 chars, 3 plus the ending string terminator. Try this:
char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);
The line memcpy(test+5,test1,3); does the following in plain words:
"start at the last element of array "test" and copy 3 characters from array "test1" to there", which basically writes 2 characters beyond the length of the array 'test'.
So if you just want to play around with 'memcpy' define a 3rd array:
char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);

Copying a part of a string (substring) in C

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;
}

Resources