Is this unsafe to use in C? - c

Hello I've come upon a problem. Im not very experienced in C.
I am trying to concatenate one char to my path variable.
But when I am running this line of code my other string variable gets "overriden" or behaves weird afterwards. When commented out everything works normally. I don't want to post the whole code here inseat I am just curios if this single line is somehow unsafe to run.
strcat(path, "/");
I also tried:
//edit i actually tried strcat but later strncat copied the line while reversing the changes//
char temp = '/';
strncat(path, &temp);
I am stuck wayyy to long on this so maybe someone can help.

For starters the function strncat has three parameters
char *strncat(char * restrict s1, const char * restrict s2, size_t n);
So this call
strncat(path, "/");
will not compile.
Apart from this error this code snippet
char temp = '/';
strncat(path, &temp);
has one more error that is the expression &temp does not point to a string.
You can append a character to a string only if the array containing the string has enough space to accommodate one more character. For example you may not change a string literal.
If the array containing the string has enough memory to accommodate the character '/' then you can write
strcat( path, "/" );
or
size_t n = strlen( path );
path[n++] = '/';
path[n] = '\0';
Or as #Barmar correctly pointed in his comment to the answer you could use strncat the following way
char temp = '/';
strncat(path, &temp, 1);

Related

Why is strcpy appending junk characters to the end of a small fraction of strings?

I have a function that takes as its input a string containing a hyperlink and is attempting to output that same hyperlink except that if it contains a question mark, that character and any characters that follow it are purged.
First, I open a text file and read in a line containing a link and only a link like so:
FILE * ifp = fopen(raw_links,"r");
char link_to_filter[200];
if(ifp == NULL)
{
printf("Could not open %s for writing\n", raw_links);
exit(0);
}
while(fscanf(ifp,"%s", link_to_filter) == 1)
{
add_link(a,link_to_filter, link_under_wget);
};
fclose(ifp);
Part of what add_link does is strip the unnecessary parts of the link after a question mark (like with xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/online-giving/step1.php?new=1) which are causing an issue with my calls to wget. It does this by feeding link_to_filter through this function remove_extra, seen below.
char * remove_extra(char * url)
{
char * test = url;
int total_size;
test = strchr(url,'?');
if (test != NULL)
{
total_size = test-url;
url[total_size] = '\0';
}
return url;
}
at the end of remove_extra, upon returning from remove_extra and immediately prior to using strcpy a call to printf like so
printf("%s",url);
will print out what I expect to see (e.g. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/online-giving/step1.php without the '?' or trailing characters), but immediately after this block of code runs
struct node * temp = (struct node *)malloc(sizeof(struct node));
char * new_link = remove_extra(url);
temp->hyperlink =(char *)malloc(strlen(new_link) * sizeof(char));
strncpy(temp->hyperlink, new_link, strlen(new_link));
the result of a printf on member hyperlink occasionally has a single, junk character at the end (sometimes 'A' or 'Q' or '!', but always the same character corresponding to the same string). If this were happening with every link or with specific types of links, I could figure something out,
but it's only for maybe every 20th link and it happens to links both short and long.
e.g.
xxxxxxxxxxxxxxxxxxxx/hr/ --> xxxxxxxxxxxxxxxxxxxx/hr/!
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/windows-to-the-past/ --> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/windows-to-the-past/Q
This is happening both with strcpy and homemade string copy loops so I'm inclined to believe that it's not strcpy's fault, but I can't think of where else the error would lie.
If you compute len as the length of src, then the naive use of strncpy -- tempting though it might be -- is incorrect:
size_t len = strlen(src);
dest = malloc(len); /* DON'T DO THIS */
strncpy(dest, src, len); /* DON'T DO THIS, EITHER */
strncpy copies exactly len bytes; it does not guarantee to put a NUL byte at the end. Since len is precisely the length of src, there is no NUL byte within the first len bytes of src, and no NUL byte will be inserted by strncpy.
If you had used strcpy instead (the supposedly "unsafe" interface):
strcpy(dest, src);
it would have been fine, except for the fact that dest is not big enough. What you really need to do is this:
dest = malloc(strlen(src) + 1); /* Note: include space for the NUL */
strcpy(dest, src);
or, if you have the useful strdup function:
dest = strdup(src);
Mostly likely You forgot to copy a null terminator at the end of string, remember that strlen(str) gives the number of visible characters, You also need '\0' at the end.
You need to do
temp->hyperlink =(char *)malloc(strlen(new_link)+1);//char is one byte, sizeof(char)=1
and
strcpy(temp->hyperlink, new_link); Should work fine.
Why not use strdup?

separating a string with strtok

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.

explanation of what my code is doing (C)

char *extractSubstring(char *str)
{
char temp[256];
char *subString; // the "result"
printf("%s\n", str); //prints #include "hello.txt"
strcpy(temp, str); //copies string before tokenizing
subString = strtok(str,"\""); // find the first double quote
subString = strtok(NULL,"\""); // find the second double quote
printf("%s\n", subString); //prints hello.txt
strcpy(str, temp); //<---- the problem
printf("%s", subString); //prints hello.txt"
return subString;
}
After I strcpy, why does it add a quotation? When I comment out the 2nd strcpy line, the program works. The printfs will be deleted out of my program. I was just using it to show what was happening with my program.
Can someone please explain to me what is going on? Thank you.
It is important to realize that strtok() modifies the source string in-place, and returns pointers into it.
Thus, the two calls to strtok() turn str into
#include \0hello.txt\0
^ subString points here
(For simplicity, I don't show the final terminating \0).
Now, the second ("problematic") strcpy() changes str back to:
#include "hello.txt"
^ subString still points here
This is what makes the " reappear in subString.
One way to fix it is by tokenizing a copy and keeping the original intact. Just make sure that your function doesn't return a pointer to an automatic variable (that would go out of scope the moment the function returns).
The first thing to know is that strtok modifies the first argument (str), if this is a constant (such as when calling extractSubstring like so: extractSubstring("#include \"hello.txt\"");) then this leads to undefined behaviour.
You already copy str into temp so you should use temp in your calls to strtok. When the tokenizing is done you should copy subString into a variable that you either allocate on the heap (malloc) or that you pass to extractSubstring as an extra parameter. You can't return a pointer to a local array because the array runs out of scope the the function ends.
So in summary:
subString = strtok(temp, "\"");
subString = strtok(NULL, "\"");
char * ret = malloc(strlen(subString));
strcpy(ret, subString);
ret[strlen(ret)] = '\0';
return ret;

Substring C from string like folder1/file1.txt

i have strings like "folder1/file1.txt" or "foldername1/hello.txt" and i need to take the substring that identify the folder name with the slash (/) included (example: from "folder1/file1.txt" i need "folder1/"). The folders name are not all with the same length.
How can i do this in C?? thanks
First, find the position of the slash with strchr:
char * f = "folder/foo.txt"; // or whatever
char * pos = strchr( f, '/' );
then copy into a suitable place:
char path[1000]; // or whatever
strncpy( path, f, (pos - f) + 1 );
path[(pos-f)+1] = 0; // null terminate
You should really write a function to do this, and you need to decide what to do if strchr() returns NULL, indicating the slash is not there.
Find the last '/' character, advance one character then truncate the string. Assuming that the string is modifiable, and is pointed to by char *filename;:
char *p;
p = strrchr(filename, '/');
if (p)
{
p[1] = '\0';
}
/* filename now points to just the path */
You could use the strstr() function:
char *s = "folder1/file1.txt";
char folder[100];
char *p = strstr(s, "/");
if (0 != p)
{
int len = p - s + 1;
strncpy(folder, s, len);
folder[len] = '\0';
puts(folder);
}
If you work on a POSIX machine, you can look up the dirname() function, which does more or less what you want. There are some special cases that it deals with that naïve code does not - but beware the weasel words in the standard too (about modifying the input string and maybe returning a pointer to the input string or maybe a pointer to static memory that can be modified later).
It (dirname()) does not keep the trailing slash that you say you require. However, that is seldom a practical problem; adding a slash between a directory name and the file is not hard.

Typecast:LPCTSTR to Char * for string concatenate operation

Can u Give solution for this code of typecasting, LPCTSTR(here lpsubkey) to Char*
for below code snippet ,
char* s="HKEY_CURRENT_USER\\";
strcat(s,(char*)lpSubKey);
printf("%S",s);
here it makes error of access violation ,so what will be the solution for that?.
...thanks in advance
There are several issues with your code that might well lead to the access violation. I don't think any have anything to do with the cast you mentioned.
You are assigning a pointer to the first element of a fixed size char array to a char * and then attempt to append to this using strcat. This is wrong as there is no additional space left in the implicitly allocated string array. You will need to allocate a buffer big enough to hold the resulting string and then copy the string constant in there before calling strcat. For example, like so:
char *s = (char*)malloc(1024 * sizeof(char));
strcpy(s, "HKEY_CURRENT_USER\\");
strcat(s, T2A(lpSubKey));
printf("%s", s);
free(s);
Please note that the fixed size array I'm allocating above is bad practise. In production code you should always determine the correct size of the array on the go to prevent buffer overflows or use functions like strncat and strncpy to ensure that you are not copying more data into the buffer than the buffer can hold.
These are not the same thing. What are you trying to do?
The problem is you are trying to append to a string that you have not reserved memory for.
Try:
char s[1024] = "HKEY_CURRENT_USER";
strcat(s,(char*)lpSubKey );
printf("%S",s);
Do be careful with the arbitrary size of 1024. If you expect your keys to be much longer your program will crash.
Also, look at strcat_s.
ATL and MFC has set of macros to such conversion, where used next letters:
W - wide unicode string
T - generic character string
A - ANSI character string
OLE - BSTR string,
so in your case you need T2A macros
strcat does not attempt to make room for the combination. You are overwriting memory that isn't part of the string. Off the top of my head:
char *strcat_with_alloc(char *s1, char *s2)
{
if (!s1 || !s2) return NULL;
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *dest = (char *)malloc(len1 + len2 + 1);
if (!dest) return NULL;
strcpy(dest, s1);
strcat(dest, s2);
return dest;
}
now try:
char* s="HKEY_CURRENT_USER\\";
char *fullKey = strcat_with_alloc(s,(char*)lpSubKey);
if (!fullKey)
printf("error no memory");
else {
printf("%S",fullKey);
free(fullKey);
}

Resources