I'm trying to create a method which, given multiple strings, merges them together. Now, this is what I came up with. The main is purely for test so in the end I'll have only one part string at the time, the location on which that part belongs in the full string, and the final string where I need to put these parts.
int mergeParts(char* text, char* part, int position){
int printSpot = position * CONTENTSIZE;
strcat(text[printSpot], part);
printf("%s\n", text);
return 0;
}
Now, the problem with this code is a segmentation error, I tried multiple things but the only one that seems to work is using strcat(text, part); without using the "location" on which the part of the string must be copy.
#define CONTENTSIZE 10
int main(){
int i;
char* part1 = "This is a ";
char* part2 = "test with ";
char* part3 = "something ";
char* part4 = "that i wro";
char* part5 = "te in it";
int totParts = 5;
char* parts[totParts] = {part1,part2,part3,part4,part5};
int stringSize = totParts * CONTENTSIZE;
char* finalString = malloc(stringSize);
for(i = 0; i<totParts; i++){
mergeParts(finalString, parts[i], i);
}
return 0;
}
How can I do this specifying to the string the location where to copy the parts.
A good example that I can give you to explain better what I'm looking for is:
I have a empty string "------------------------------"
I have to write inside "This "; "is an"; " exam"; "ple o"; "f the"; " text";
If I receive " exam";, the result in my string has to be "---------- exam---------------".
Then I receive " text"; and so the result will be "---------- exam---------- text"
And so on until I have "This is an example of the text";
It seems that strcat(text[printSpot], part); is the point. I think you should use strcat(&(text[printSpot]), part); instead. text[printSpot] will have the actual char data like 'e', not the address of the string which is required for strcat.
Or you can use strcat(text+printSpot,part) simply.
The main issue causing the segfault is that you're not passing the correct argument to strcat:
strcat(text[printSpot], part);
Both arguments are expected to be of type char *, but for the first argument you're passing in a single char. Passing a non-pointer where a pointer is expected invokes undefined behavior. In this case, the character being passed in is being interpreted as an address (which is invalid), and that invalid address is dereferenced, causing a crash.
You should be passing in the address of that array element:
strcat(&text[printSpot], part);
You also haven't initialized the bytes in finalString. The strcat function expects its first argument to point to a null terminated string, but because none of the allocated bytes have been initialized, you potentially read past the end of allocated memory, which again invokes undefined behavior.
Putting an empty string in finalString will take care of this:
strcpy(finalString, "");
Or equivalently:
finalString[0] = '\x0';
This allows the test program to work properly, where you're appending to an empty string in order, but it doesn't satisfy the requirement of updating parts of an existing string, possibly in the middle. Using strcat will null-terminate the destination string after the second argument is appended, resulting in anything that might have come after it to be lost.
Assuming finalString is initially set with an "empty" string as in your example of the proper length, you should instead use memcpy. This will copy over only the characters in the string and not add a null terminating byte:
memcpy(&text[printSpot], part, strlen(part));
You'll also want to populate finalString with '-' characters to start:
char* finalString = malloc(stringSize + 1);
memset(finalString, '-', stringSize);
finalString[stringSize]=0;
Output:
This is a ----------------------------------------
This is a test with ------------------------------
This is a test with something --------------------
This is a test with something that i wro----------
This is a test with something that i wrote in it--
Related
I am trying to append single quotes before and after a char array. Following is the code I am trying:
static const char str[] = "select * from name";
STATICF boolean test(){
char[] key = "1234";
strcat(str,(const char *)"\'");
strcat(str,key);
strcat(str,(const char *)"\'");
}
It does not work as I get segmentation fault. How can I fix this?
The array str is initialized to be exactly as big as the string that initializes it. This means that attempting to append anything to that string will write past the end of the array. Doing so invokes undefined behavior which in this case causes your program to crash.
You need to make the destination string big enough to hold the resulting string, and you need to not qualify it as const.
Also, manually constructing a SQL string is a bad idea as it can lead to a SQL injection attack. You should instead use prepared statements which can inject parameters into a command safely.
static const char str[] = "select * from name";
STATICF boolean test(){
char[] key = "1234";
int len = strlen(str) + 1 + strlen(key) + 1 + 1;
char dest[len];
strcpy(dest,str);
strcat(dest,"'");
strcat(dest,key);
strcat(dest,"'");
}
strcat(str,(const char *)"\'");
strcat(str,key);
strcat(str,(const char *)"\'");
str needs to be big enough to hold the whole concatenated result string, plus \0 to terminate the string. This isn´t the case at your example with the declaration of str as:
static const char str[] = "select * from name";
with str to hold only the size of the old string plus \0. Thus, trying to append more characters causes the segmentation fault.
Try to declare str with a fixed size, large enough to hold the result string (the old string of select * from name + \' + 1234 + \' + the terminating \0 which shall be 25 characters in total if I´d counted right).
str needs to be non-constant to change the value of str by the way, so omit static const.
Also omit the cast of (const char *); and replace "\'" with "'".
The result is like the following:
char str[25];
strcpy(str,"select * from name");
STATICF boolean test(){
char key[] = "1234";
strcat(str,"'");
strcat(str,key);
strcat(str,"'");
}
int main(int argc, char** argv) {
char data[1024];
data[0] = '\0';
for(int i = 1; i < argc; i++){
strcpy(data+strlen(data), (argv[i] + 1));
}
strcpy(data+strlen(data), data+strlen(data)/2);
printf(data);
return 0;
}
As you can see this is my code so far. What I'm trying to do is: Remove first letter from every argument, concat them into data and after the loop take half of the resulting string and concat it again, then print it. Example:
Calling the program with the arguments hello, world and yes should print:
elloorldesrldes
it works until strcpy(data+strlen(data), data+strlen(data)/2);. Here I try to take half of the string (data) and concat it to the end of the same string. When I leave that part out I get the result elloorldes but when I put it in, instead of giving me the expected results I get the error RUN FAILED (exit value -1.073.741.819, total time: 4s), however I'm not sure why that's the case.
You cannot do this
strcpy(data+strlen(data), data+strlen(data)/2);
because strcpy cannot handle cases when memory overlaps.
man strcpy
char *strcpy(char *dest, const char *src);
DESCRIPTION
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'),
to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.
You need to use memmove for this, which handles memory overlap:
size_t oldsize = strlen(data);
size_t size = oldsize/2;
memmove(data+oldsize, data+size, size);
data[oldsize + size] = 0;
Also don't do printf(data) with content provided by the user. Let's say the
passed arguments are hello, world%d, then data will contain %d and
printf would yield undefined behaviour, because there are arguments missing.
You should do this:
printf("%s\n", data);
or
puts(data);
I'm looking to separate a line (given as one string) into words. for example:
" Hello world". I can have one or more tabs or spaces between the words and in the beginning. I'm trying to do something like this:
(findCommand is a function and line is the string I get as input, for this part I only need the first 2 words)
CommandResult findCommand (const char* line){
char* commandLine = malloc(strlen(line)+1);
strcpy(commandLine, line);
char space[] = " \t";
char* word1 = strtok(commandLine,space);
char* word2 = strtok(NULL,space);
I've tried to run this in Eclipse with different variations of spaces and tabs. some of them worked fine, on others I get a sigmentation fault and I can't figure out why.
This:
char* commandLine = malloc(sizeof(strlen(line)));
is wrong. You shouldn't use sizeof here, and certainly not on the result of calling strlen(). The above is the same as:
char *commandLine = malloc(sizeof (size_t));
since the return type of strlen() is size_t. Thus, the actual strlen() return value is ignored.
The proper code is:
char *commandLine = malloc(strlen(line) + 1);
since you must add 1 for the terminator, which is not included in the length returned by strlen().
There is no need for any sizeof here, since you're very obviously working with characters.
Use malloc((strlen(line) + 1)* sizeof(char)) instead of malloc(sizeof(strlen(line))).
You allocate only space for an integer because sizeof returns an integer.
I am using strtok to extract 2 words from a string names[result]. I want to get the first value from the strtok and stored it into a char array named lastName and the second value into a char array named firstName. However I got an invalid initializer error for 2 lines which are indicated by the arrow when I compiled my code. How do I resolve my problem?
char *p = NULL;
p = strtok(names[result]," ");
char lastName[50] = p; <---
p = strtok(NULL, " ");
char firstName[50] = p; <---
printf("%s %s\n",firstName,lastName);
strtok gives the pointer to the tokenized string.
char lastName[50] = p; Isn't really a good thing that you are doing there. Should use strncpy() to copy the string, or if only want the pointer, then should store in another pointer.
Array initialization in C can only use a literal, not a variable. So your code is a syntax error.
You need to use the typical strcpy() function to copy the string, or some of the more safe (and modern) varities, like strlcpy() or snprintf().
You could also do the parsing and copying in one call, using sscanf(), with proper size specifiers in the formatting string to avoid the risk of buffer overflow.
You can initialize a string to the character array like char lastName[50] = "Sample";
In this case you are trying to initialize a pointer to the character array 'char lastName[50] = p;' which is not valid.
Better you can use strcpy, memcpy function to copy the string to the character array or you can assign it in another pointer.
The other answers are all correct in that copying the string data out will make this program work, but the reason strtok is so dastardly (and generally using it is considered ill-advised) is that it changes your input by inserting NULLs into the original string. If you're going to be using it anyway, you might as well advantage of this and just use the pointers that strtok is returning directly.
Of note, though, is that since the input is changed and maybe whoever passed that input into you is not expecting that, it might be better to copy the input to a separate string first before ever calling strtok on it.
Observe the output of this code to see what I mean:
int main(int argc, char *argv[]) {
char name[] = "Firstname Lastname";
printf("Name before strtok: %s\n", name);
char *first = strtok(name, " ");
char *last = strtok(NULL, " ");
printf("Token strings: first=%s last=%s\n", first, last);
printf("Name after strtok: %s\n", name);
}
Produces:
Firstname Name before strtok: Firstname Lastname
Token strings: first=Firstname last=Firstname
Name after strtok: Firstname
I am trying to remove first semicolon from a character arrary whose value is:
Input: ; Test: 876033074, 808989746, 825766962, ; Test1:
825766962,
Code:
char *cleaned = cleanResult(result);
printf("Returned BY CLEAN: %s\n",cleaned);
char *cleanResult(char *in)
{
printf("Cleaning this: %s\n",in);
char *firstOccur = strchr(in,';');
printf("CLEAN To Remove: %s\n",firstOccur);
char *restOfArray = firstOccur + 2;
printf("CLEAN To Remove: %s\n",restOfArray); //Correct Value Printed here
char *toRemove;
while ((toRemove = strstr(restOfArray + 2,", ;"))!=NULL)
{
printf("To Remove: %s\n",toRemove);
memmove (toRemove, toRemove + 2, strlen(toRemove + 2));
printf("Removed: %s\n",toRemove); //Correct Value Printed
}
return in;
}
Output (first semicolon still there): ; Test: 876033074,
808989746, 825766962; Test1: 825766962;
Regarding sizeof(cleaned): using sizeof to get the capacity of an array only works if the argument is an array, not a pointer:
char buffer[100];
const char *pointer = "something something dark side";
// Prints 100
printf("%zu\n", sizeof(buffer));
// Prints size of pointer itself, usually 4 or 8
printf("%zu\n", sizeof(pointer));
Although both a local array and a pointer can be subscripted, they behave differently when it comes to sizeof. Thus, you cannot determine the capacity of an array given only a pointer to it.
Also, bear this in mind:
void foo(char not_really_an_array[100])
{
// Prints size of pointer!
printf("%zu\n", sizeof(not_really_an_array));
// Compiles, since not_really_an_array is a regular pointer
not_really_an_array++;
}
Although not_really_an_array is declared like an array, it is a function parameter, so is actually a pointer. It is exactly the same as:
void foo(char *not_really_an_array)
{
...
Not really logical, but we're stuck with it.
On to your question. I'm unclear on what you're trying to do. Simply removing the first character of a string (in-place) can be accomplished with a memmove:
memmove( buffer // destination
, buffer + 1 // source
, strlen(buffer) - 1 // number of bytes to copy
);
This takes linear time, and assumes buffer does not contain an empty string.
The reason strcpy(buffer, buffer + 1) won't do is because the strings overlap, so this yields undefined behavior. memmove, however, explicitly allows the source and destination to overlap.
For more complex character filtering, you should consider traversing the string manually, using a "read" pointer and a "write" pointer. Just make sure the write pointer does not get ahead of the read pointer, so the string won't be clobbered while it is read.
void remove_semicolons(char *buffer)
{
const char *r = buffer;
char *w = buffer;
for (; *r != '\0'; r++)
{
if (*r != ';')
*w++ = *r;
}
*w = 0; // Terminate the string at its new length
}
You are using strcpy with overlapping input / output buffer, which results in undefined behavior.
You're searching for a sequence of three characters (comma space semicolon) and then removing the first two (the comma and the space). If you want to remove the semicolon too, you need to remove all three characters (use toRemove+3 instead of toRemove+2). You also need to add 1 to the strlen result to account for the NUL byte terminating the string.
If, as you say, you just want to remove the first semicolon and nothing else, you need to search for just the semicolon (which you can do with strchr):
if ((toRemove = strchr(in, ';')) // find a semicolon
memmove(toRemove, toRemove+1, strlen(toRemove+1)+1); // remove 1 char at that position