Strange behaviour when implementing strcat in C - c

I'm trying to implement the strcat function myself. Here's my code:
char *my_strcat(char *dst, const char* src) {
char *tmp = dst;
while(*tmp) {
tmp ++;
}
while(*tmp++ = *src++);
return dst;
}
However, when I try to test this function, I get only the src string. (i.e. I'm expecting to get dst+src, but the returned value is the same as src)
As we can tell from the code, in the first while loop, I'm trying to move tmp pointer to the end of dst.
However,
I tried to add a printf in the first while loop, nothing is printed out, which indicates that it didn't even entered the loop.
Then I tried to used if (*tmp == '\0') print something, and found that *tmp == '\0' is true.
But I'm pretty sure that tmp is a non-empty string, so *tmp should point to the first character of the string (I think). So I'm feeling confused about it. Can anyone tell why this happens and how can I fix it?
Edit:
The calling code is
char *subpath = "";
subpath = my_strcat(subpath, path);
path is a const char* read from the command.
Do I need to assign the value back to subpath? Or just calling my_strcat is enough?

There are two problems here:
char *subpath = "";
subpath = my_strcat(subpath, path);
subpath points to a string of length 0, there is not enough space to append anything.
subpath points to a string literal and writing into string literals is undefined behaviour, on modern desktop platforms your program usually crashes.
You want something like this:
char subpath[100] = "";
char *foo;
foo = my_strcat(subpath, path);
or just
char subpath[100] = "";
my_strcat(subpath, path);
or
char subpath[100] = "Hello ";
my_strcat(subpath, "world!");
printf("%s\n", subpath); // prints Helllo World!

Related

How to break a string in C with /

I have a string with the following pattern :
char *str = "ai/aj/module_mat.mod";
and I want to select module_mat as my final string for the further logic. I have tried to used rindex() so that I can get the final part of the string. But I am not able to do this in C. What am I doing wrong?
The code I am trying is -
char *first = rindex(str, "/");
char *first = strtok(first, ".");
Your mistake is right here:
char *str = "ai/aj/module_mat.mod";
Since str points to a constant, this should be:
const char *str = "ai/aj/module_mat.mod";
Now your compiler should show you the other problems.
Similarly:
char *first = rindex(str, "/");
Since rindex is returning a pointer into the constant you passed it, that pointer should also be const.
char *first = strtok(first, ".");
Hmm, what do the docs for strtok say:
If a delimiter byte is found, it is overwritten with a null byte
to terminate the current token, and strtok() saves a pointer to the following byte; ...
So strtok modifies the thing the pointer points to, so passing it a pointer to a constant is bad! You can't modify a constant.
First off, the string literal is immutable, so it is very dangerous to bind it to a mutable char pointer. First fix your code:
const char* str = "ai/aj/module_mat.mod";
Next, use strchr:
#include <string.h>
const char* p = strchr(str, '/');
if (p != NULL) {
++p;
printf("Last part: %s\n", p);
} else {
printf("No '/' found in string %s.\n", str);
}
If a / is found in the string, p will point to it, and hence p can be used as the suffix substring of the original string, and there's no need to modify the original string. We advance p by one to skip past the / and are left with the final part of the string.

"integer from pointer without cast" when adding nullbyte to pointer

I was messing around with all of the string functions today and while most worked as expected, especially because I stopped trying to modify literals (sigh), there is one warning and oddity I can't seem to fix.
#include <stdio.h>
#include <string.h>
int main() {
char array[] = "Longword";
char *string = "Short";
strcpy(array, string); // Short
strcat(array, " "); // Short (with whitespace)
strcat(array, string); // Short Short
strtok(array, " "); // Short
if (strcmp(array, string) == 0)
{
printf("They are the same!\n");
}
char *substring = "or";
if (strstr(array, substring) != NULL)
{
printf("There's a needle in there somewhere!\n");
char *needle = strstr(array, substring);
int len = strlen(needle);
needle[len] = "\0"; // <------------------------------------------------
printf("Found it! There ya go: %s",needle);
}
printf("%s\n", array);
return 0;
}
Feel free to ignore the first few operations - I left them in because they modified array in a way, that made the strstr function useful to begin with.
The point in question is the second if statement, line 32 if you were to copy it in an editor.
(EDIT: Added arrow to the line. Sorry about that!)
This line is wrong:
needle[len] = "\0";
Doublequotes make a string literal, whose type is char *. But needle[len] is a char. To make a char literal you use singlequotes:
needle[len] = '\0';
See Single quotes vs. double quotes in C or C++
Your second strcat call overruns the end of array, corrupting whatever happens to be after it in memory. Once that happens, the later code might do just about anything, which is why writing past the end of an array is undefined behavior

c copying first letter of ptr

I have no idea what is wrong with the following code. I perused stackoverflow without finding much assistance.
char * abbreviate_name( const char * full_name) {
int length = strlen(full_name) + 1;
char * final = malloc(length);
*answer = '\0';
char ptr[51];
// above is where I declare all my variables
strncpy(ptr, full_name, length); // copy full_name because it is a const
// ...
final = &ptr[1]; // this line copies all of ptr when I do a prinf on it
I'm just wondering how to get the first letter of ptr.
I tried playing with the ptrs and addresses and couldn't get it to work.
to get the first char of a pointer you can either go *ptr or ptr[0].
Your code has other problems though, assign to final doesn't copy, it just points final to another location, in this case you are going to point to a stack variable and it's going to fail badly.
instead, just strcpy into final and get rid of "ptr"
final[0] = ptr[0];
*final = *ptr;
final[0] = *ptr;
*final = ptr[0];
You can, in addition to Keith's answer, accomplish the allocation and copy of full_name to final in one step by making use of strdup:
char *abbreviate_name (const char *full_name) {
char *final = strdup (full_name);
...
strdup will call malloc to dynamically allocate storage sufficient to hold full_name. Just as if you had used malloc, you are responsible for freeing the memory when it is no longer needed.
I am probably shooting in the dark and writing an answer which is very much prone to down-votes, but let me begin.
Probably OP is looking for a function which provides and abbreviated version of a string, thus first letter of each of the given words in a string ( full_string ). reason I thought this because of char * return type and function name.
char * abbreviate_name( const char * full_name) ;
If I am correct in understanding the question, then you are probably looking for
strtok
and here is a snippet for extracting what you are looking for
char *str1, *saveptr1, *token ;
for ( str1 = full_name; ; str1 = NULL) {
token = strtok_r(str1, " " , &saveptr1); // delimited with " "
if ( token == NULL ) {
break; // break once no tokens available
}
printf("%c ", *token); // Extract first letter for each word, which probably form the abbreviated string you are looking for
}

Return a string on C

I'm getting a core dump that I have no clue how to solve. I have searched other questions and googled my problem but I just can't figure out how to solve this...
Here is the code:
const char checkExtension(const char *filename)
{
const char *point = filename;
const char *newName = malloc(sizeof(filename-5));
if((point = strrchr(filename,'.palz')) != NULL )
{
if(strstr(point,".palz") == 0)
{
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
return point;
}
The function was called char checkExtensions(const char *filename). I added the const due the solutions that I have found online but so far I haven't been able to make it work...
Thank you in advance for the help!
You have many problems with your code. Here are some of them:
Your function returns char which is a single character. You need to return a pointer to an array of characters, a C string.
You don't allocate the right amount of memory. You use sizeof() on a pointer which yields the size of a pointer.
You make it impossible for the caller to know whether or not to deallocate memory. Sometimes you heap allocate, sometimes not. Your approach will leak.
You pass '.palz', which is a character literal, to strrchr which expects a single char. What you mean to pass is '.'.
A better approach is to let the caller allocate the memory. Here is a complete program that shows how:
#include <string.h>
#include <stdio.h>
void GetNewFileName(const char *fileName, char *newFileName)
{
const char *dot = strrchr(fileName, '.');
if (dot)
{
if (strcmp(dot, ".palz") == 0)
{
size_t len = dot - fileName;
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
}
size_t len = strlen(fileName);
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
int main(void)
{
char fileName[256];
char newFileName[256];
strcpy(fileName, "foo.bar");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz.txt");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
return 0;
}
Output
foo.bar foo.bar
foo.bar.palz foo.bar
foo.bar.palz.txt foo.bar.palz.txt
Note that strcmp compares sensitive to letter case. On Windows file names are insensitive to case. I will leave that issue for you to deal with.
By letting the caller allocate memory you allow them to chose where the memory is allocated. They can use a local stack allocated buffer if they like. And it's easy for the caller to allocate the memory because the new file name is never longer than the original file name.
This is most probably your problem:
const char *newName = malloc(sizeof(filename-5));
First, filename is of type const char *, which means that (filename - 5) is also of this type. Thus, sizeof(filename - 5) will always return the size of the pointer datatype of your architecture (4 for x32, 8 for x64).
So, depending on your architecture, you are calling either malloc(4) or malloc(8).
The rest of the code doesn't even compile and it has serious string manipulation issues, so it's hard to tell what you were aiming at. I suppose the strncpy() was copying too much data into newName buffer, which caused buffer overflow.
If your goal was to extract the filename from a path, then you should probably just use char *basename(char *path) for that.
Several pretty major problems with your code. Making it up as I type, so it may not fix everything first time right away. Bear with me.
You need to return a char *, not a char.
const char checkExtension(const char *filename)
{
const char *point = filename;
You malloc memory but the instruction flow does not guarantee it will be freed or returned.
sizeof(filename) should be strlen(filename), minus 5 (sans extension) but +1 (with terminating 0).
const char *newName = malloc(sizeof(filename-5));
strrchr searches for a single character. Some compilers allow "multibyte character constants", but they expect something like 2 -- not five. Since you know the length and start of the string, use strcmp. (First ensure there are at least 5 characters. If not, no use in testing anyway.)
if((point = strrchr(filename,'.palz')) != NULL ) {
Uh, strstr searches for a string inside a string and returns 0 if not found (actually NULL). This contradicts your earlier test. Remove it.
if(strstr(point,".palz") == 0)
{
strncpy copies n characters, but famously (and documented) does not add the terminating 0 if it did not get copied. You will have to this yourself.
.. This is actually where the malloc line should appear, right before using and returning it.
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
You return the original string here. How do you know you need to free it, then? If you overwrote a previous char * its memory will be lost. Better to return a duplicate of the original string (so it can always be freed), or, as I'd prefer, return NULL to indicate "no further action needed" to the calling routine.
return point;
}
Hope I did not forget anything.
There are several problems with your code:
Wrong return type:
const char checkExtension(const char *filename){
You need to return a pointer (const char *), not a single character.
Not enough memory:
const char checkExtension(const char *filename){
const char *newName = malloc(sizeof(filename-5));
You are allocating the size of a pointer (char *), which is typically 4 or 8. You need to call strlen() to find out the size of the string:
Multibyte character:
if((point = strrchr(filename,'.palz')) != NULL ) {
'.palz' is a multibyte character literal. While this is allowed in C, its value is implementation-defined and might not do what you expect. String literals use double quotes (".palz").
No terminating zero:
strncpy(newName, filename, strlen(filename)-5);
Note that strncpy() doesn't necessarily null-terminate the target string. It write at most strlen(filename)-5 characters. If the source string contains more characters (as in your case), it will not write a terminating zero.
I'm not sure what exactly you're trying to do. Perhaps something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *checkExtension(const char *filename)
{
int len = strlen (filename)-5;
char *newName = NULL; /* return NULL on allocation failure. */
if (len > 0 && !strcmp (filename+len, ".palz")) {
newName = malloc (len+1);
if (newName) {
memcpy (newName, filename, len);
newName[len] = 0;
}
}
return newName;
}
int main (int ac, char **av)
{
if (ac > 1) {
const char *p = checkExtension (av[1]);
puts (p ? p : "NULL");
} else {
puts ("?");
}
return 0;
}
Multiple errors here. You have not said what you are trying to achieve, that has to be implied from the code. You have declared point and newName as const, yet reassigned with a value. You have tested strstr() == 0 when it should be strstr() == NULL. You have called strrchr(filename,'.palz') but sent a string instead of a char. Then you have returned the local variable point which goes out of scope before you get a chance to use it, because it was not declared as static. So it's irrelevant whether you returned a char or a char pointer.
char *checkExtension(const char *filename) {
// if filename has extension .palz return a pointer to
// the filename stripped of extension or return NULL
char *point;
static char newName[512];
strncpy(newName, filename, 512);
if ((point = strstr(newName, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
// printf("%s\n",newName ); // use only for debugging
return newName;
}
}
return NULL;
}
Alternatively provide a string the function can modify -
char *checkExtension(const char *filename, char *newName) { ... }
Alternatively provide a filename the function can modify -
char *checkExtension(char *filename) {
char *point;
if ((point = strstr(filename, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
return filename;
}
}
return NULL;
}

how to effectively use strtok function

Yes, I'm a newbie as well. And I have been having this problem for quite some time. I'm trying to use strtok to split off a string, but the thing is it does not work. I have looked at the example on the man-pages as well as those online, and I still don't have the answer.
In the code below, I tried to use the sample code given as an answer in this site. The original while loop is:
char str[] = "hello world how are you?\n";
char *res;
res = strtok(str, " \n");
puts(res);
while (res != NULL)
{
res = strtok(NULL, " \n");
if(res!=NULL)
puts(res);
}
but when a change the str to data, and its respective delimiters (&=), it becomes a Segmentation Fault. How do I fix this? What's wrong in the code? Here is the complete code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *data;
data = "integer1=1&integer2=2&integer3=3&integer4=4";
puts(data);
char str[] = "hello world how are you?\n";
char *res;
res = strtok(data, "=&");
puts(res);
while (res != NULL)
{
res = strtok(NULL, "=&");
if(res!=NULL)
puts(res);
}
return 0;
}
by the way, the strtok_r function doesn't work either.
This:
char str[] = "hello world how are you?\n";
creates an array and initializes it with the contents of the string literal. This, however:
char *data;
data = "integer1=1&integer2=2&integer3=3&integer4=4";
declares data to be a pointer to the first character of the string literal, which is, of course, read-only, so when strtok() tries to modify it, it fails (invoking undefined behavior).
Notes:
So that's why you declare pointers to string literals as const char * and explicitly not as char *, and if you do so, I will find you and const-qualify you.
Arrays are not pointers, they never were, and they never will be either.
The behaviour you're observing can be explained by question 1.32 in com.lang.c FAQ:
What is the difference between these initializations?
char a[] = "string literal";
char *p = "string literal";
My program crashes if I try to assign a new value to p[i].
And the answer is:
A string literal (the formal term for a double-quoted string in C source) can be used in two slightly different ways:
As the initializer for an array of char, as in the declaration of char a[] , it specifies the initial values of the characters in that array (and, if necessary, its size).
Anywhere else, it turns into an unnamed, static array of characters, and this unnamed array may be stored in read-only memory, and which therefore cannot necessarily be modified. In an expression context, the array is converted at once to a pointer, as usual (see section 6), so the second declaration initializes p to point to the unnamed array's first element.
strtok break memory block. And literal strings can't modofiy. So you can't use strtoke for both.
Try this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char *data;
data = "integer1=1&integer2=2&integer3=3&integer4=4";
char *cur, *res;
cur = data;
res = strpbrk(cur, "=&");
while (res != NULL)
{
fwrite(cur, 1, res-cur, stdout);
fputc('\n', stdout);
cur = res + 1;
res = strpbrk(cur, "=&");
}
fputs(cur, stdout);
return 0;
}
This doesn't modify memory block.

Resources