String concatenation without altering original values - C - c

I am making a dynamic PUT request through the use of string concatenation with C. My problem is that after the first request, a string that I need to remain static putEndpoint, is altered with the string concatenation I'm using it for.
char putEndpoint[] = "PUT /api/v1/products/";
char http[] = " HTTP/1.1";
char productID[idLen];
for(int i = 0; i < 13; i++) {
productID[i] = newTag[i];
}
// going into this strcat, putEndpoint correctly = "PUT /api/v1/products/"
char *putRequestID = strcat(putEndpoint,productID);
// putEndpoint now = "PUT /api/v1/products/xxxxxxxxxxx"
char *putRequestEndpoint = strcat(putRequestID,http);
Now if I were to make a 2nd call (which I will need to do), putEndpoint initializes as "PUT /api/v1/products/xxxxxxxxxxx".
EDIT: Is there an alternative to strcat() that could accomplish this concatenation?
I now understand that strcat() is meant to alter values.

You can use sprintf.
A simple working example-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char putEndpoint[] = "PUT /api/v1/products/";
char http[] = " HTTP/1.1";
char *putRequestEndpoint;
putRequestEndpoint=malloc(strlen(putEndpoint)+strlen(http)+1); //allocating memory
sprintf(putRequestEndpoint,"%s%s",putEndpoint,http); // formatted output is stored in putRequestEndpoint
printf("%s\n",putRequestEndpoint);
printf("%s",putEndpoint); // will print original string unchanged.
free(putRequestEndpoint); //freeing memory
return 0;
}

I ended up changing putEndpoint to a constant and created a buffer array and that I then copied putEndpoint into. This array then resets after each request.
const char putEndpoint[] = "PUT /api/v1/products/";
char http[] = " HTTP/1.1";
char productID[idLen];
char putRequestBuffer[100];
strcpy(putRequestBuffer, putEndpoint);
strcat(putRequestBuffer, productID);
char *putRequestEndpoint = strcat(putRequestBuffer,http);

memcpy and static arrays with a fixed size and proper bounds checking are your friend, my friend.

You would have to reset it with code. If you change putEndpoint[] to a const, which will make your first line look like
const char putEndpoint[] = "PUT /api/v1/products/";
the compiler will give you an error the first time you strcat(putEndpoint,...) because strcat will be trying to write to the constant variable. This will force you to find an alternative solution.
The code below cleanly allocates temporary memory for the endpoint string as needed, copies the first string into it, concatenates the next two onto it, uses it, and finally de-allocates it and sets the pointer back to NULL.
int lengthEndpoint = 0;
char* putRequestEndpoint = NULL;
lengthEndpoint = strlen(putEndpoint) + strlen(productID) + strlen(http);
lengthEndpoint += 1; // add room for null terminator
putRequestEndpoint = malloc(lengthEndpoint);
strcpy(putRequestEndpoint, putEndpoint);
strcat(putRequestEndpoint, productID);
strcat(putRequestEndpoint, http);
// do something with putRequestEndpoint
free(putRequestEndpoint);
putRequestEndpoint = NULL;
Before answering this, I refreshed my memory of C string manipulation using this WIKIBOOKS site. I'd recommend it for further reading on this subject.

Related

C - Implementing Queue of Char * Array

I want to implement a queue which holds 10 elements of char * array. I searched on the internet but couldn't find enough solutions.
I have a char array:
char str[50]:
char *arr[5];
And the user enters some string with backspace character e.g "Hello I am computer". The string is in str[] array. I token them with strtok() function and assign it to the arr[].Then it becomes:
//arr[0] = "Hello"
//arr[1] = "I"
//arr[2] = "am"
//arr[3] = "computer"
It is ok until now, I am doing it correctly.
Now my question is how to hold this whole arr array in queue's first node or element. There are lots of examples about queue that holding int values and they are easy to understand, but I couldn't do the char * version.
As far as I understood your question you need to implement a queue of type string.
You can do it as you do with any other queue.But instead of int it would of type char* you would also need to pass length of the word so you could dereference that many number of char starting from the char pointer till length of the word.
void Enqueue(char* x, int len)
{
// if empty
front = rear = 0;
// else
rear = (rear+1);
char ch[100];
for(int i=0;i<len;i++) {
ch[i] = *(x+i);
}
Arr[rear] = ch;
}
First of all you have to be careful when saving an address to a variable that you want to use later. You have to ensure that the address hold by the pointer is still valid when you read from it:
int main()
{
char str[] = "Hello I am computer"; // "Hello I am computer" is stored on the stack
AddStringToQueue(str[0]);
}
// str could be overwritten by another function who allocates local variables
As you said in the comment you should use void* malloc(sizeof("Hello I am computer")) which return the start pointer of your allocated memory.
The other thing is why you want to store the string as tokens? Wouldn't it be easier to store the whole string ("Hello I am computer") and use the first character as your start address for the string? If you need it as tokens you maybe can call strtok() after you read out the queue.
Let me make an example:
#define QUEUE_MAX 10
int QueuePos = 0;
char* Queue[QUEUE_MAX];
memset(Queue, NULL, sizeof(Queue));
// call AddStringToQueue("Hello I am computer"); anywhere
void AddStringToQueue(char* string)
{
char* ptr = (char*)malloc(sizeof(string));
memcpy(ptr, string, sizeof(string));
Queue[QueuePos++] = ptr;
if (QueuePos == QUEUE_MAX) QueuePos = 0; // overwrites Queue if max. is reached
}
I am not sure if you mean this.
Hope it helps.
PS: I didn't compiled this so i am not sure if it works, it should just be an example.

How do I send a char* to a function and have it change the contents of the char* in C?

I have been trying and searching online for too long without any success. I've tried a lot of the suggested answers but nothing has worked for me.
I want to basically send in a char*. It can make it NULL if necessary, but would rather the function modify a char* that already has something.
Example:
char *old = "kit";
function(old){ //does stuff and writes "kat" to old}
printf("new = %s", old);
And
result: new = kat
How can I do this?
Thanks
EDIT:
What I'm currently trying:
calling_function(char *in){
char **old = NULL;
function(&old);
printf("old in calling function is now = %s", *old);
}
function(**old){
<does stuff to get char *another_string = "kat">
*old = another_string;
printf("old is now = %s ", *old);
}
And the result is:
old is now "kat"
old in calling function is now =
and it immediately exist the system with an unspecified error exit(-1) then hangs.
A char* is nothing more an address that points to some bytes which are then interpreted as a string, how to do what you need really depends on what you need to do.
If you want to change a character of the string then a normal char* (non const) pointer will be enough:
void function(char *data) {
data[0] = 'a';
}
If, instead, you want to replace the whole string with another one (possibly of different length), then you will need to pass the address that contains the address, so that you can directly replace it to a new address (that points to a different string):
void function(char **data) {
*data = strdup("newstring");
// strdup is used because a string literal must be considered as const
// otherwise you could invoke UB by modifying the returned string
}
char *value;
function(&value);
An example for passing integer as reference is here: Passing by reference in C
For your example, the value can be changed in the function as below:
char *old = "kit";
/* this will print kit */
printf("old = %s",old);
function(old);
/* this will print kat */
printf("updated old = %s", old);
function(char *old) {
*old = "kat"
}
The line
char *old = "kit";
Can cause trouble because old may point to read-only memory. What you want to do is this:
char old[128]; // or however many you need
function(old){ //does stuff and writes "kat" to old // You can use sprintf for this}
printf("new = %s", old);
Which will allocate old on the stack, where it can be modified.
This will take an existing char * and change it.
char* old = "kit";
void changingFunction( char* pointer ) {
strcpy( pointer, "kat" );
/* or just pointer[1] = 'a'; */
}
changingFunction(old);
printf("new = %s\n", old);
Be careful, though. Remember that you're essentially dealing with an array, and the function doesn't know the size of the array. You always want to stay within the bounds of the array.
Consequently, you should make the function more advanced:
void changingFunction( char* pointer ) {
char * newString = "kat";
strncpy(pointer, newString, strlen(pointer));
}
By using strncpy, you ensure that you stay within your bounds, and since you're dealing with a null terminated char*, you can use strlen to find how big your bounds are.
You can change your function prototype to
void myFunction(char** pold)
and within that function, you are free to write
*pold = "kat";
And call the function like this: myFunction(&old);
But beware; this approach has dangers:
1) You may leak memory as the previous string (i.e. what was old originally pointing to?) may be dangling.
2) *pold = "kat"; assigns read-only memory to *pold. This is because "kat" is probably added to a string literal pool on program startup by the C runtime library. Attempting to modify the string (e.g. (*pold)[0] = 'K') is undefined behaviour. Using *pold = strdup("kat"); circumvents this problem.
I learned something by trying to answer this question! Here's my program that does the operation:
#include <stdio.h>
void f(char* str)
{
strcpy(str, "kat");
}
int main(void) {
// char* str = "kit"; // Initializing like this causes a crash!
char str[4]; // This initialization works
strcpy(str, "kit");
f(str);
printf(str); // Prints "kat"
return 0;
}
There are obvious issues with safety, but what was strange to me is that if you declare str using the commented-out line, the program crashes. I didn't realize that initializing a string literal like that gave you a pointer to read-only memory. That's very non-obvious to me, so I was confused when my little program crashed.
I think it's important to point out that fact first and foremost because it's central to why a naive solution to the problem wouldn't necessarily work. Interesting.

Char x[50] and Char x[100] Output

I'm not used to C as I'm primarily a Java guy, with some knowledge of C++, so forgive me if this is a trivial question. I could not seem to find an answer while searching online.
I'm initializing a char array...
char tcp[50];
So that I can concatenate a const char and a char. In examples I saw an easy way to do this was by creating that empty char array and then using...
strcat(x,y);
To stick them together.
Problem is, printing out the blank char array when it is set to "50" gives me a result of:
X??|?
When I change it to...
char tcp[100];
And print it, its blank. Why is this?
The array contents are undefined, assuming it is a local (automatic) array.
Use:
char tcp[50] = "";
Or:
char tcp[50] = {0};
Or:
char tcp[50];
tcp[0] = 0;
Or:
char tcp[50];
memset(tcp, 0, sizeof(tcp));
As you like.
Always null terminate you char arrays before doing anything:
tcp[0] = '\0';
C happily allocates the space for the array you declare, but it does not set its content to 0.
Therefore, the content of the array you're printing is random (or rather depending in the previous contents of the memory)
When creating an array, the compiler puts it somewhere in memory but does not initialize it, so whatever is in that memory when the program is started will be the initial "string".
Terminate the string manually after you created the array, either by making the whole array "zeroed" out, or just put zero as the first character:
char tcp[50] = { '\0' };
Or
char tcp[50];
/* ... */
tcp[0] = '\0';
The difference here is, you're essentially working with two empty arrays trying to merge them in the memory space of one (not sure if that makes sense for you).
First of all, in C you have to terminate strings with \0. That's something not exposed or visible in Java. Also you essentially used two undefined strings (as there's no value set).
#include <stdio.h>
#include <string.h>
char target[256];
const char source_a[] = "Hello";
const char source_b[] = "World!";
int void(main)
{
target[0] = '\0'; // this essentially empties the string as we set the first entry to be the end. Depending on your language version of C, you might as well write "char target[256] = {'\0'};" above.
strcat(target, source_a); // append the first string/char array
strcat(target, " "); // append a const string literal
strcat(target, source_b); // append the second string
printf("%s\n", target);
return 0;
}
Important: Using strcat() can be unsave, as there's no length check performed, and other than Java, these "strings" have a fixed length (the one you set when defining the variables). If there's no length given, but you copy a string on initialization, that length is taken (e.g. char test[] = "Hello!"; will be 7 chars long (due to terminating \0)).
If you'd like a more Java like approach on strings, use C++ and the std::string class, that performs a lot more similar to Java's strings.

Simple C string manipulation

I trying to do some very basic string processing in C (e.g. given a filename, chop off the file extension, manipulate filename and then add back on the extension)- I'm rather rusty on C and am getting segmentation faults.
char* fname;
char* fname_base;
char* outdir;
char* new_fname;
.....
fname = argv[1];
outdir = argv[2];
fname_len = strlen(fname);
strncpy(fname_base, fname, (fname_len-4)); // weird characters at the end of the truncation?
strcpy(new_fname, outdir); // getting a segmentation on this I think
strcat(new_fname, "/");
strcat(new_fname, fname_base);
strcat(new_fname, "_test");
strcat(new_fname, ".jpg");
printf("string=%s",new_fname);
Any suggestions or pointers welcome.
Many thanks and apologies for such a basic question
You need to allocate memory for new_fname and fname_base. Here's is how you would do it for new_fname:
new_fname = (char*)malloc((strlen(outdir)+1)*sizeof(char));
In strlen(outdir)+1, the +1 part is for allocating memory for the NULL CHARACTER '\0' terminator.
In addition to what other's are indicating, I would be careful with
strncpy(fname_base, fname, (fname_len-4));
You are assuming you want to chop off the last 4 characters (.???). If there is no file extension or it is not 3 characters, this will not do what you want. The following should give you an idea of what might be needed (I assume that the last '.' indicates the file extension). Note that my 'C' is very rusty (warning!)
char *s;
s = (char *) strrchr (fname, '.');
if (s == 0)
{
strcpy (fname_base, fname);
}
else
{
strncpy (fname_base, fname, strlen(fname)-strlen(s));
fname_base[strlen(fname)-strlen(s)] = 0;
}
You have to malloc fname_base and new_fname, I believe.
ie:
fname_base = (char *)(malloc(sizeof(char)*(fname_len+1)));
fname_base[fname_len] = 0; //to stick in the null termination
and similarly for new_fname and outdir
You're using uninitialized pointers as targets for strcpy-like functions: fname_base and new_fname: you need to allocate memory areas to work on, or declare them as char array e.g.
char fname_base[FILENAME_MAX];
char new_fname[FILENAME_MAX];
you could combine the malloc that has been suggested, with the string manipulations in one statement
if ( asprintf(&new_fname,"%s/%s_text.jpg",outdir,fname_base) >= 0 )
// success, else failed
then at some point, free(new_fname) to release the memory.
(note this is a GNU extension which is also available in *BSD)
Cleaner code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char *extra = "_test.jpg";
int main(int argc, char** argv)
{
char *fname = strdup(argv[1]); /* duplicate, we need to truncate the dot */
char *outdir = argv[1];
char *dotpos;
/* ... */
int new_size = strlen(fname)+strlen(extra);
char *new_fname = malloc(new_size);
dotpos = strchr(fname, '.');
if(dotpos)
*dotpos = '\0'; /* truncate at the dot */
new_fname = malloc(new_size);
snprintf(new_fname, new_size, "%s%s", fname, extra);
printf("%s\n", new_fname);
return 0;
}
In the following code I do not call malloc.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* Change this to '\\' if you are doing this on MS-windows or something like it. */
#define DIR_SYM '/'
#define EXT_SYM '.'
#define NEW_EXT "jpg"
int main(int argc, char * argv[] ) {
char * fname;
char * outdir;
if (argc < 3) {
fprintf(stderr, "I want more command line arguments\n");
return 1;
}
fname = argv[1];
outdir = argv[2];
char * fname_base_begin = strrchr(fname, DIR_SYM); /* last occurrence of DIR_SYM */
if (!fname_base_begin) {
fname_base_begin = fname; // No directory symbol means that there's nothing
// to chop off of the front.
}
char * fname_base_end = strrchr(fname_base_begin, EXT_SYM);
/* NOTE: No need to search for EXT_SYM in part of the fname that we have cut off
* the front and then have to deal with finding the last EXT_SYM before the last
* DIR_SYM */
if (!fname_base_end) {
fprintf(stderr, "I don't know what you want to do when there is no extension\n");
return 1;
}
*fname_base_end = '\0'; /* Makes this an end of string instead of EXT_SYM */
/* NOTE: In this code I actually changed the string passed in with the previous
* line. This is often not what you want to do, but in this case it should be ok.
*/
// This line should get you the results I think you were trying for in your example
printf("string=%s%c%s_test%c%s\n", outdir, DIR_SYM, fname_base_begin, EXT_SYM, NEW_EXT);
// This line should just append _test before the extension, but leave the extension
// as it was before.
printf("string=%s%c%s_test%c%s\n", outdir, DIR_SYM, fname_base_begin, EXT_SYM, fname_base_end+1);
return 0;
}
I was able to get away with not allocating memory to build the string in because I let printf actually worry about building it, and took advantage of knowing that the original fname string would not be needed in the future.
I could have allocated the space for the string by calculating how long it would need to be based on the parts and then used sprintf to form the string for me.
Also, if you don't want to alter the contents of the fname string you could also have used:
printf("string=%s%c%*s_test%c%s\n", outdir, DIR_SYM, (unsigned)fname_base_begin -(unsigned)fname_base_end, fname_base_begin, EXT_SYM, fname_base_end+1);
To make printf only use part of the string.
The basic of any C string manipulation is that you must write into (and read from unless... ...) memory you "own". Declaring something is a pointer (type *x) reserves space for the pointer, not for the pointee that of course can't be known by magic, and so you have to malloc (or similar) or to provide a local buffer with things like char buf[size].
And you should be always aware of buffer overflow.
As suggested, the usage of sprintf (with a correctly allocated destination buffer) or alike could be a good idea. Anyway if you want to keep your current strcat approach, I remember you that to concatenate strings, strcat have always to "walk" thourgh the current string from its beginning, so that, if you don't need (ops!) buffer overflow checks of any kind, appending chars "by hand" is a bit faster: basically when you finished appending a string, you know where the new end is, and in the next strcat, you can start from there.
But strcat doesn't allow to know the address of the last char appended, and using strlen would nullify the effort. So a possible solution could be
size_t l = strlen(new_fname);
new_fname[l++] = '/';
for(i = 0; fname_base[i] != 0; i++, l++) new_fname[l] = fname_base[i];
for(i = 0; testjpgstring[i] != 0; i++, l++) new_fname[l] = testjpgstring[i];
new_fname[l] = 0; // terminate the string...
and you can continue using l... (testjpgstring = "_test.jpg")
However if your program is full of string manipulations, I suggest using a library for strings (for lazyness I often use glib)

Memory access violation. What's wrong with this seemingly simple program?

This is a quick program I just wrote up to see if I even remembered how to start a c++ program from scratch. It's just reversing a string (in place), and looks generally correct to me. Why doesn't this work?
#include <iostream>
using namespace std;
void strReverse(char *original)
{
char temp;
int i;
int j;
for (i = 0, j = strlen(original) - 1; i < j; i++, j--)
{
temp = original[i];
original[i] = original[j];
original[j] = temp;
}
}
void main()
{
char *someString = "Hi there, I'm bad at this.";
strReverse(someString);
}
If you change this, which makes someString a pointer to a read-only string literal:
char *someString = "Hi there, I'm bad at this.";
to this, which makes someString a modifiable array of char, initialized from a string literal:
char someString[] = "Hi there, I'm bad at this.";
You should have better results.
While the type of someString in the original code (char*) allows modification to the chars that it points to, because it was actually pointing at a string literal (which are not permitted to be modified) attempting to do any modification through the pointer resulted in what is technically known as undefined behaviour, which in your case was a memory access violation.
If this isn't homework, the C++ tag demands you do this by using the C++ standard library:
std::string s("This is easier.");
std::reverse(s.begin(), s.end());
Oh, and it's int main(), always int main(), dammit!
You're trying to modify a string literal - a string allocated in static storage. That's undefiend behaviour (usually crashes the program).
You should allocate memory and copy the string literal there prior to reversing, for example:
char *someString = "Hi there, I'm bad at this.";
char* stringCopy = new char[strlen( someString ) + 1];
strcpy( stringCopy, someString );
strReverse( stringCopy );
delete[] stringCopy;//deallocate the copy when no longer needed
The line
char *someString = "Hi there, I'm bad at this.";
makes someString point to a string literal, which cannot be modified. Instead of using a raw pointer, use a character array:
char someString[] = "Hi there, I'm bad at this.";
You can't change string literals (staticly allocated). To do what you want, you need to use something like:
int main()
{
char *str = new char[a_value];
sprintf(str, "%s", <your string here>);
strReverse(str);
delete [] str;
return 0;
}
[edit] strdup also works, also strncpy... i'm sure there's a variety of other methods :)
See sharptooth for explanation.
Try this instead:
#include <cstring>
void main()
{
char someString[27];
std::strcpy( someString, "Hi there, I'm bad at this." );
strReverse( someString );
}
Better yet, forget about char * and use <string> instead. This is C++, not C, after all.
When using more strict compiler settings, this code shouldn't even compile:
char* str = "Constant string";
because it should be constant:
const char* str = "Now correct";
const char str[] = "Also correct";
This allows you to catch these errors faster. Or you can just use a character array:
char str[] = "You can write to me, but don't try to write something longer!";
To be perfectly safe, just use std::string. You're using C++ after all, and raw string manipulation is extremely error-prone.

Resources