Could anyone tell me what is wrong with this code?
for(int i=0;i<4;i++)
{
long int a = strtol(strtok("1-2-3-4","-"),(char**)NULL,10);
cout << a <<endl
}
I'm running on Solaris Unix. It's giving me a segmentation fault.
The fault is in strtol().
The error is with the strtok call, not with strtol. You can't call strtok on a string literal, since it's going to try to modify the string. Modifying a string literal causes undefined behaviour in C++.
The problems are legion.
I would expect that the core dump is because the string "1-2-3-4" is stored in read-only memory, so when strtok() modifies it (to isolate the first token), the program crashes. You say the crash is in strtol(); that would suggest that the return value from strtok() is NULL.
The first call to strtok() uses the string as an argument; the second call passes NULL in its place to indicate 'continue where you left off last time'. As written, if the string was modifiable, then you'd parse 1 four times.
This is closer to correct (though untested):
char input[] = "1-2-3-4";
char *data = input;
for (int i = 0; i < 4; i++)
{
char *token = strtok(data, "-");
if (token != 0)
{
long int a = strtol(token, NULL, 10);
cout << a << endl;
}
data = NULL;
}
In general, you need to do error detection from strtol(); further, doing so is quite fraught. However, with the sample string, you would not have to worry about that.
As the problem is already discussed, I'd like to show an alternate approach :
#include <stdio.h>
#include <string.h>
int main ()
{
long int a;
char str[] ="1-2-3-4";
char * pch;
pch = strtok (str,"-");
while (pch != NULL)
{
a = strtol(pch,(char**)NULL,10);
cout << a <<endl;
pch = strtok (NULL, "-");
}
return 0;
}
Related
I have built my own functions of strlen and strdup.
When i use my strdup in the first time it's okay, i close the window, run it again, then in the end of the program after the return 0 from the main the program crashes. VS just says that it triggered a breakpoint.
#include "stdafx.h"
#include <iostream>
using namespace std;
int MyStrlen(const char* str);
char* MyStrdup(const char* str);
int main()
{
char *s1 = "Hello World!";
char *s2 = MyStrdup(s1);
cout << s1 << " , " << s2 << endl;
system("pause");
return 0;
}
int MyStrlen(const char* str)
{
register int iLength = 0;
while (str[iLength] != NULL)
{
iLength++;
}
return iLength;
}
char* MyStrdup(const char* str)
{
char* newStr;
int strLength = MyStrlen(str);
newStr = new char(strLength+1);
for (register int i = 0; i < strLength; i++)
{
newStr[i] = str[i];
}
newStr[strLength] = NULL;
return newStr;
}
Can someone note the place that makes it crash? I think it's a memory leak maybe.
Also, can you note things to improve in the code? For my learning purpose
EDIT: Thanks, I don't know why I used () instead of [] to define my new char[]. That was a memory leak or overwrite after all.
The "new" statement for an array should be with square brackets:
newStr = new char[strLength+1];
When you do
new char(c)
It allocates a single character and copies the character c into it.
When you do
new char[n]
it allocates memory for n characters
The expression new char(strLength+1) allocates a single character, and initializes it to strLength + 1. That of course means you will write out of bounds and have undefined behavior when you copy the string.
You should use new char[strLength + 1] instead, to allocate an "array" of characters.
On an unrelated note, while the terminating character in a string is commonly called the null character, it's not actually a null pointer (which is what NULL is for). Not that it really matters since in C++ NULL is a macro that expands to 0, but you should probably be explicit and use '\0' anyway (it gives more context for future readers).
I have string like this 1-2,4^,14-56
I am expecting output 2-3,5^,15-57
char input[48];
int temp;
char *pch;
pch = strtok(input, "-,^");
while(pch != NULL)
{
char tempch[10];
temp = atoi(pch);
temp++;
itoa(temp, tempch, 10);
memcpy(pch, tempch, strlen(tempch));
pch = strtok(NULL, "-,^");
}
After running through this if I print input it prints only 2 which is first character of the updated string. It does not print all characters in the string. What is the problem with my code?
For plain C, use the library function strtod. Other than atoi, this can update a pointer to the next unparsed character:
long strtol (const char *restrict str, char **restrict endptr, int base);
...
The strtol() function converts the string in str to a long value. [...] If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr.
Since there may be more than one 'not-a-digit' character between the numbers, skip them with the library function isdigit. I placed this at the start of the loop so it would not accidentally convert a string such as -2,3 to -1,4 -- the initial -2 would be picked up first! (And if that is a problem elsewhere, there is also a strtoul.)
Since it appears you want the result in a char string, I use sprintf to copy the output into a buffer, which must be large enough for your possible input plus extra characters caused by a decimal overflow.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
int main (void)
{
char *inputString = "1-2,4^,14-56";
char *next_code_at = inputString;
long result;
char dest[100], *dest_ptr;
printf ("%s\n", inputString);
dest[0] = 0;
dest_ptr = dest;
while (next_code_at && *next_code_at)
{
while (*next_code_at && !(isdigit(*next_code_at)))
{
dest_ptr += sprintf (dest_ptr, "%c", *next_code_at);
next_code_at++;
}
if (*next_code_at)
{
result = strtol (next_code_at, &next_code_at, 10);
if (errno)
{
perror ("strtol failed");
return EXIT_FAILURE;
} else
{
if (result < LONG_MAX)
dest_ptr += sprintf (dest_ptr, "%ld", result+1);
else
{
fprintf (stderr, "number too large!\n");
return EXIT_FAILURE;
}
}
}
}
printf ("%s\n", dest);
return EXIT_SUCCESS;
}
Sample run:
Input: 1-2,4^,14-56
Output: 2-3,5^,15-57
There are two major problems with this code:
First of all,
pch = strtok(input, ",");
When applied to the string 1-2,4^,14-56 will return the token 1-2.
When you call atoi("1-2") you'll get 1, which gets converted to 2.
You can fix this by changing the first strtok to pch = strtok(NULL, "-,^");
Second of all, strtok modifies the string, which means that you lose the original delimiter found. As this looks like a homework exercise, I'll leave you to figure out how to get around this.
I think this could by easier using regular expressions(and C++ instead of C of course):
Complete exmaple:
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
int main()
{
// Your test string.
std::string input("1-2,4^,14-56");
// Regex representing a number.
std::regex number("\\d+");
// Iterators for traversing the test string using the number regex.
auto ri_begin = std::sregex_iterator(input.begin(), input.end(), number);
auto ri_end = std::sregex_iterator();
for (auto i = ri_begin; i != ri_end; ++i)
{
std::smatch match = *i; // Match a number.
int value = std::stoi(match.str()); // Convert that number to integer.
std::string replacement = std::to_string(++value); // Increment 1 and convert to string again.
input.replace(match.position(), match.length(), replacement); // Finally replace.
}
std::cout << input << std::endl;
return 0;
}
Output:
2-3,5^,15-57
strtok modifies the string you pass to it. Either use strchr or something like that to find the delimiters or make a copy of the string to work on.
I need help in my following code and hope that you can help me through. All I wanted is to pass in INT type to setX() and setY(). However, there is no way for me to convert vector char* to int. Is there alternative to this?
template<class T>
vector<string> Delimiter(T inputString){
int count=0;
char str[inputString.length()];
strcpy(str,inputString.c_str());
char * pch;
vector<string> returnContainer;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str,",[]");
while (pch != NULL)
{
returnContainer.push_back(pch);
pch = strtok (NULL, " ,[]");
count++;
}
for(int i=0; i<returnContainer.size(); i++){
cout << "return:" << returnContainer[i] << endl;
}
return returnContainer;
}
//Main()
fileDataAfterFiltered = Delimiter(fileData[i]); // Delimiter (vector<string> type)
point2DObj[point2DCount].setX(fileDataAfterFiltered[1]); // error
point2DObj[point2DCount].setY(fileDataAfterFiltered[2]); // error
//Assn3.cpp:107:59: error: no matching function for call to ‘Point2D::setX(std::basic_string&)’
Delimiter() returns a vector<string> and you give one of these strings to setX() and setY(), but both expect an integer parameter. You must convert the string to int
int x = atoi(fileDataAfterFiltered[1].c_str());
point2DObj[point2DCount].setX(x);
int y = atoi(fileDataAfterFiltered[2].c_str());
point2DObj[point2DCount].setY(y);
But: in C++ array and vector elements start at 0 not 1, so you might want to replace this with fileDataAfterFiltered[0] and fileDataAfterFiltered[1] respectively.
If you are using a C++11 compiler, function std::stoi() will do the trick:
point2DObj[point2DCount].setX(std::stoi(fileDataAfterFiltered[1]));
Otherwise you can use the old atoi():
point2DObj[point2DCount].setX(atoi(fileDataAfterFiltered[1].c_str()));
Aside from this, your code has many other problems, but I hope you can fix them by yourself.
there's plenty of ways of converting string to int. boost::lexical_cast is one which will magically do the conversion you want. Otherwise you can use atoi (if you don't care about errors), or strtol (if you do).
point2DObj[point2DCount].setX(atoi(fileDataAfterFiltered[1].c_str()));
point2DObj[point2DCount].setX(boost::lexical_cast<int>(fileDataAfterFiltered[1]));
I am trying to reverse a null terminated string in place in C++. I have written the code below:
//Implement a function to reverse a null terminated string
#include<iostream>
#include<cstdlib>
using namespace std;
void reverseString(char *str)
{
int length=0;
char *end = str;
while(*end != '\0')
{
length++;
end++;
}
cout<<"length : "<<length<<endl;
end--;
while(str < end)
{
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
int main(void)
{
char *str = "hello world";
reverseString(str);
cout<<"Reversed string : "<<str<<endl;
}
However, when I run this C++ program , I get a a write access violation inside the while loop at the statement : *str = *end ;
Even though this is fairly simple, I can't seem to figure out the exact reason I am getting this error.
Could you please help me identify the error?
char *str = "hello world";
is a pointer to a string literal, and can't be modified. String literals reside in read-only memory and attempting to modify them results in undefined behavior. In your case, a crash.
Since this is clearly an assignment, I won't suggest using std::string instead, since it's good to learn these things. Use:
char str[] = "hello world";
and it should work. In this case, str would be an automatic-storage (stack) variable.
Here is a problem from spoj. nothing related to algorithms, but just c
Sample Input
2
a aa bb cc def ghi
a a a a a bb bb bb bb c c
Sample Output
3
5
it counts the longest sequence of same words
http://www.spoj.pl/problems/WORDCNT/
The word is less than 20 characters
But when i run it, it's giving segmentation fault. I debugged it using eclipse. Here's where it crashes
if (strcmp(previous, current) == 0)
currentLength++;
with the following message
No source available for "strcmp() at 0x2d0100"
What's the problem?
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
int main(int argc, const char *argv[])
{
int t;
cin >> t;
while (t--) {
char line[20000], previous[21], current[21], *p;
int currentLength = 1, maxLength = 1;
if (cin.peek() == '\n') cin.get();
cin.getline(line, 20000);
p = strtok(line, " '\t''\r'");
strcpy(previous, p);
while (p != NULL) {
p = strtok(NULL, " '\t''\r'");
strcpy(current, p);
if (strcmp(previous, current) == 0)
currentLength++;
else
currentLength = 1;
if (currentLength > maxLength)
maxLength = currentLength;
}
cout << maxLength << endl;
}
return 0;
}
The problem is probably here:
while (p != NULL) {
p = strtok(NULL, " '\t''\r'");
strcpy(current, p);
While p may not be NULL when the loop is entered.
It may be NULL when strcpy is used on it.
A more correct form of the loop would be:
while ((p != NULL) && ((p = strtok(NULL, " \t\r")) != NULL))
{
strcpy(current, p);
Note. Tokenizing a stream in C++ is a lot easier.
std::string token;
std::cin >> token; // Reads 1 white space seoporated word
If you want to tokenize a line
// Step 1: read a single line in a safe way.
std::string line;
std::getline(std::cin, line);
// Turn that line into a stream.
std::stringstream linestream(line);
// Get 1 word at a time from the stream.
std::string token;
while(linestream >> token)
{
// Do STUFF
}
Forgot to check for NULL on strtok, it will return NULL when done and you cannot use that NULL on strcpy, strcmp, etc.
Note that you do a strcpy right after the strtok, you should check for null before doing that using p as a source.
The strtok man page says:
Each call to strtok() returns a pointer to a null-terminated string containing the next
token. This string does not include the delimiting character. If no more tokens are found,
strtok() returns NULL.
And in your code,
while (p != NULL) {
p = strtok(NULL, " '\t''\r'");
strcpy(current, p);
you are not checking for NULL (for p) once the whole string has been parsed. After that you are trying to copy p (which is NULL now) in current and so getting the crash.
You will find that one of previous or current does not point to a null-terminated string at that point, so strcmp doesn't know when to stop.
Use proper C++ strings and string functions instead, rather than mixing C and C++. The Boost libraries can provide a much safer tokeniser than strtok.
You probably undersized current and previous. You should really use std::string for this kind of thing- that's what it's for.
You are doing nothing to check your string lengths before copying them into buffers of size 21. I bet that you are somehow overwriting the end of the buffer.
If you insist on using C strings, I'd suggest using strncmp instead of strcmp. That way, in case you are ending up with a non-null terminated string (which is what I suspect is the case), you can restrict your compare to the max length of the string (in this case 21).
Try this one...
#include <cstdio>
#include <cstring>
#define T(x) strtok(x, " \n\r\t")
char line[44444];
int main( )
{
int t; scanf("%d\n", &t);
while(t--)
{
fgets(line, 44444, stdin);
int cnt = 1, len, maxcnt = 0, plen = -1;
for(char *p = T(line); p != NULL; p = T(NULL))
{
len = strlen(p);
if(len == plen) ++cnt;
else cnt = 1;
if(cnt > maxcnt)
maxcnt = cnt;
plen = len;
}
printf("%d\n", maxcnt);
}
return 0;
}