I am new to C and working on a project where I need to be able to get a substring but I am having difficulty as there is a compiler warning about the initialisation and a core dump if I attempt to run the program which I am not sure how to resolve.
I have a function called substring which passes in the source string, the start index and to end index.
Below is my substring function.
char *substring(char * src, int from, int to)
{
char * dst = "\0";
strncpy(dst, src+from, to);
return dst;
}
Below is how I am calling the function
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
rowReport is a MYSQL_ROW, and bPartyColIndex is just an int equal 0 to reference the correct column from the MYSQL_ROW.
At the moment the line above has a compiler warning of:
warning: initialization makes pointer from integer without a cast
which I am unable to determine how to fix this warning.
If I try and run the program I then get a coredump which says that it is a segmentation fault within the substring function performing the strncpy.
char * dst = "\0";
strncpy(dst, src+from, to);
That's why there's a segfault. Assigning dst with \0 isn't correct ! Actually, dst isn't big enough to store the src + from bytes. You should allocate it instead:
char *substring(char * src, int from, int to)
{
size_t src_size = to + 1 - from;
char * dst = malloc(src_size); // Assuming str + from is ok
if (dst != 0)
strncpy(dst, src+from, src_size);
return dst;
}
In this case, you will have to free dst :
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
puts(debug);
free(debug);
You need to allocate new memory for your substring, or have the caller pass in the desired buffer. What you're trying won't work, you are never allocating the storage.
You need something like:
char * substring(const char *str, int from, int to)
{
const size_t len = to - from + 1;
char *out = malloc(len + 1);
if(out != NULL)
{
memcpy(out, str + from, len);
out[len] = '\0';
}
return out;
}
Then the caller needs to free() the returned pointer when done with it.
Your substring function, by itself, has some issues. You are not allocating any space for dst and copying into it. That could lead to a seg fault. You are also not checking if either from or to my go beyond the end of string (can be checked with strlen).
You should also check that from is less than to.
First:
char * dst = "\0";
strncpy(dst, src+from, to);
You are writing to a string literal but string literals are immutable in C. This invokes undefined behavior.
Second:
rowReport[bPartyColIndex] has to be a char * but it is of a different type.
You didn't specify the type of rowReport in your question, but assuming it is a char array you have to pass &rowReport[bPartyColIndex] instead of rowReport[bPartyColIndex] to substring function.
Related
I am learning C and I have written the following strcat function:
char * stringcat(const char* s1, const char* s2) {
int length_of_strings = strlen(s1) + strlen(s2);
char s3[length_of_strings + 1]; // add one for \0 at the end
int idx = 0;
for(int i=0; (s3[idx]=s1[i]) != 0; idx++, i++);
for(int i=0; (s3[idx]=s2[i]) != 0; idx++, i++);
s3[idx+1] = '\0';
// s3 is a character array;
// how to get a pointer to a character array?
char * s = s3;
return s;
}
That part that looks odd to me is where I have to "re-assign" the character array to a pointer, otherwise C complains that my return is a memory address. I also tried "casting" the return value to (char *) s3, but that didn't work either.
What is the most common way to do this "conversion"? Is this a common pattern in C programs?
There are many ways to handle this situation, but returning a pointer to stack-allocated memory inside the function isn't one of them (the behavior is undefined; consider this memory untouchable once the function returns).
One approach is to allocate heap memory using malloc inside the function, build the result string, then return the pointer to the newly allocated memory with the understanding that the caller is responsible for freeing the memory.
Here's an example of this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *stringcat(const char* s1, const char* s2) {
int i = 0;
int s1_len = strlen(s1);
int s2_len = strlen(s2);
char *result = malloc(s1_len + s2_len + 1);
result[s1_len+s2_len] = '\0';
for (int j = 0; j < s1_len; j++) {
result[i++] = s1[j];
}
for (int j = 0; j < s2_len; j++) {
result[i++] = s2[j];
}
return result;
}
int main(void) {
char *cat = stringcat("hello ", "world");
printf("%s\n", cat); // => hello world
free(cat);
return 0;
}
Another approach is for the caller to handle all of the memory management, which is similar to how strcat behaves:
/* Append SRC on the end of DEST. */
char *
STRCAT (char *dest, const char *src)
{
strcpy (dest + strlen (dest), src);
return dest;
}
man says:
The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.
The problem isn't converting from array to pointer; that happens all the time implicitly, and it's no big deal. Your problem is you've just returned a pointer to invalid memory. The array you allocated in the function disappears when the function returns, and dereferencing a pointer to that array is undefined behavior (returning the pointer isn't technically illegal, but any good compiler warns you, because a pointer that is never dereferenced is usually pretty useless).
If you want to return a new array with the concatenated string, you must use dynamically allocated memory, e.g. from malloc/calloc; making the array static would also work (it would now be persistent global memory), but it would make your function both non-reentrant and non-threadsafe, so it's usually frowned on.
Your little trick of assigning to a pointer and returning the pointer may have fooled the compiler into thinking you weren't doing anything illegal, but it did nothing to make your code safer.
You might be used to languages with more dynamic memory handling, but your function here won't work because C strings are just a block of local memory which disappears when you return. That means that whatever you write to char s3[] will disappear after the return (the details vary and the memory can sometimes stick around long enough for you to think it worked even when it didn't).
Normally you'd want to allocate the memory before calling the function, and pass it in as a parameter, as in:
void stringcat(const char * first, const char * second, char * dest, const size_t dest_len)
Called like this:
char title[] = "Mr. ";
char last[] = "Jones";
char addressname[sizeof(title) + sizeof(last)];
stringcat(title, last, addressname, sizeof(addressname));
The other way to do it is to allocate the memory in the function using malloc(), and return that, but you have to remember to free it in the code when you're done with it.
I've been trying to do this simple task for a while now but can't get it to work properly as I'm not super familiar with pure C tricks.
Basically I have a function that get called by a block of code that I didn't write myself and can't edit.
int myMethod(char* str);
My task is to find the position of a substring in the char* and if found get the string from index 0 to index of the found substring and assign it to the original char* str.
Here is what I tried to do:
int myMethod(char* str)
{
int splitPos = strstr(str, "Pikachu") - str;
char buffer[splitPos + 1];
strncpy(buffer, str, splitPos);
buffer[splitPos] = '\0';
memcpy(str, buffer, strlen(buffer) + 1);
}
And I get a SegFault at the last strcpy call. I tried changing it to the followings with the same result
memmove(str, buffer, ...)
strcpy(...)
There are multiple problems in your function:
you do not check the return value of strstr for success. Your code has undefined behavior if it fails to locate the substring.
strncpy will not null terminate the destination string if the source is longer than splitPos-1, which it is. Do not use strncpy, it does not do what you think, it is very error prone for both the programmer and the reader. For your purpose, memcpy with the same arguments is equivalent and less problematic.
strlen(buffer) is redundant, it evaluates to splitPos.
You actually do not need a temporary buffer for your goal: truncating the string can be done by simply setting the start of the substring to '\0'.
if the destination string is read-only, modifying it has undefined behavior, and might explain the observed segmentation fault.
Here is a simplified version:
int myMethod(char *str) {
char *p = strstr(str, "Pikachu");
if (p != NULL) {
*p = '\0';
}
}
Conversely if you just need to manipulate the substring in further code in myMethod, you can make a copy to avoid the fateful attempt at modifying the original string:
int myMethod(char *str) {
char *p = strstr(str, "Pikachu");
size_t len = p ? p - str : stren(str);
char buffer[len + 1];
memcpy(buffer, str, len);
buffer[len] = '\0';
str = buffer;
/* use `str` in this function */
}
I thought I understood the answer to this question but I don't. I understand the first result but I still don't know how to do the copy correctly. I tried the following code:
// TstStrArr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <malloc.h>
int main()
{
char ** StrPtrArr;
char InpBuf0[] = "TstFld0";
char InpBuf1[] = "TstFld1";
StrPtrArr = (char **)malloc(2 * sizeof(char *));
StrPtrArr[0] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf0, sizeof(StrPtrArr[0]));
strncpy_s(StrPtrArr[0], sizeof(StrPtrArr[0]), InpBuf0, _TRUNCATE);
printf("strptrarr=%s\n", StrPtrArr[0]);
StrPtrArr[1] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf1, sizeof(*StrPtrArr[1]));
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); // error here
printf("*strptrarr=%s\n", StrPtrArr[1]);
free(StrPtrArr[0]);
free(StrPtrArr[1]);
free(StrPtrArr);
return 0;
}
The result I got was:
inpbuf=TstFld0 sizeof= 4 strptrarr=Tst
inpbuf=TstFld1 sizeof= 1
and the following error:
Exception thrown: write access violation.
destination_it was 0xFFFFFFCD.
The result I thought I'd get was either of the following:
inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1
inpbuf=TstFld1 sizeof= 1 *strptrarr=T
I understand the first copy copied the input buffer to the 4 byte pointer which was incorrect. I thought the second copy would copy the input buffer to the value of the dereferenced pointer of a size of 11 but it didn't. I'm guessing the copy was to the first character of the string in the array. I don't understand memory enough to know the significance of the address 0xFFFFFFCD but I guess it's in read-only memory thus causing the error.
What is the correct way to do the copy?
(I don't think it matters, but I'm using VS 2015 Community Edition Update 3.)
Why
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE);
?
*StrPtrArr[1] should be StrPtrArr[1] because StrPtrArr is of type char** and you need char* here.
and sizeof(*StrPtrArr[1]) - is quite strange....
actually sizeof(StrPtrArr[1]) also cannot provide correct value.
You should remember size of allocated memory and then use it like:
size_t arrSize = 10 + 1;
StrPtrArr[1] = (char *)malloc(arrSize);
. . .
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);
The problem is that you are using sizeof when deciding how many characters to copy. However, you allocated a fixed number of characters which is not known to sizeof operator: sizeof StrPtrArr[0] is equal to the size of char pointer on your system (four bytes, judging from the output), not 10 + 1. Hence, you need to specify that same number again in the call to secure string copy.
It isn't as complicated as people seem to think.
char* array = calloc( n, sizeof(array[0]) ); // allocate array of pointers
// assign a dynamically allocated pointer:
size_t size = strlen(str) + 1;
array[i] = malloc(size);
memcpy(array[i], str, size);
I intentionally used calloc during allocation, since that sets all pointers to NULL. This gives the advantage that you can harmlessly call free() on the pointer, even before it is assigned to point at a string.
This in turn means that you can easily (re)assign a new string to an index at any time, in the following way:
void str_assign (char** dst, const char* src)
{
size_t size = strlen(src) + 1;
free(*dst);
*dst = malloc(size);
if(*dst != NULL)
{
memcpy(*dst, src, size);
}
}
...
str_assign(&array[i], "something");
I have to create a copy of some elements of the standard library in C and I have to create a copy of strcat. So I have to create a function that concatenate two strings in C. I know arrays in C can't change the allocated size. The only fonction i'm allowed to use is copies i made of strlen, strstr, and write() ... My code looks like this :
char *my_strcat(char *dest, char *src)
{
int dest_size;
int src_size;
int current_pos;
int free_space;
int pos_in_src;
src_size = my_strlen(src);
dest_size = my_strlen(dest);
while (dest[current_pos] != '\0')
current_pos = current_pos + 1;
free_space = dest_size - current_pos;
if (free_space < src_size)
return (0);
while (src[pos_in_src] != '\0')
{
dest[current_pos] = src[pos_in_src];
pos_in_src = pos_in_src + 1;
current_pos = current_pos + 1;
}
return (dest);
}
But I don't know how to declare my dest and src in the main.
I don't know how to create an array with a big size, declare it as a string like dest = "Hello\0" but this array has to still contains more than 6 characters.
Can you help me please ?
char dest[19] = "epite";
char *src = "chor42spotted";
my_strcat(dest, src);
Also, read the man for strcat(3)
the dest string must have enough space for the result.
https://linux.die.net/man/3/strcat
So your function is behaving incorrectly, you do not need to check that you have enough free space in dest
You want a function mystrcat which behaves exactly like stdlib strcat.
So the prototype is
/*
concatenate src to dest
dest [in / out] - the string to add to (buffer must be large enough)
src [in] - the string to concatenate.
Returns: dest (useless little detail for historical reasons).
*/
char *mystrcat(char *dest, const char *src);
Now we call it like this
int main(void)
{
char buff[1024]; // nice big buffer */
strcpy(buff, "Hello ");
mystrcat(buff, "world");
/* print the output to test it */
printf("%s\n", buff);
return 0;
}
But I'm not going to write mystrcat for you. That would make your homework exercise pointless.
The 1st parameter of the array simply has to be large enough to contain both strings + one null terminator. So if you for example have "hello" and "world", you need 5 + 5 +1 = 11 characters. Example:
#define LARGE_ENOUGH 11
int main (void)
{
char str[LARGE_ENOUGH] = "hello";
my_strcat(str, "world");
puts(str); // gives "helloworld"
}
In real world applications, you would typically allocate space for the array to either be same large number (couple of hundred bytes) or with a length based on strlen calls.
As for the implementation itself, your solution is needlessly complicated. Please note that the real strcat leaves all error checking to the caller. It is most likely implemented like this:
char* strcat (char* restrict s1, const char* restrict s2)
{
return strcpy(&s1[strlen(s1)], s2);
}
The most important part here is to note the const-correctness of the s2 parameter.
The restrict keywords are just micro-optimizations from the C standard, that tells the compiler that it can assume that the pointers point at different memory areas.
If you wish to roll out your own version with no library function calls just for fun, it is still rather easy, you just need two loops. Something like this perhaps:
char* lolcat (char* restrict s1, const char* restrict s2)
{
char* s1_end = s1;
while(*s1_end != '\0') // find the end of s1
{
s1_end++;
}
do // overwrite the end of s1 including null terminator
{
*s1_end = *s2;
s1_end++;
s2++;
} while(*s1_end != '\0'); // loop until the null term from s2 is copied
return s1;
}
I'm trying to write a function will convert the characters from an array into ints so that I can produce a sum or other math process for each group. I know that first I have to use strtok to get rid of the spaces and '+'. I've been trying to first at least start with getting strtok to work but it keeps saying segmentation fault when I try to run it.
Any help?
#include <string.h>
#include <stdio.h>
int main(void)
{
char* string[] = { "10 + 20", "1 + 3 + 6 + 8" };
sum(string[0]);
}
int sum(char* s)
{
char *stringcopy = malloc( strlen(s) + 1 );
char* del = " +";
char* token;
int i;
stringcopy = s; /* 'copy' problem here */
token = strtok(stringcopy, del);
while( token ) {
printf("%s\n", token);
token = strtok(NULL, del);
}
return 11; /* placeholder until I get the sum */
}
There is a simple reason strtok gives you a segmentation fault:
You are running it on a string literal, which despite having type char[n] is an immutable object.
strtok modifies any string you run it on!
The work-around is simple: Run on a copy. Here a function for duplicating strings (most C libraries provide this non-standard function as char* strdup(const char*):
char* my_strdup(const char* s) {
size_t size = strlen(s)+1;
char* ret = malloc(size);
if(ret)
memcpy(ret, s, size);
return ret;
}
Don't forget to free() the copy later.
You tried doing so, but after getting off to a good start and reserving space for the string with malloc, you just discarded it (memory leak) by assigning a pointer to the literal to that same pointer.
This statement
textcopy = s; /* making copy for strtok */
does not do what you think.
In fact there us a memory leak because at first you allocated memory and textcopy got the address of the first byte of the storage
char *textcopy = malloc( strlen(s) + 1 );
and then you reassigned textcopy.
textcopy = s; /* making copy for strtok */
You have to use standard function strcpy instead
strcpy( textcopy, s ); /* making copy for strtok */
Also it would be better if the function would declared as
int stringSum(const char* s);
This line does not do what you thought it would:
textcopy = s; /* making copy for strtok */
No string is copied here. All that happens is that instead of pointing to the first byte of the block of memory that you just allocated for it (with malloc( strlen(s) + 1 )),
textcopy now points directly at the first byte of the literal string "10 + 20" that you passed to stringSum as s.
You probably wanted something like strcpy(textcopy, s). I had suggested strncpy earlier; strncpy(textcopy, s, strlen(s)) + 1 might work, but (as the comments explain) seems to be rather pointless to use in this context.
The line
textcopy = s; /* making copy for strtok */
doesn't make copy of s and put it in textcopy. Instead, you need to use:
strcpy(textcopy, s);