I've a simple question about string/char. I've tried to implement a basic system like this;
#include <stdio.h>
#include <string.h>
int main()
{
//I'll use 'char*' for socket receive buffer!
const char* input = "This is a test!";
char n[4];
strncpy(n, input, 4);
printf("%s\n%i\n", n, strlen(n));
return 0;
}
And I got this output:
Thisd0#
7
What's wrong? This is a simple as a for/while loop (IDK).
You still need to put a null-terminating char (\0) at the end.
char n[5] = { '\0' }; // Initializes the array to all \0
strncpy(n, input, 4);
Your n char needs to be 5 bytes big (4 characters + null-terminater). You're seeing gonk afterwards because there is no null-terminator \0.
Related
tl;dr
Why do I get different output every time I run this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
for (int i = 0; i < 21; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
But not this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
const char* _session = "ABCDEFGHIJ";
int _expectedSeq = 123;
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
for (int i = 0; i < 38; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
Question
Deep in our application code, I came across this:
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
Now, I need to write a (simpler) variant of this code:
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
Somehow, this doesn't work! What's weird is that the latter produces different results every time.
Thoughts
The former example only has a hex literal at the end. Is this masking the issue in the former's case?
Or, am I actually messing up my debug output, printf? (By the way, I got the & 0xff thing from Printing hexadecimal characters in C.)
Could it have something to do with using char instead of unsigned char? But then, why does the former case work?
The problem is that your string literal has an embedded NUL byte, and that marks the end of the string as far as sprintf is concerned. So your call is identical to:
sprintf(login,
"\x15",
_user,
_password);
And that writes into the login array only two bytes: 0x15 0x00.
There are several approaches to solve this mixing of bytes and characters. My choice would be something along the lines of:
memcpy(login, "\x15\x00\x01", 3);
sprintf(login + 3,
"%-8s%-10s",
_user,
_password);
The call to memcpy takes as parameter the number of bytes, so it is immune to the embedded NUL problem.
But note that sprintf automaticall adds a NUL byte at the end of the output string, so you actually need 22 bytes: 3 + 8 + 10 + 1 = 22:
char login[22];
Your issue is that second format string contains a null character (\x00) which terminates it prematurely. Change the string to use %c instead and have a null character printed there.
After trying for about 1 hour, my code didn't work because of this:
void s_s(string const& s, char data[10])
{
for (int i = 0; i < 10; i++)
data[i] = s[i];
}
int main()
{
string ss = "1234567890";
char data[10];
s_s("1234567890", data);
cout << data << endl;//why junk
}
I simply don't understand why the cout displays junk after the char array. Can someone please explain why and how to solve it?
You need to null terminate your char array.
std::cout.operator<<(char*) uses \0 to know where to stop.
Your char[] decays to char* by the way.
Look here.
As already mentioned you want to NUL terminate your array, but here's something else to consider:
If s is your source string, then you want to loop to s.size(), so that you don't loop past the size of your source string.
void s_s(std::string const& s, char data[20])
{
for (unsigned int i = 0; i < s.size(); i++)
data[i] = s[i];
data[s.size()] = '\0';
}
Alternatively, you can try this:
std::copy(ss.begin(), ss.begin()+ss.size(),
data);
data[ss.size()] = '\0';
std::cout << data << std::endl;
You have ONLY allocated 10 bytes for data
The string is actually 11 bytes since there is an implied '\0' at the end
At a minimum you should increase the size of data to 11, and change your loop to copy the '\0' as well
The function std::ostream::operator<< that you are trying to use in the last line of the main will take your char array as a pointer and will print every char until the null sentinel character is found (the character is \0).
This sentinel character is generally generated for you in statements where a C-string literal is defined:
char s[] = "123";
In the above example sizeof(s) is 4 because the actual characters stored are:
'1', '2', '3', '\0'
The last character is fundamental in tasks that require to loop on every char of a const char* string, because the condition for the loop to terminate, is that the \0 must be read.
In your example the "junk" that you see are the bytes following the 0 char byte in the memory (interpreted as char). This behavior is clearly undefined and can potentially lead the program to crash.
One solution is to obviously add the \0 char at the end of the char array (of course fixing the size).
The best solution, though, is to never use const char* for strings at all. You are correctly using std::string in your example, which will prevent this kind of problems and many others.
If you ever need a const char* (for C APIs for example) you can always use std::string::c_str and retrieve the C string version of the std::string.
Your example could be rewritten to:
int main(int, char*[]) {
std::string ss = "1234567890";
const char* data = ss.c_str();
std::cout << data << std::endl;
}
(in this particular instance, a version of std::ostream::operator<< that takes a std::string is already defined, so you don't even need data at all)
I am wondering why the display of the char array is short few characters. However, when I use length+2, all characters are displayed. I am not sure what I am doing wrong. Your help will be appreciated. I am using Dev-C++
#include <iostream>
#include <string.h>
using namespace std;
char *Appendstring(char *a, char *b, char *c, char *d, char *e) // will append b to the end of a
{
// char *buffer = new char[strlen(a)+strlen(b)+1];
static char buffer[90];
char *p=buffer;
while(*p++=*a++); // Copy a into buffer
while(*p++=*b++); // Copy b into buffer right after a
while(*p++=*c++); // Copy c into buffer right after b
while(*p++=*d++); // Copy d into buffer right after c
while(*p++=*e++); // Copy e into buffer right after d
*p=0; // Null-terminate the string
return buffer;
}
int main ()
{
char *new_string;
int length;
char *str="Because";
char *add="it has been";
char *addstr1="very warm";
char *addstr2="lately";
char *addstr3="Summer is coming!";
length=strlen(str)+strlen(add)+strlen(addstr1)+strlen(addstr2)+strlen(addstr3)+1; //total length of the new string
new_string=Appendstring(str, add, addstr1, addstr2, addstr3);
for (int i=0; i<=length+2; i++) //Why do I need to do length+2 to have all characters displayed???
cout<<new_string[i];
return 0;
}
Because your string copying code is wrong. It copies the null bytes at the end of the strings too.
Try this
while (*a) // Copy a into buffer
*p++ = *a++;
while (*b) // Copy b into buffer
*p++ = *b++;
etc.
You are actually printing out 4 non-printable characters in your for loop.
The total number of printable characters in your strings is 50. Your length variable is 51 because you add 1 to it. Then the for loop is from 0 to 51+2, which will print out a total of 54 characters.
But, since your Appendstring function is incorrectly embedding the null bytes as John describes, you have 4 null characters in the string. When you stream a null character to cout, it is non-printable and nothing is displayed.
Once you change the Appendstring function as John describes, then you will not need to add 1 to length and the for loop should be
for (int i=0; i<length; i++)
I am trying to converts a sequence of multibyte characters to a corresponding sequence of wide characters using the mbstowcs_s function. But I keep having the following heap corruption problem. Can anyone tell me how to fix that?
Here is a sample code. When debugging, it is always the line delete wc_name causing the problem. I know it shouldn't be it.
#include <Windows.h>
#include <iostream>
#include <string>
int main (int argc, char *argv[]) {
size_t returnValue; // The number of characters converted.
const size_t sizeInWords = 50; // The size of the wcstr buffer in words
const char* c_name = "nanana"; // The address of a sequence of characters
wchar_t *wc_name = new wchar_t(50);
errno_t err = mbstowcs_s(&returnValue, wc_name, sizeInWords,
c_name, strlen(c_name) );
wcout << wc_name << endl;
delete wc_name;
return 0;
}
wchar_t *wc_name = new wchar_t(50); should be wchar_t *wc_name = new wchar_t[50]; to allocate an array. And corresponding delete wc_name should be delete[] wc_name;. BTW, if you know the size of the array at compile time itself, there is no need for dynamic memory allocation. You can simply do wchar_t wc_name[50];.
Hi I'm trying to tokenize a string by loading an entire file into a char[] using fread.
For some strange reason it is not always working, and valgrind complains in this very small sample program.
Given an input like test.txt
first
second
And the following program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
//returns the filesize in bytes
size_t fsize(const char* fname){
struct stat st ;
stat(fname,&st);
return st.st_size;
}
int main(int argc, char *argv[]){
FILE *fp = NULL;
if(NULL==(fp=fopen(argv[1],"r"))){
fprintf(stderr,"\t-> Error reading file:%s\n",argv[1]);
return 0;
}
char buffer[fsize(argv[1])];
fread(buffer,sizeof(char),fsize(argv[1]),fp);
char *str = strtok(buffer," \t\n");
while(NULL!=str){
fprintf(stderr,"token is:%s with strlen:%lu\n",str,strlen(str));
str = strtok(NULL," \t\n");
}
return 0;
}
compiling like
gcc test.c -std=c99 -ggdb
running like
./a.out test.txt
thanks
Your buffer size should be filesize + 1. The +1 is for the null char.
filesize = fsize(argv[1]);
char buffer[filesize + 1];
Also fread does not put a \0 at the end of the string. So you'll have to do it yourself as:
fread(buffer,sizeof(char),filesize,fp);
buffer[filesize] = 0;
From this site:
int main(int argc, char* argv[])
{
std::string str = "The quick brown fox";
// construct a stream from the string
std::istringstream stream(str);
// use stream iterators to copy the stream to the vector
// as whitespace separated strings
std::istream_iterator<std::string> it(stream), end;
std::vector<std::string> results(it, end);
// results = ["The", "quick", "brown", "fox"]
}
SO much easier than dealing with those nasty C-strings that keep banging you on the head.
And you know what's great about using higher-order methods ? It takes less screen estate and is easier to understand.
buffer is not null-terminated. You need to make it one byte larger than the size of the file, and you need to set the last byte to be \0.
Your buffer must be filesize + 1 and you will also need to set the terminating 0:
int size = fsize(argv[1]);
char buffer[size + 1];
buffer[size] ='\0';
Also, you should probably allocate the buffer on the heap instead of the stack...
Your buffer is too small. Try this:
int fileSize = fsize(argv[1]);
char buffer[fileSize + 1];
buffer[fileSize] = 0;
right before your call to fread.