I want to check if a char* points to a valid string...Can I check this variable...
char* c;
What I tried:
if(c == NULL) //c is not null
if(*c == '\0') //false
if(strlen(c) == 0) //exception
I think it is not possible to check a char* when it was not allocated and dont point to a valid string...
Truth is, you can't ever be sure a pointer is valid. Testing for NULL may give you certainty that it is invalid, but it doesn't guarantee any validity. That's one reason not to use this kind of thing in C++. A std::string is always in a valid state.
If the pointer is not NULL, there is no way of saying if the value of the pointer is valid or not.
c can point anywhere. This might be a null terminated string, a string without terminating null byte, any accessible binary data or any address that is not accessible. What exactly do you want to check for and why? If you want to differentiate between a valid string and a not-initialized, you would normally use NULL for the uninitialized case and check c==NULL. Accessing *c (strlen does this, too) is not OK if c is not a valid pointer. So a typical usecase would be like this:
// initializing to NULL
char *c = NULL;
// maybe setting value
if(condition)
c = strdup("mein string");
// cleanup
if(c != NULL) {
free(c);
c = NULL;
}
If you have an upper bound on the size of the string you expect:
char * c = new char[size];
then perhaps you can check if it terminates within the bound:
bool is_valid(char *c, size_t size) {
while (size--) if (*c) return true;
return false;
}
another way is encapsulating the char * within a class in the constructor, or to have a valid flag in such a class.
It depends on the O/S. Under Windows you have the IsBadXxxPtr() family of functions which will test for a pointer to valid memory, although they won't test if the pointer is to a valid instance of a particular type.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366713(v=vs.85).aspx
etc.
Related
I was asked to write a function that accepts a character array, a zero-based start position, and a length.
It should return a character array containing length characters (len) starting with the start character of the input array
#include<iostream>
#include<vector>
#include<iterator>
using namespace std;
char* lengthChar(char c[],int array_len, int start, int len)
{
char* v = new char[len];
if(start < 0 || len > array_len || (start + len - 1) >= array_len){
return NULL;
}
if((start + len) == start)
{
return v;
}
copy(&c[start], &c[len+start], &v[0]);
return v;
}
My question is when I call my function as
char* r = lengthChar(t,3, 1, 0);
Normally based on my implementation, it should return a pointer pointing to an empty array. However, I can't seem to verify this. When I do if(!r[0]), it doesn't detect it. I even did
char s[] = {};
char* tt = &s[0];
if(r[0] == *tt)
Still nothing. The strange thing is when I cout the value of r[0], nothing is printed. So I don't know what actually is return. How do I verify that it is empty?
Don't use if(!r[0]) to check if NULL was returned. You want to compare directly to NULL using if(!r) or if(r == NULL). This will tell you if the string is empty. Doing if(!r[0]) when you return NULL is undefined behavior so you definitely want to make sure the address is valid before you try and access what it points to.
Another thing to note is that in the case that you return NULL, you function has a memory leak. You need to move char* v = new char[len]; to after you decide if you are going to return NULL. You could call delete [] v; in the if statement, but that makes the code more brittle.
There are a few things going on here. Firstly, I would replace that
if((start+len) == start)
with just
if(len == 0) // if(!len) works too
And also note that you don't need to take the address of an index, so
&c[start] is the same thing as c + start
I would read http://www.cplusplus.com/reference/algorithm/copy/ to make sure you understand that the value being passed is an iterator.
But secondly, your char* v = new char[len] statement is invoking undefined behavior. When you call
new char[len];
You're merely telling the compiler that you want to give space to a new character array. Remember that std::cout is a function. It is going to detect a char array as a c string. This means that the char array needs to be null terminated. If it's not, you are truly just invoking undefined behavior because you're reading memory on places that have been allocated but not initialized.
When you call
if(!r[0])
This doesn't really mean anything at all. r[0] is technically initialized, so it is not a nullptr, but it doesn't have any data in it so it is going to evaluate to true with undefined behavior.
Now, if you want to make this more concrete, I would fill the array with zeros
char* v = new char[len];
memset(v, 0, len);
Now your char is a truly "empty" array.
I think it's just a misunderstanding of what an "empty" array actually means.
Finally, don't listen to the guys who say just use std::vector. They're absolutely right, it's better practice, but it's better to understand how those classes work before you pull out the real power of the standard library. Just saying.
I wanted to access character pointer ith element. Below is the sample code
string a_value = "abcd";
char *char_p=const_cast<char *>(a_value.c_str());
if(char_p[2] == 'b') //Is this safe to use across all platform?
{
//do soemthing
}
Thanks in advance
Array accessors [] are allowed for pointer types, and result in defined and predictable behaviors if the offset inside [] refers to valid memory.
const char* ptr = str.c_str();
if (ptr[2] == '2') {
...
}
Is correct on all platforms if the length of str is 3 characters or more.
In general, if you are not mutating the char* you are looking at, it best to avoid a const_cast and work with a const char*. Also note that std::string provides operator[] which means that you do not need to call .c_str() on str to be able to index into it and look at a char. This will similarly be correct on all platforms if the length of str is 3 characters or more. If you do not know the length of the string in advance, use std::string::at(size_t pos), which performs bound checking and throws an out_of_range exception if the check fails.
You can access the ith element in a std::string using its operator[]() like this:
std::string a_value = "abcd";
if (a_value[2] == 'b')
{
// do stuff
}
If you use a C++11 conformant std::string implementation you can also use:
std::string a_value = "abcd";
char const * p = &a_value[0];
// or char const * p = a_value.data();
// or char const * p = a_value.c_str();
// or char * p = &a_value[0];
21.4.1/5
The char-like objects in a basic_string object shall be stored contiguously.
21.4.7.1/1: c_str() / data()
Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
The question is essentially about querying characters in a string safely.
const char* a = a_value.c_str();
is safe unless some other operation modifies the string after it. If you can guarantee that no other code performs a modification prior to using a, then you have safely retrieved a pointer to a null-terminated string of characters.
char* a = const_cast<char *>(a_value.c_str());
is never safe. You have yielded a pointer to memory that is writeable. However, that memory was never designed to be written to. There is no guarantee that writing to that memory will actually modify the string (and actually no guarantee that it won't cause a core dump). It's undefined behaviour - absolutely unsafe.
reference here: http://en.cppreference.com/w/cpp/string/basic_string/c_str
addressing a[2] is safe provided you can prove that all possible code paths ensure that a represents a pointer to memory longer than 2 chars.
If you want safety, use either:
auto ch = a_string.at(2); // will throw an exception if a_string is too short.
or
if (a_string.length() > 2) {
auto ch = a_string[2];
}
else {
// do something else
}
Everyone explained very well for most how it's safe, but i'd like to extend a bit if that's ok.
Since you're in C++, and you're using a string, you can simply do the following to access a caracter (and you won't have any trouble, and you still won't have to deal with cstrings in cpp :
std::string a_value = "abcd";
std::cout << a_value.at(2);
Which is in my opinion a better option rather than going out of the way.
string::at will return a char & or a const char& depending on your string object. (In this case, a const char &)
In this case you can treat char* as an array of chars (C-string). Parenthesis is allowed.
I'm reading the 3rd edition of The C++ Programming Language by Bjarne Stroustrup and attempting to complete all the exercises. I'm not sure how to approach exercise 13 from section 6.6, so I thought I'd turn to Stack Overflow for some insight. Here's the description of the problem:
Write a function cat() that takes two C-style string arguments and
returns a single string that is the concatenation of the arguments.
Use new to find store for the result.
Here's my code thus far, with question marks where I'm not sure what to do:
? cat(char first[], char second[])
{
char current = '';
int i = 0;
while (current != '\0')
{
current = first[i];
// somehow append current to whatever will eventually be returned
i++;
}
current = '';
i = 0;
while (current != '\0')
{
current = second[i];
// somehow append current to whatever will eventually be returned
i++;
}
return ?
}
int main(int argc, char* argv[])
{
char first[] = "Hello, ";
char second[] = "World!";
? = cat(first, second);
return 0;
}
And here are my questions:
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
Related to the previous question, what should I return from cat()? I assume it will need to be a pointer if I must use new. But a pointer to what?
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
The latter; the method takes C-style strings and nothing in the text suggests that it should return anything else. The prototype of the function should thus be char* cat(char const*, char const*). Of course this is not how you’d normally write functions; manual memory management is completely taboo in modern C++ because it’s so error-prone.
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
In this exercise, yes. In the real world, no: like I said above, this is completely taboo. In reality you would return a std::string and not allocate memory using new. If you find yourself manually allocating memory (and assuming it’s for good reason), you’d put that memory not in a raw pointer but a smart pointer – std::unique_ptr or std::shared_ptr.
In a "real" program, yes, you would use std::string. It sounds like this example wants you to use a C string instead.
So maybe something like this:
char * cat(char first[], char second[])
{
char *result = new char[strlen(first) + strlen(second) + 1];
...
Q: How do you "append"?
A: Just write everything in "first" to "result".
As soon as you're done, then continue by writing everything in "second" to result (starting where you left off). When you're done, make sure to append '\0' at the end.
You are supposed to return a C style string, so you can't use std::string (or at least, that's not "in the spirit of the question"). Yes, you should use new to make a C-style string.
You should return the C-style string you generated... So, the pointer to the first character of your newly created string.
Correct, you should delete the result at the end. I expect it may be ignored, as in this particular case, it probably doesn't matter that much - but for completeness/correctness, you should.
Here's some old code I dug up from a project of mine a while back:
char* mergeChar(char* text1, char* text2){
//Find the length of the first text
int alen = 0;
while(text1[alen] != '\0')
alen++;
//Find the length of the second text
int blen = 0;
while(text2[blen] != '\0')
blen++;
//Copy the first text
char* newchar = new char[alen + blen + 1];
for(int a = 0; a < alen; a++){
newchar[a] = text1[a];
}
//Copy the second text
for(int b = 0; b < blen; b++)
newchar[alen + b] = text2[b];
//Null terminate!
newchar[alen + blen] = '\0';
return newchar;
}
Generally, in a 'real' program, you'll be expected to use std::string, though. Make sure you delete[] newchar later!
What the exercise means is to use new in order to allocate memory. "Find store" is phrased weirdly, but in fact that's what it does. You tell it how much store you need, it finds an available block of memory that you can use, and returns its address.
It doesn't look like the exercise wants you to use std::string. It sounds like you need to return a char*. So the function prototype should be:
char* cat(const char first[], const char second[]);
Note the const specifier. It's important so that you'll be able to pass string literals as arguments.
So without giving the code out straight away, what you need to do is determine how big the resulting char* string should be, allocate the required amount using new, copy the two source strings into the newly allocated space, and return it.
Note that you normally don't do this kind of memory management manually in C++ (you use std::string instead), but it's still important to know about it, which is why the reason for this exercise.
It seems like you need to use new to allocate memory for a string, and then return the pointer. Therefore the return type of cat would be `char*.
You could do do something like this:
int n = 0;
int k = 0;
//also can use strlen
while( first[n] != '\0' )
n ++ ;
while( second[k] != '\0' )
k ++ ;
//now, the allocation
char* joint = new char[n+k+1]; //+1 for a '\0'
//and for example memcpy for joining
memcpy(joint, first, n );
memcpy(joint+n, second, k+1); //also copying the null
return joint;
It is telling you to do this the C way pretty much:
#include <cstring>
char *cat (const char *s1, const char *s2)
{
// Learn to explore your library a bit, and
// you'll see that there is no need for a loop
// to determine the lengths. Anything C string
// related is in <cstring>.
//
size_t len_s1 = std::strlen(s1);
size_t len_s2 = std::strlen(s2);
char *dst;
// You have the lengths.
// Now use `new` to allocate storage for dst.
/*
* There's a faster way to copy C strings
* than looping, especially when you
* know the lengths...
*
* Use a reference to determine what functions
* in <cstring> COPY values.
* Add code before the return statement to
* do this, and you will have your answer.
*
* Note: remember that C strings are zero
* terminated!
*/
return dst;
}
Don't forget to use the correct operator when you go to free the memory allocated. Otherwise you'll have a memory leak.
Happy coding! :-)
When trying to delete/free character ptr without being processed completely by strtok_r, its giving me stack trace error.
I know that one cannot free/delete a strtok_r char ptr in a regular way, without completing the whole strings separation process by strtok_r func.
Can anyone tell me how to free a char ptr, when its under process by strtok_r?
char *data = new char[temp->size()+1];//temp is of type string
copy(temp->begin(),temp->end(),data);
data[temp->size()]='\0';
count = 0;
while(pointData != NULL)
{
if(count == 0)
pointData = strtok_r(data,":",&data);
else
pointData = strtok_r(NULL,":",&data);
if(count == 5)//some condition to free data
delete[] data;// this produces stack trace error
cout<<pointdata<<endl;
count++;
}
Because strtok_r is advancing "data" as it goes, which means that it is no longer pointing at the address of the allocation; you need to keep a "freedata" pointer or the like around:
char *data, *freedata;
freedata = data = new char[temp->size()+1];
// do yer stuffz here
delete[] freedata;
The context passed to strtok_r in the third argument should be a different pointer to the string you want to separate. Try:
char *context;
....
pointData = strtok_r(data,":",&context);
else
pointData = strtok_r(NULL,":",&context);
I don't believe you need to initialise it before you pass it in.
The only pointers you may ever pass to free are those obtained by malloc, or those obtained from functions which are specified to return a pointer to memory "as if" obtained by malloc. strtok_r does not return a pointer to a string "as if obtained by malloc", so you may not call free on it. If you read the specification for this function, it returns a pointer to character in your input string, which has been potentially modified to clobber a separator with a null terminator.
The following code attempts to put the contents of string c into arg[0].
const char **argv = new const char* [paramlist.size() + 2];
argv[0] = c.c_str();
This is another way to do it.
argv[0] = "someprogram"
I am noticing that later in my program, the second way works, but the first way causes an error. What could possibly be different? How could the first way be changed so that it works right?
This is where the problem occurs:
execvp(c.c_str(), (char **)argv);
If I change it to the following, then the problem doesn't occur. Why is that?
execvp(argv[0], (char **)argv);
In both ways you keep const char* pointers in argv[0]. So the only concern is whether pointers are valid and point to zero-terminated string.
"someprogram" pointer is valid and point to zero-terminated string during program execution.
c.c_str() pointer is guaranteed to be valid from the moment it is returned (by std::basic_string::c_str() function) to the moment string c is changed or destroyed. So if you access string c explicitly or implicitly with any non-const function (including its destructor) the pointer you stored into argv[0] will likely become invalid.
ADD:
Obviously to make argv[0] = c.c_str(); variant work correctly you have to just use argv only in the scope of std::string c (where c exist) and don't change c in any way after you make this assignment (argv[0] = c.c_str();).
You can use _strdup:
const char **argv = new const char* [paramlist.size() + 2];
argv[0] = _strdup(c.c_str());
_strdup allocates memory to store the copy of the string. When you are finished with the string, use free() to return the memory.
The _strdup function looks something like this:
char *_strdup (const char *s) {
char *d = (char *)(malloc (strlen (s) + 1));
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}