C invalid operands to binary + (have ‘char *’ and ‘char *’)? - arrays

In C I have:
filedata->string_table + (X)->sh_name
Now I want to add the following string next to it: "new"
I tried:
filedata->string_table + (X)->sh_name + "new"
but this won't compile and I get:
readelf.c:6807:83: error: invalid operands to binary + (have ‘char *’ and ‘char *’)
filedata->string_table + (X)->sh_name : filedata->string_table + (X)->sh_name+"new")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
How to fix this?

Use proper way to concatenate strings.
If you want to add the result to existing buffer, use strcat() to concatenate strings.
char buffer[1024000]; /* enough size */
strcpy(buffer, filedata->string_table + (X)->sh_name);
strcat(buffer, "new");
You also can use snprintf() to put the result of concatenation in a buffer.
char buffer[1024000]; /* enough size */
snprintf(buffer, sizeof(buffer), "%s%s",
filedata->string_table + (X)->sh_name, "new");
To print the result to the standard output, use two %s format specifier to print the two strings in a row.
printf("%s%s",
filedata->string_table + (X)->sh_name, "new");
If the string "new" is fixed, also you can do like this:
printf("%snew",
filedata->string_table + (X)->sh_name);

You cannot concatenate strings or char using the operator +. Use strncat() or snprintf().

(X)->sh_name+"new" + in C does not concatenate the strings. It tries to add pointer to pointer which is invalid.
You need to use function strcat or strncat
Sorry These functions affect the strings but I want a new one –
it is so simple:
char *strcatAlloc(const char * restrict s1, const char * restrict s2)
{
size_t s1len;
char *newstring;
if(s1 && s2)
{
s1len = strlen(s1);
newstring = malloc(s1len + strlen(s2) + 1);
if(newstring)
{
strcpy(newstring, s1);
strcpy(newstring + s1len, s2);
}
}
return newstring;
}
int main(void)
{
// you should check if the function fails. Omitted for the example clarity
printf("`%s`\n", strcatAlloc("hello ", "world"));
printf("`%s`\n", strcatAlloc("", "world"));
printf("`%s`\n", strcatAlloc("hello ", ""));
printf("`%s`\n", strcatAlloc("", ""));
//you should free allocated space
}
or version where you can pass your buffer (it will allocate memory if that buffer is NULL)
char *strcatAlloc(const char * restrict s1, const char * restrict s2, char *buff)
{
size_t s1len;
if(s1 && s2)
{
s1len = strlen(s1);
if(!buff) buff = malloc(s1len + strlen(s2) + 1);
if(buff)
{
strcpy(buff, s1);
strcpy(buff + s1len, s2);
}
}
return buff;
}
int main(void)
{
char s[100];
// you should check if the function fails. Omitted for the example
printf("`%s`\n", strcatAlloc("hello ", "world", NULL));
printf("`%s`\n", strcatAlloc("", "world", NULL));
printf("`%s`\n", strcatAlloc("hello ", "", s)); //you can pass your own large enough buffer
printf("`%s`\n", strcatAlloc("", "", NULL));
//you should free allocaated space
}

Remember that C doesn't have an actual string type - strings are stored in arrays of char, and C doesn't define the + or = operators for array types.
You can append strings to a character buffer using strcat or strncat:
char foo[] = "This is ";
char bar[] = "a test";
char target[ sizeof foo + sizeof bar ];
strcpy( target, foo ); // copies contents of foo to target buffer
strcat( target, bar ); // appends contents of bar to target buffer
The target buffer must be large enough to accommodate the final string including the terminator. In this example, we took the sizes (not lengths!) of foo and bar which are 9 and 7 respectively (including the string terminators). Note that this would not work if they were declared as
char *foo = "This is ";
char *bar = "a test";
because sizeof foo would only give us the size of the pointer object, not the size of the string to which it points. In that case you'd have to get the size at runtime using strlen. If you're using a version that supports VLAs (C99 or later), you could simply do
char *foo = "This is ";
char *bar = "a test";
char target[ strlen( foo ) + strlen( bar ) + 1];
If not, you'd have to allocate your buffer dynamically:
char *target = malloc( strlen( foo ) + strlen( bar ) + 1 );
and you'd have to remember to free it when you're done.
If you have a mix of string and non-string types, you can use sprintf:
char *name = "blah";
int number = 42;
sprintf( target, "%s-%d", name, number ); // writes "blah-42" to target buffer
Again, the target buffer must be large enough to store the resulting string plus the terminator.

Related

why does strcat not work inside function?

hi i'm trying to write a function that get 3 words, concatenate them to one word and print the word reverse.
i can't put the concatenated word into the ptr w1 in concatWords function.
another question - should i put '\0' in the end of every word?
can someone review my code?
thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
void printReversedWord(char *word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word);
}
}
int main()
{
char word1[N+1];
char word2[N+1];
char word3[N+1];
char* longWord;
initWords(word1, word2, word3);
longWord = concatWords(word1, word2, word3);
printReversedWord(longWord);
free(longWord);
return 0;
}
You allocate memory that you assign to w1. Whatever w1 was pointing at can therefore not be included in the final string. You need a separate variable for where to put the final result.
Example:
char *concatWords(char *w1, char *w2, char *w3) {
size_t w1len = strlen(w1);
size_t w2len = strlen(w2);
size_t w3len = strlen(w3);
// the final result will be stored in memory pointed out by `res`:
char *res = malloc(w1len + w2len + w3len + 1); // +1 for null terminator
if (res) {
// copy the three strings where they belong:
memcpy(res, w1, w1len);
memcpy(res + w1len, w2, w2len);
memcpy(res + w1len + w2len, w3, w3len + 1); // +1 for null terminator
}
return res;
}
Another issue: printReversedWord is missing the subscript operator on word:
void printReversedWord(char *word) {
for (size_t i = strlen(word); i-- > 0;) {
printf("%c", word[i]); // <- here
}
}
Demo
The function strcat deals with strings. That means that the both function arguments shall point to strings. And the function also builds a string.
Also as your function does not change passed strings then its parameters should have qualifier const. And the function shall build a new string. Otherwise after this statement
w1 = (char*)malloc(sizeof(char) * len);
the first passed string is lost.
The function can look the following way
char * concatWords( const char *w1, const char *w2, const char *w3 )
{
size_t len = strlen( w1 ) + strlen( w2 ) + strlen( w3 );
char *result = malloc( len + 1 );
if ( result != NULL )
{
strcpy( result, w1 );
strcat( result, w2 );
strcat( result, w3 );
}
return result;
}
In turn the function printReversedWord can look the following way/ Pay attention to that your function implementation has a bug in this statement
printf("%c", word);
You have to write
printf("%c", word[i]);
Here is the updated function definition.
void printReversedWord( const char *word )
{
size_t len = strlen( word );
while ( len != 0 )
{
putchar( word[--len] );
}
putchar( '\n' );
}
In main you should write
initWords( word1, word2, word3 );
longWord = concatWords(word1, word2, word3);
if ( longWord != NULL ) printReversedWord(longWord);
free( longWord );
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This method:
allocates memory that is not zeroed out, which will make it impossible to "cat" to it, because that assumes the string is null-terminated.
allocates memory and then overwrites the pointer that points to the first word. That would be lost.
allocates only memory for the three words, but misses the final zero that needs to be written to a null-terminated string
does not communicate clearly, which parameters will or will not be changed be the function
So to fix this:
char* concatWords(const char* w1, const char* w2, const char* w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
char* all = calloc(len + 1, sizeof(char));
strcat(all, w1);
strcat(all, w2);
strcat(all, w3);
return all;
}
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This function needs a fair bit of work. I'm assuming you want to allocate a new string sufficiently large for the job, concatenate w1, w2 and w3 into it, and return that new string.
Firstly, you overwrote the pointer for w1 in this line:
w1 = (char*)malloc(sizeof(char) * len);
So (in that function) you've now lost whatever was pointed to by w1, because w1 is now pointed to newly-allocated memory.
Secondly, you've not allocated enough memory to store the string: you need an extra +1 to include the terminal NUL character.
The original values of w1, w2 and w3 passed into the function were cast to (char *) from the base addresses of char[] arrays, so you can't use w1 = realloc(w1, len+1); - you'll need a new variable to store the new pointer.
Your concatWords() function should look like this:
char* concatWords(const char * const w1,
const char * const w2,
const char * const w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3) + 1; // Note the +1!
new_w = (char*)malloc(sizeof(char) * len);
strcpy(new_w, w1);
strcat(new_w, w2);
strcat(new_w, w3);
return new_w;
}
Note that I've changed the function's parameter types, so that you don't accidentally change the values of the w1, w2 or w3 pointers, or the memory they point to. Always use minimum viable permissions, to prevent the risk of memory corruption. In C terms, if you can const it, const it!
Your printReversedWord(char *word) function won't work either. You're passing word to printf() as the argument to its "%c" format string, not the contents of the memory it's pointing to. You never use the index variable i!
This will have the effect of passing either the first or the last byte of the pointer value as the character to print, depending whether your CPU's big-endian or little-endian.
So if word's value as a pointer was 0x12345678 (the location of the first character in the string it points to), you'd either be printing 0x12 (unprintable control character DC2) or 0x78 ('x') over and over again instead of the reversed contents of word. Of course, the actual effect would depend on the real pointer's value, not my example here.
It should be (something like):
void printReversedWord(const char * const word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word[i]);
}
printf("\n"); // Don't forget the newline!
}
Note the [i] in the printf() argument. It indexes into the char array pointed to by word. Note also (again) the improvement in the parameter type. I've also added a newline at the end.
Finally, looking at:
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
You've defined N, but then explicitly embedded 10 in the scanf() format strings. What happens if you change the value of N at a later point?
I'll leave the solution for that as an exercise for the student. :)
The max length of each string is defined in a globally available token... Why not use it (and temporarily use a bit too much dynamic memory)?
char* concatWords(char *w1, char *w2, char *w3) {
char *p = (char*)malloc( (3*N+1) * sizeof *p );
if( p )
sprintf( p, "%s%s%s", w1, w2, w3 );
return p;
}
One could also add checking that all 3 incoming pointers are not NULL...

Array is being modified

I'm trying to replicate the function strcat. The problem is that my array src is being modified even though I'm just use it to copy.
#include <stdio.h>
char *ft_strcat(char *dest, char *src)
{
int i = 0;
int c = 0;
while (dest[i] != '\0')
i++;
while (src[c] != '\0')
{
dest[i] = src[c];
c++;
i++;
}
dest[i] = '\0';
return dest;
}
int main(void)
{
char src[] = "_And Good Bye";
char dest[] = "Hello World";
char *ptr;
printf("\nString 1: %s\nString 2: %s\n", src, dest);
ptr = ft_strcat(dest, src);
printf("\nAfter strcat function.\nString 1: %s\nString 2: %s\n", src, dest);
return 0;
}
Output:
String 1: _And Good Bye
String 2: Hello World
After strcat function.
String 1: And Good Bye
String 2: Hello World_And Good Bye
After I run ft_strcat(dest, src), my char src looses the character, "_". I don't understand why if I only use it to be copied.
I expect that src is not modified.
dest has exactly enough memory to store "Hello World". When you append src to it you're overwriting adjacent memory. That adjacent memory happens to contain src. There's no guarantee that it will, but stack memory is often allocated this way.
For example, if I print out the memory address of src and dest I see...
printf("src: %p\ndest: %p\n", &src, &dest);
src: 0x7ffeea74e31a
dest: 0x7ffeea74e30e
The memory looks like this.
001111111111111111
ef0123456789abcdef
Hello World0_And Good Bye0
^ ^
dest src
When you concatenate src onto dest you overwrite the adjacent memory resulting in...
001111111111111111
ef0123456789abcdef
Hello World_And Good Bye00
^ ^
dest src
You need to allocate dest to have enough space.
// "Hello World" + "_And Good Bye" + null byte
char dest[25] = "Hello World";
In a real program you'd allocate dest as dynamic memory and reallocate it to have enough space.
char *dest = malloc(12);
strcpy(dest, "Hello world");
dest = realloc(dest, strlen(dest) + strlen(src) + 1);
The actual type of a string literal in C is char [N], wherein N is the minimum amount of space required to store the characters of the string, including the null terminating byte.
In the case where you use a string literal to initialize an array of an unknown size (char foo[] = ...), the resulting array is given the same typing as the string literal.
So in,
char src[] = "_And Good Bye";
char dest[] = "Hello World";
src will have the type char [14], and dest the type char [12].
Knowing this, it becomes obvious that dest does not have enough room to append the contents of src (zero excess memory, in fact). Care must always be taken to guarantee that there is enough room, otherwise you risk Undefined Behavior.
At a minimum, you would need char dest[25], though it may be prudent to drastically oversize your destination buffer.
char dest[512] = "Hello World";
const char *src = "_And Good Bye";
Initializing dest in this way fills the rest of its memory with zeroes.
For starters the function should be declared at least like
char *ft_strcat(char *dest, const char *src);
because the source string is not changed within the function.
Within the function you are trying to append the source string to the end of the destination string but the array that contains the destination string has no enough memory to accommodate also the source string, See the declarations of the arrays
char src[] = "_And Good Bye";
char dest[] = "Hello World";
You need to enlarge the array dest.
For example you could write
char src[] = "_And Good Bye";
char dest[ 2 * sizeof( src )] = "Hello World";
Objects of the type int in general are unable to store all possible lengths of strings. For example the function strlen or the operator sizeof return values of the type size_t
In fact the declarations of the variables i and c
int i = 0;
int c = 0;
are redundant within the function.
The function can look the following way
char * ft_strcat( char *dest, const char *src )
{
char *p = dest;
while ( *p ) ++p;
while ( ( *p++ = *src++ ) != '\0' );
return dest;
}
Try to use Const modifier in source parameter. that's my first point.
char *strcat(char *destination, const char *source)

Trying to troubleshoot concatenating a string in C

I am trying to concatenate two strings together. I put two strings into two arrays and created a third array that is the size of the two strings. Then I use the for loop to print out one letter at a time.
The program gets to This before crashing. There are no error codes or debug messages in the IDE!!! How do I debug my program and what kind of mindset should I have if I have no obvious error messages to go off of when something like this happens?
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
int pointerArrays() {
char strOne[] = {"This is the first string array."};
char strTwo[] = {"This is the second string array."};
char *px, *py, *pz;
px = strOne;
py = strTwo;
pz = (char *) malloc(1 + sizeof(px) + sizeof(py));
strcpy(pz, px);
strcpy(pz, py);
for (int i = 0; i < sizeof(pz); i++) {
printf("%c", pz[i]);
}
return 0;
}
int main(void) {
pointerArrays();
return 0;
}
There are two problems. First of all, this here doesn't work:
malloc(1 + sizeof(px) + sizeof(py));
sizeof(px) doesn't evaluate to the size of the string, it just evaluates to the size of a char*, which isn't what you intended. Instead, try something like this:
pz = (char *)malloc(strlen(strOne) + strlen(strTwo) + 1);
The second problem is that instead of concatenating the two strings, you're copying them over each other. The second call needs to be
strcat(pz, py);
Rather than strcpy again.
On a side note, when you print a string, instead of just looping through the array, you can also just use the %s format specifier:
printf("%s", pz);
Last but not least, don't forget to free the memory when you're done:
free(pz);
Insert another line to see what the argument to malloc() rceives:
printf ("malloc(%d)\n", 1 + sizeof(px) + sizeof(py));
I bet you can figure it out from there.
Just a sidenote (not the reason of your crash): you are copying to the same location twice:
strcpy(pz, px);
strcpy(pz, py);
should be
strcpy(pz, px);
strcpy(pz + strlen(px), py);
not fixing it would cause y to right OVER x
But the main issue is using sizeof instead of strlen. sizeof will return the pointer's size (4 or 8 typically), while strlen will actually return the length of the string (which is what you expected)
using sizeof is very dangerous and will fail in most real life usage cases.
it is enough to change
char strOne[] = "This is the first string array.";
char strTwo[] = "This is the second string array.";
to
char strOne[64] = "This is the first string array.";
char strTwo[64] = "This is the second string array.";
or
char *strOne = "This is the first string array.";
char *strTwo = "This is the second string array.";
and the result of your function will be far from the expected.
Always use strlen to get the string length.
Here you have much more universal and safer solution:
char *concatenate(const char *str1, const char *str2)
{
size_t str1len = strlen(str1), str2len = strlen(str2);
char *res = malloc(str1len + str2len + 1);
if(res)
{
strcpy(res, str1);
strcpy(res + str1len, str2);
}
return res;
}

String concatenation in c

I have a variable called char *inputstr, if the string length given to variable is a an odd number, I need to insert a "0" at the beginning of the string variable inputstr.
For example:
char *inputstr = "1ABc2" .
Now I need to append "0" and make it "01ABc2". How do I achieve this?
char a[2] = "0";
char *inputstr = "1ABc2";
if( strlen (inputstr) % 2 == 0)
{
strcat (a, inputstr);
strcpy (inputstr, a);
}
if( condition)
{
Using inputstr variable // here string value is along with junk characters
}
First, you need to set aside a buffer large enough for your target string:
/**
* Attempting to modify the contents of a string literal leads to undefined
* behavior; to be safe, pointers to literals should be declared "const".
* You are not going to write the modified string back to what inputstr
* points to.
*/
const char *inputstr = "1ABc2";
/**
* Compute the size of the target buffer, which is the length of inputstr
* plus 1 for the leading "0" plus 1 for the string terminator.
*/
size_t targetBufferLength = strlen( inputstr ) + 2;
/**
* Allocate the target buffer. Since targetBufferLength is a run-time
* value, this will only work with C99 and later. If you're using C90
* or earlier, targetBufferLength will have to be a compile-time constant,
* so you'll have to compute it manually and declare it as
*
* char targetBuffer[7]; // 5 + 1 + 1
*
* or
*
* #define TARGETBUFFERLENGTH 7
* ...
* char targetBuffer[TARGETBUFFERLENGTH];
*
*/
char target[targetBufferLength] = {0};
Now you can write your new string to the target buffer. You can use sprintf:
sprintf( target, "%s%s", "0", inputstr );
or you can use a combination of strcpy and strcat (or strncpy and strncat for the paranoid in the room):
strcpy( target, "0" );
strcat( target, inputstr );
Be aware of the potential for buffer overflow with either method. Make sure that your target buffer is large enough for the final string. Using strcpy and strcat is risky, but using strncpy and strncat in their place isn't a guarantee of success either.
You could also allocate the buffer dynamically:
char *target = calloc( targetBufferLength, sizeof *target );
The advantage of this is that you can resize the buffer as necessary if it
isn't big enough:
if ( strlen( target ) + strlen( newStr ) > targetBufferLength )
{
char *tmp = realloc( target, (targetBufferLength + strlen( newStr ) + 1) * sizeof *target );
if ( tmp )
{
target = tmp;
targetBufferLength += strlen( newStr ) + 1;
strcat( target, newStr );
}
else
{
// could not extend target buffer, don't append
}
}
The disadvantage is that you now have memory management issues, and you have to remember to free the buffer when you're done with it.
you can use memmove as the areas overlap but IMO is better to write a simple routine for it:
src - the string to append in front of the dest. dest has to be big enough to accommodate its new characters
char *straddfront(char *dest, const char *src)
{
size_t srclen = strlen(src);
size_t destlen = strlen(dest);
for (int i = 0; i <= destlen; i++)
*(dest + destlen + srclen - i) = *(dest + destlen - i);
strncpy(dest, src, srclen);
return dest;
}
You are searching for strcat (or really better strncat) defined in string.h
But you have to notice:
strcat concatenates two strings, thus you need to use the string "0" as the destination
if destination is not large enough, program behavior is unpredictable
the destination (the first argument of strcat i the only one that is modified, not the second argument (that is actually a const char*)

How to replace a piece of const char* with another string in C?

Assume that you have a link like http://1.1.1.1/test.mpg. Then you want to change it to http://1.1.1.1/test.mkv. How can you change "mpg" to "mkv" programmatically in C? I tried to use strtok and strcpy but I am not good in C so I couldn't do it.
The following is the solution, but there is one thing left to you for experimenting!
The malloc'ed memory is not free'd in the below code. Try it on your own!
One other drawback is, it does replace only the first occurrence of the string.. So you cna improve this code to replace all the occurrence of the string!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strrep(char *str, char *o_s, char *n_s)
{
char *newstr = NULL;
char *c = NULL;
/* no substring found */
if ((c = strstr(str, o_s)) == NULL) {
return str;
}
if ((newstr = (char *) malloc((int) sizeof(str) -
(int) sizeof(o_s) +
(int) sizeof(n_s) + 1)) == NULL) {
printf("ERROR: unable to allocate memory\n");
return NULL;
}
strncpy(newstr, str, c-str);
sprintf(newstr+(c-str), "%s%s", n_s, c+strlen(o_s));
return newstr;
}
int main(void)
{
char str[] = "http://1.1.1.1/test.mpg";
char old_s[] = "mpg";
char new_s[] = "mkv";
char *str_new = strrep(str, old_s, new_s);
if (str_new != NULL) {
printf("Original : %s\n", str);
printf("Replaced : %s\n", str_new);
}
return 0;
}
$ gcc strrep.c
$ ./a.out
Original : http://1.1.1.1/test.mpg
Replaced : http://1.1.1.1/test.mkv
$
You shouldn't change a const char*. Changing it will lead to undefined behavior. Usually, a const is there for a reason.
That aside, you should create a new char*, copy the contents inside it, and modify that.
Changing a character from a const char * should not be allowed by the compiler, and if done via an explicit cast to char * will lead to undefined behaviour.
If you declare the string as an array that is stored either globally or on the stack:
char str[] = "http://1.1.1.1/test.mpg";
Then you are not dealing with const char * and altering characters is OK. Otherwise,
char *str = "http://1.1.1.1/test.mpg";
the string literal will possibly be stored in a read-only protected area of the process and an attempt to write there will most probably generate a protection fault.
A const char * pointer cannot and must not be changed. This is indicated by the const, that obviously tells that this pointer points to constant characters.
If you need to change something in this variable programatically your only choice is to first copy it to another variable of sufficient size and change that. For this you can just change the last few bytes by using array indexing. Something like this will work:
const char * url = "http://1.1.1.1/test.mpg";
char * url2;
url2 = malloc( strlen( url ) + 1 );
strcpy( url2, url ); // no need to use strncpy
url2[ strlen( url2 ) - 3 ] = 'm';
url2[ strlen( url2 ) - 2 ] = 'k';
url2[ strlen( url2 ) - 1 ] = 'v';
Note that in this case this only works so smoothely, because the length of "mkv" and "mpg" is the same. If it is not you need some more complicated techiques.

Resources