I' m trying to understad the work with a pointers. So I've wrote a test program where name is split into labels by removing the separating dots. Each label is represented as a length/data pair as follows:
google.ru represents as "x\06googlex\02ru"
I get signal SIGABRT when i returned from my test function
I guess it's caused with my bad work with pointer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(unsigned char* dns, unsigned char* host);
int main(int argc, const char * argv[])
{
unsigned char host[]="google.ru";
unsigned char* dnsTest=(unsigned char*)malloc(20);
if(dnsTest==NULL)
{
exit(1);
}
test(dnsTest, host);
printf("%s", dnsTest);
free(dnsTest);
return 0;
}
void test(unsigned char* dns, unsigned char* host)
{
strcat((char*)host, ".");
int lock=0;
for(int i=0; i<strlen((char *)host);i++)
{
if(host[i]=='.')
{
*dns=i-lock;
dns++;
for(;lock<i; lock++)
{
*dns=host[lock];
dns++;
}
lock++;
}
}
*dns='\0';
}
Since you tagged c++ as well, you can use new \ delete instead of malloc \ free. New will call constructor (when you will learn classes it will be useful), and new return to you exact type, so no need to cast (and casting is almost always a bad idea)
Then assertion after memory allocation with new will be redundant:
if(dnsTest==NULL)
since c++ new will throw an exception by default.
If you go ahead, you can use std::string - its much more simple than c null terminated strings (but not for the task of understanding pointers).
Every other comments (about redundant strlen usage and absence of '\0' symbol) is correct too, but I want to give you two advices, how to grasp pointers.
First - read K&R - it's the Bible.
Second - if you use Microsoft Visual Studio, you can compile your code in Debug mode, and use Memory View tab. Visual Studio compiler place some magic number inside memory (link) at debug mode. They can help you with understanding where you addressing unallocated memory or how exactly your memory layout looks like.
Related
So I've been trying to convert integer values to wchar_t*. This is the test I run so I could simplify it as much as I can.
int test=123;
wchar_t *testc[12][12];testc[0][0]=L"hello";
_itow(test,testc[0][0],10);
wcout<<testc[0][0];
This code right here compiles but also gives me the Not Responding error of doom.
What is VERY strange for my understanding is why this
int test=123;
wchar_t *testc[12][12];testc[0][0]=L"hello";
_itow(test,testc[1][0],10);
wcout<<testc[0][0]<<testc[1][0];
Works without any problem, and showing the output "hello123" just as intended.
Any idea why this happens?
My project has some occurrences similar to the first code shown (except the wcout part), thus I want to understand why they give me the Not Responding state.
Main issue with your code is not allocating memory for testc[1][0].
Also it will be better to use standard c++ functions like std::to_wstring instead of _itow.
So here is sample code for your problem :
int main()
{
int test=123;
wchar_t *testc[12][12];
testc[0][0]=L"hello";
testc[1][0] = new wchar_t[4];
std::wstring temp = std::to_wstring(123);
for(int i=0;i<temp.length();i++)
{
testc[1][0][i] = temp[i];
}
wcout<<testc[0][0]<<testc[1][0];
return 0;
}
This is just sample code and i am assuming in your program you are taking care of memory allocation and deallocation
I am trying to concatenate two char arrays using the function strcat(). However the program crashes.
#include <cstdio>
#include <cstring>
int main() {
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *file_bk_path = strcat(strdup(file_path), ".bk");
printf("%s\n", file_bk_path);
return 0;
}
The strangest thing to me is that the program indeed produces an output before crashing:
D:/MyFolder/YetAnotherFolder/test.txt.bk
What is the reason for this problem and how it can be fixed?
Error state is reproduced in Windows (MinGW 7.2.0).
strdup is creating new memory for you to hold a duplicate of the string. The memory is only as long as strlen(file_path) + 1. You then try to add an extra 2 characters into memory that you don't own. You will go out of range of the memory created and create some undefined behaviour. It might print because setting the memory and printing the first part could be happening correctly, but it is undefined and anything can happen. Also note, in strdup you need to call free on the memory it creates for you, or you are going to leak some memory.
Here is a much simpler way to do this, use a std::string:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
std::string file_bk_path = std::string(file_path) + ".bk";
std::cout << file_bk_path << "\n";
Here is a live example.
If it absolutely needs to be in C-style then you are better off controlling the memory yourself:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *bk_string = ".bk";
char *file_bk_path = malloc((strlen(file_path) + strlen(bk_string) + 1)*sizeof(char));
if (!file_bk_path) { exit(1); }
strcpy(file_bk_path, file_path);
strcat(file_bk_path, bk_string);
printf("%s\n", file_bk_path);
free(file_bk_path);
Here is a live example.
As mentioned in the comments and answers, strdup mallocs the length of your path string, plus an extra cell for the string end character '\0'. When you concatenate to this two characters writing after the allocated area.
Following #Ben's comments, I'd like to elucidate some more:
To be clear strcat adds a delimiter, but this is already after the memory you were allocated.
In general unless you specifically hit no-no addresses, the program will probably run fine - in fact this is a common hard to find bug. If for example you allocate some more memory right after that address, you will be deleting said delimiter (so printing the string will read further into the memory.
So in general, you may be OK crash wise. The crash (probably) occurs when the program ends, and the OS cleans up the memory you forgot to free yourself - That extra cell is a memory leak, and will cause the crash. So you do get a full print, and only after a crash.
Of course all of this is undefined behavior, so may depend on the compiler and OS.
I'm writing a Win32 console application in Visual Studio 2010.
Consider one function that take two char* as parameters.
Following is prototype of function:
void WriteApplicationFile(char *mappname,char* MessageString)
{
//Do some File related stuffs.
}
Now the following calls are working perfectly:
WriteApplicationFile("FirstOne", "Append Me");
WriteApplicationFile("FirstOne", "Append Another");
But if I try the same thing with some character array thing this will give me assertion, and throw me on assembly.
The following code is not working:
char * LocalBuffer = new char[100];
sprintf(LocalBuffer,"Number of jobs in Queue %d",JobsCount);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer);
LocalBuffer = NULL;
//Work fine.
//...
LocalBuffer = new char[100];
sprintf(LocalBuffer,"Log file name %s",LogFileCharName);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer); // I got assertion here..
LocalBuffer = NULL;
Where am I going wrong?
One more thing is that I want to handle all assertion and bugs with try-catch block. How would I do this?
If use new[] you must use delete[], not free() or delete. Replace:
free(LocalBuffer);
with:
delete[] LocalBuffer;
There appears to be no reason to be dynamically allocating memory. The size of the buffer is a compile time constant, is not large (no stack overflow) and the buffer appears to not be required to live beyond the scope in which it was allocated.
As this is c++ strongly suggest using std::string which will handle dynamic memory management for you and std::ostringstream which is typesafe and avoids specification of fixed sized buffers instead of sprintf():
#include <sstream>
#include <string>
std::ostringstream out;
out << "Number of jobs in Queue " << JobsCount;
const std::string s(out.str());
If access to a c-style string is required use std::string::c_str().
Additionally, the argument types of WriteApplicationFile() are char*, not const char*, so passing a string literal to the function would be causing undefined behaviour if the function modifies the arguments.
First, are you programming in C or in C++. The code you present
looks like C, but you speak of a try/catch block, which can only
be C++.
In C++, use std::ostringstream and std::string. Any other
solution is simply incorrect.
In C, you should use snprintf, instead of sprintf. It is
almost impossible to use sprintf safely. (How many characters
are in LogFileCharName, for example.) And don't use dynamic
allocation when you don't have to. (That holds for C++ as
well; there should be no new or delete (nor malloc nor
free) in the code you show.
As to what is going wrong, there are at least two possible
problems in the code you show: you're allocating memory with
new[], but freeing it with free (undefined behavior), and
you're not checking the length of LogFileCharName before
calling sprintf, so you could be overwriting the end of the
buffer.
The set functions' idea:
First argument is a reference, allocates space to hold copy of testing, sets str member of beany to point to the new block, copies testing to new block, and sets ct member of beany.
Problem:
1) Line that contains:
for (int i = 0; i < temp.length(); i++)
Error:expression must have a class
type
2) Line that contains:
temp[i] = cstr[i];
Error: expression must have
pointer-to-object type
3) overload of function show() for stringy type can't find matching function signature due to presence of const
Very new to these concepts, could someone explain the reason for the errors?
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cctype>
struct stringy {
char * str; //points to a string
int ct; //length of string(not counting '\0')
};
void set(stringy & obj, char cstr);
void show(const stringy & obj, int times=1);
void show(const char * cstr, int times = 1);
int _tmain(int argc, _TCHAR* argv[])
{
string beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing);
show(beany);
show(beany, 2);
testing[0] = 'D';
testing[1] = 'u';
show(testing);
show(testing, 3);
show("Done");
return 0;
}
void set(stringy & obj, char cstr)
{
char * temp = new char[cstr];
obj.str = temp;
for (int i = 0; i < temp.length(); i++)
temp[i] = cstr[i];
}
void show(const stringy & obj, int times)
{
for (int i = 0; i < times; i++)
cout << obj.str;
}
void show(const char * cstr, int times)
{
for (int i = 0; i < times; i++)
cout << cstr;
}
I hope you won't take this personally... but this code has so many errors on so many logical levels that in my opinion it's simply FUBAR.
Please do yourself a favor and start by reading a C++ book. A list of good ones can be found here and you can also find decent resources for free on the internet.
C++ is not a language that you (or anyone else indeed) can hope to learn by just typing it some characters and looking at what happens... that is simply just a suicidal approach to C++.
EDIT:
After doing some googling seems indeed that you are following a book. From a few excerpts I found on the net seems a book that is teaching programming using C++. I don't think this is a good idea because C++ is too complex and apparently illogical to be the first language for a programmer, also it's very very easy to get programs that compile fine and that will just drive you crazy when you run them. There are some gurus however that think this is a viable approach.
Your book is indeed listed, not because is good, but just because the title is close to one of a good book. Probably just a marketing trick to sell it.
EDIT2:
I felt a bit sorry for being so rude when your only fault is choosing a bad book to learn C++. To try compensate here is my attempt to tell all problems I think are present in your C++ code:
1. Learn standard C++
#include "stdafx.h"
If you are learning C++ then you should try to put aside everything that microsoft tells you about the language. Standard C++ has never been important for microsoft; probably because portable code is more a threat to microsoft than good for them.
Once you know C++ (but only then) it's ok to write microsoft-specific code if that is your platform. But it's important that you know what is ms-only and what is C++. There are cases in which the difference is just plain stupid and not worth considering (e.g. for scoping or handling of allocation failures) but sometimes you actually MUST use their variation of the language to work with windows.
MS development tools are great (or at least they were... I was simply in love with VC6 for example) but they will always try to trick you into writing unportable code. This is done both in IDEs and in the windows API examples. Don't fall into those traps: write portable code unless you have a real need for platform-specific code and be always be conscious about it.
2. Don't pollute the global namespace
using namespace std;
This is a bad idea. Even if it's a bit annoying it's much better if you get used to write std:: before standard functions. The reasons are because of the complex rules of name lookup and overload resolution that are present in the language and because of all the names that you are getting into your namespace without being conscious about them.
Saving typing time is not really that important in C++ (it's important in PERL if you are writing a throw-away script... but not for general programs). Much more important to help who is reading your code (and this includes yourself) and using std:: does that.
3. Use a proper main declaration
This is again about not falling in stupid MS traps. The correct declaration for main is
int main(int argc, const char *argv[])
You should never use anything else when learning about C++. If the MS tool you are using doesn't allow you to write a correct declaration (that wouldn't be a surprise) then just drop it on the floor now and learn C++ using a tool that shows some respect for the standard instead. Once you know C++ you can begin use non-portable stuff if you really need but knowing that's non-portable stuff.
Mingw is a good free C++ compiler for windows and there are free good IDEs if you like them. Over the years I got to like more using a good editor like emacs (vim is also ok, I used it for many years) and a command line compiler, but mainly because I work in a variety of languages on several different operating systems and no single IDE can cover all that. I want to put low level knowledge (how to copy a piece of text, how to search for a string, how to ask to completion, how to open another file) at a finger level and not having to think consciously in which IDE I am just to find the proper command. You cannot really play Chopin if you've to think every time to where G# is on the keyboard.
May be I'm just old, however... ;-)
4. Pick a reasonable naming convention
struct stringy {
char * str; //points to a string
int ct; //length of string(not counting '\0')
};
In your code your are naming a class stringy. It's better if you get used to what is the most common naming convention in C++ for classes, that is having it named Stringy instead.
The standard C++ library is not following this convention but those classes will always be prefixed by std:: anyway.
My advice is also to NOT use the idea of system hungarian notation of calling variables depending on the C++ type (like iIndex, sFileName) that is sometimes present in MS documentation. That idea doesn't scale up and simply means you will use bad names for all your variables.
5. Problems with set function
void set(stringy & obj, char cstr)
{
char * temp = new char[cstr];
obj.str = temp;
for (int i = 0; i < temp.length(); i++)
temp[i] = cstr[i];
}
In this function there are several errors:
You want to pass a char * not a char. A char holds the room for a single character and instead you want to initialize your stringy instance with a sequence of characters. In C++ you can use a char pointer for that because there is a specific support for char sequences in memory that are closed with the special ascii char NUL (note the single "L", the ASCII NUL character in C++ is spelled '\0' and is not to be confused with the NULL pointer). C++ preferred way for handling sequences of characters is actually the std::string standard class, but NUL-terminated sequences of characters are also fully supported for backward-compatibility with C.
A pointer is however just the address of a charater... that character will be followed by other characters until you find the closing '\0' but a pointer has no length member (actually has no members at all, it's a primitive type like int or double).
To know the lenght of a sequence of characters that has been passed using a pointer there is the standard function strlen (that returns the number of characters in the sequence excluding the terminating '\0'). So your code should probably be something like:
void set(stringy & obj, char *cstr)
{
char * temp = new char[1 + strlen(cstr)];
obj.str = temp;
strcpy(obj.str, cstr);
}
I've been using also the standard function strcpy that does the copy of a char sequence including the end '\0' marker. A possibile implementation of strcpy (here just to show the idea of '\0'-terminated strings) is the following:
char *mystrcpy(char *dest, const char *src)
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return dest;
}
6. Memory allocation
The stringy class is badly designed (in C++ there isn't any big difference between struct and class: just what is the default for visibility). To be specific construction and destruction are not handled where they should be (inside the stringy class), and for a class designed this way also assignment and copy construction must be handled or forbidden.
As a consequence your program is simply forgetting deallocation leaking memory (normally not a serious issue for main, but it's important to understand the problem).
Hopefully this problem is just because the book didn't arrive yet to explain those concepts.
Anyway I find it strange a book that talks about new[] but not about delete[] (may be there is a reason that your book is not listed as a good book).
A properly implemented stringy should IMO look something like:
struct stringy
{
int size; // Number of characters EXCLUDING ending '\0'
char *ptr; // Pointer to first character
stringy(const char *s = "")
: size(strlen(s)), ptr(new char[1 + size])
{
strcpy(ptr, s);
}
~stringy()
{
delete[] ptr;
}
stringy(const stringy& other)
: size(other.size), ptr(new char[1 + size])
{
strcpy(ptr, other.ptr);
}
stringy& operator=(const stringy& other)
{
char *newptr = new char[1 + other.size];
strcpy(newptr, other.ptr);
delete[] ptr;
ptr = newptr;
size = other.size;
return *this;
}
};
temp is a const char*. That type does not provide any kind of length facilities- it is not an object and does not have a length() member method. Use a std::string- that is what it is for.
Below code crash in VS 2010 when you compile with following flag and if you add /GF- or remove the opimization flag they don't crash. The crash occur at assembly code which translate 'if( path[i] == '/' )'. I like to understand the optimization that compiler does here and lead to crash. Looking forward for some pointers.
-Karthik
cl.exe /MD /O2 test.c
// Test.c
#include <stdio.h>
#include <string.h>
void testpath(char* path, int bufsiz)
{
int i;
printf("%p\n", path);
for( i=0; i < strlen(path); i++ ) {
if( path[i] == '/' ) {
path[i] = '\\';
}
}
}
int main()
{
const char* path = "testexport.prj";
char *path1 = "testexport.prj";
printf("%p\n", path);
printf("%p\n", path1);
testpath(path, 1024);
}
Trying to modify the contents of a string literal invokes Undefined Behaviour.
From ISO C99 (Section 6.4.5/6)
It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined
From ISO C++-98 (Section 2.13.4/2)
Whether all string literals are distinct(that is, are stored in non overlapping objects) is implementation defined. The effect of attempting to modify a string literal is undefined.
On most implementations (including MSVC) this results to crash of your application.
You try to modify a string literal, that's undefined behavior.
const char* path = "testexport.prj";
testpath(path, 1024);
// then later:
void testpath(char* path, int bufsiz)
{
int i;
for( i=0; i`<`strlen(path); i++ ) {
if( path[i] == '/' ) {
path[i] = '\\';// <<<<<< UB here
}
}
string literals are usually stored in read-only memory, so on your implementation an attempt to modify a string literal results in access violation that crashes your program.
We have an application where in VC6.0 there appears to be a bug in string pooling. Two different strings appear to "pool" to one string, causing a crash. This crash does not occur in VS2010. OR if /Zi is used in VS6.0 instead of /ZI. Just wondering if the default in VS6.0 is to use string pooling and not the default in VS2010. In which case it could be that the string pooling bug still exists. If there are MANY strings which are near identical, the working theory I have (yet to be vetted) is that there is a hash collision going undetected in the string pooling, which eliminates one of the two strings. This would be visible in the generated ASM code when looking at the pointers for two nearly similar strings.
In our case we are not modifying strings in VC6.0, just referencing them.