I am currently getting a segfault, and I just can't seem to figure out why...
I am making a code that concatenates string values:
char* concat(char** strs, unsigned int nstrs)
{
char* newstring;
int length = 0;
int j;
int charcount;
int strcount;
int k = 0;
for (j = 0; j <= nstrs - 1; j++) {
length = sizeof(strs[j]) + length;
}
newstring = malloc(length);
for (strcount = 0; strcount <= nstrs - 1; strcount++) {
for (charcount = 0; charcount <= strlen(strs[strcount]) - 1; charcount++) {
newstring[k] = strs[charcount][strcount];
k++;
}
}
return newstring;
And in my main function I have...
char* introname[] = {"My", "name", "is", "Trill-o"};
printf("%s\n", concat(introname, 4));
in your code, you need to change
sizeof(strs[j])
to
strlen(strs[j])
Always remember, sizeof is not a function, it's an operator. It returns the size of the supplied data type. In yor code, strs[j] is of type char *, so sizeof will return a value equal to sizeof(char *).
To get the length of the string, you have to use strlen().
That said, please note, strlen() does not include the count for terminating null. So, you've to add space for one more byte while using length in malloc(), like
newstring = malloc(length + 1); // 1 more byte for storing the terminating null.
Also, you must check the return value of malloc() to ensure the success. In case if malloc() fails, it will return NULL and the subsequent usage of newstring will lead to UB.
As per the logical part, your code should read
newstring[k] = strs[strcount][charcount];
and to properly terminate the string,
newstring[k] = '\0' ;
outside for loop.
sizeof(strs[j])
in the function will give sizeof(pointer) not sizeof(array)
But since you have a string use strlen(strs[j]) to get the length of the string.
Please make a note to allocate memory to the \0 character also.
Don't use sizeof to get the length of a string.
You need to use strlen.
sizeof(strs[j]) ; // bad, will return the sizeof pointer which is 4 or 8 depending on the system
strlen(strs[j]); // this is what you want.
Your main problem is here:
length = sizeof(strs[j]) + length;
sizeof does not give the required length of the string as it is a char *, not an array. What you want is strlen(strs[j])).
Also, when you've done totalling the lengths, add one for the terminating NUL before you malloc.
Finally this:
newstring[k] = strs[charcount][strcount];
should be
newstring[k] = strs[strcount][charcount];
Also C strings are null terminated character arrays. Make sure the concatenated string has a \0 at the end. Here is a working version : string concatenation
Note I also switched the indexes of the arrays. I suppose this is what you want.
newstring = malloc(length + 1); // for '\0' character
...
newstring[k] = strs[strcount][charcount];
...
newstring[length] = '\0' ;
Related
I have to arrays of int for example arr1={0,1,1,0,0}, arr2={1,0,1,1,1} and I need to return 1 char* created by malloc that will be shown like this : "01100,10111".
when I do for loop it doesn't work, how can I do it ?
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
for (int i = 0; i < size; i++)
ans[i] = first[i];
ans[size] = ",";
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];
Among the multitude of problems:
Your allocation size is wrong. It should include space for the separating comma and the terminating nullchar. sizeof(int) is wrong regardless, it should be sizeof(char) and as-such can be omitted (sizeof(char) is always 1).
Your storage is wrong. You want to store characters, and your values should be adjusted relative to '0'.
Your indexing of the second loop is wrong.
In reality, you don't need the second loop in the first place:
char* ans = malloc(size * 2 + 2);
for (int i = 0; i < size; i++)
{
ans[i] = '0' + first[i];
ans[size+1+i] = '0' + second[i];
}
ans[size] = ',';
ans[2*size+1] = 0;
That's it.
1.
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
What is size here? It is not defined and declared in the provided code.
You do not need to cast the return value of malloc() to char. In fact, you do not need to cast the return value of malloc() anymore. It is a habit from the early C days.
Why do you need a char pointer here at all exactly? If you want to print 01100,10111 there is no need to use a char pointer for the output of the integer values.
2.
for (int i = 0; i < size; i++)
ans[i] = first[i];
Again what is size here?
What is first here? If it isn´t a pointer this statement is invalid.
3.
ans[size] = ",";
This operation is invalid. You are trying to assign a string to a pointer.
By the way, I don´t know what you trying to do with this statement. You can incorporate the comma separate in the output of 01100,10111, without your intend to include it int the memory of the int arrays itself.
4.
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];
Same as above: What is value and the type of size?
What is second? If it isn´t it a pointer this statement is invalid.
5.
To answer to the question title:
(How to) Copy two arrays of int to one char* in C
This isn´t possible. You can´t copy two arrays with its data to a pointer to char.
There are at least four issues with your code.
You malloc the wrong size, you want to use sizeof(char).
You need to zero terminate it, so you need to add extra room for the terminating zero
char* ans = (char*)malloc((size * 2+2) * sizeof(char));
second[size * 2+1] = 0;
Also the indexing of the second loop is wrong. You are accessing second array out of bounds. Make the loop more like the first.
We also need to convert the integer value to a char in the loops.
for (int i = 0; i < size; i++)
ans[size+i+1] = second[i] + '0';
When I print out the length of the temp string, it starts at a random number. The goal of this for loop is to filter out everything that's not a letter, and it works for the most part, but when I print out the filtered string it returns the filtered string but with some extra random characters before and after the string.
#define yes 1000
...
char stringed[yes] = "teststring";
int len = strlen(text);
char filt[yes];
for (int i = 0; i < len; i++) {
if (isalpha(stringed[i])) {
filt[strlen(filt)] = tolower(stringed[i]);
}
}
There are at least two problems with the line:
temp[strlen(temp)] = "\0";
The compiler should be shrieking about converting a pointer to an integer. You need '\0' and not "\0". (This might account for some of the odd characters; the least-significant byte of the address is probably stored over the null byte, making it and random other characters visible until the string printing comes across another null byte somewhere.)
With that fixed, the code carefully writes a null byte over the null byte that marks the end of the string.
You should probably not be using strlen() at this point (or at a number of other points where you use it in the loop).
You should be using i more in the loop. If your goal is to eliminate non-alpha characters, you probably need two indexes, one for 'next character to check' and one for 'next position to overwrite'. After the loop, you need to write over the 'next position to overwrite' with the null byte.
int j = 0; // Next position to overwrite
for (int i = 0; i < length; i++)
{
if (isalpha(text[i]))
temp[j++] = text[i];
}
temp[j] = '\0';
For starters the character array
char temp[MAX];
is not initialized. It has indeterminate values.
So these statements
printf("NUM:[%i] CHAR:[%c] TEMP:[%c] TEMPSTRLEN:[%i]\n", i, text[i], temp[strlen(temp)], strlen(temp));
temp[strlen(temp)] = tolower(text[i]);
have undefined behavior because you may not apply the standard function strlen to uninitialized character array.
This statement
temp[strlen(temp)] = "\0";
is also invalid.
In the left side of the assignment statement there is used the string literal "\0" which is implicitly converted to pointer to its first character.
So these statements
length = strlen(temp);
printf("[%s]\n", temp);
do not make sense.
It seems what you mean is the following
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 1000
int main(void)
{
char text[MAX] = "teststring";
size_t length = strlen(text);
char temp[MAX] = { '\0' };
// or
//char temp[MAX] = "";
for ( size_t i = 0; i < length; i++)
{
if (isalpha( ( unsigned char )text[i] ) )
{
printf("NUM:[%zu] CHAR:[%c] TEMP:[%c] TEMPSTRLEN:[%zu]\n", i, text[i], temp[strlen(temp)], strlen(temp));
temp[strlen(temp)] = tolower(text[i]);
temp[i+1] = '\0';
}
}
length = strlen(temp);
printf( "[%s]\n", temp );
return 0;
}
The program output is
NUM:[0] CHAR:[t] TEMP:[] TEMPSTRLEN:[0]
NUM:[1] CHAR:[e] TEMP:[] TEMPSTRLEN:[1]
NUM:[2] CHAR:[s] TEMP:[] TEMPSTRLEN:[2]
NUM:[3] CHAR:[t] TEMP:[] TEMPSTRLEN:[3]
NUM:[4] CHAR:[s] TEMP:[] TEMPSTRLEN:[4]
NUM:[5] CHAR:[t] TEMP:[] TEMPSTRLEN:[5]
NUM:[6] CHAR:[r] TEMP:[] TEMPSTRLEN:[6]
NUM:[7] CHAR:[i] TEMP:[] TEMPSTRLEN:[7]
NUM:[8] CHAR:[n] TEMP:[] TEMPSTRLEN:[8]
NUM:[9] CHAR:[g] TEMP:[] TEMPSTRLEN:[9]
[teststring]
Edit: next time do not change your question so cardinally because this can confuse readers of the question.
I have this string
char currentString[212] = { 0 };
and after I'm using it once, I want to reset it.
I tried many ways, such as:
for (int k = 0; k < strlen(currentString); k++)
{
currentString[k] = '\0';
}
but it won't go over the loop more than once, and it give '\0' only to the first char, the rest remain the same.
and I also tried:
currentString[0] = '\0';
yet I get the same result.
any suggestions for what can I do?
thanks!
strlen will find the length by searching for the first occurrence of \0. So if you want to reset the whole array, you should change strlen(currentString) to sizeof currentString. However, do note that this will not work with pointers.
If you pass the array to a function, you cannot determine the size of the array afterwards, so this will not work:
void foo(char * arr) {
for (int k = 0; k < sizeof arr; k++)
arr[k] = '\0';
}
Instead you need to do like this:
void foo(char * arr, size_t size) {
for (int k = 0; k < size; k++)
arr[k] = '\0';
}
But of course there's no reason to write custom functions for this when memset is available.
Imagine char currentString[] = "abc"; and then running you loop:
k = 0
initialy strlen(currentString) = 3, there are 3 characters before '\0' byte. the loop condition k < strlen(currentString) is true
k = 0 -> currentString[0] = '\0'
k++ -> k = 1
then strlen(currentString) = 0 (as the first byte of currentString is equal to '\0', there are no characters before '\0')
the loop condition is false k < strlen(currentString) -> 1 < 0
So the loop will always run only one time.
If you want to write only zero bytes to a memory region, use memset
memset(currentString, 0, sizeof(currentString));
will set the memory region as pointed to by currentString pointer with sizeof(currentString) bytes to zeros.
Setting the first byte to zero:
currentString[0] = '\0';
maybe considered enough to "clear a string".
Setting the first byte to '\0' wont clear out the currentString.You may think that because ANSI C thinks that is a string terminator and if you print your string it will show empty.But if you check the second byte you will see the second char from your string. As other's said the best option to wipe out the string is:
memset(currentString, 0, sizeof(currentString));
And is way safer and faster.Also in ANSI C 0 and '\0' are the same.
to zero the whole array
char arr[SOMESIZE];
/* ... */
memset(arr, 0, sizeof(arr));
pointer - you need to know the size of the allocated memory as sizeof will return the size of the pointer itself only, not the referenced object;
char *p = malloc(SIZE);
/* ..... */
memset(p, 0 , SIZE);
It is never a good decision to calculate anything again and again. Instead you should calculate the strlen() only once.
That being said, in your case, doing so will solve the problem, as the reason it didn't work was that strlen() returned 0 right after the first round, since the length of the string became 0.
int n = strlen(currentString);
for (int k = 0; k < n; k++)
{
currentString[k] = '\0';
}
I don't know the size of the array and using isdigit(array[i]) for every element i < sizeof(array) doesn't seem to work correctly.
I am trying to:
Check that every char is a digit.
Convert the string to int.
Check that it is > 0
int all_digits(char *string){
short i;
for(i=0; i < sizeof(string); i++){
if (!isdigit(string[i])){
//Non-digit found.
return 1;
}
}
//All of them are digits.
return 0;
}
The first part is the one that I can't get.
int n = strlen(string);
for(i=0; i < n; i++)
sizeof(pointer) is not same as sizeof(array)
You need to pass a valid string which is a null terminated string else strlen() might crash.
Edits:
Alternatively you can have
for(i=0; string[i] != '\0'; i++)
In this case you cannot get the correct length using the sizeof function.
sizeof function will give you the size of the given data type. You can use the
strlen function.
While using the strlen you have to manage the following,
Consider in your string in last there is no null value you didn't get the correct value of the string length. For this you have to send the size of that array as a another parameter or you have to place the null value in the last value of the a string.
Then you can get that easily.
In your code, string is of type char *. sizeof(string) will give you the size of a char *, not the array.
You need to pass the size of the array explicitly, using another paramter to all_digits() function and use that value in for loop condition checking.
Maybe something like this
int all_digits(char *string, int size){
short i;
for(i=0; i < size; i++){
if (!isdigit(string[i])){
//Non-digit found.
return 1;
}
}
//All of them are digits.
return 0;
}
Note: Specifically in case of a char *, a better, smaller and cleaner approach to this can be achieved using strlen() [assuming proper aguments passed], which will give you the length of the supplied string.
Simply iterate along the string, testing every character:
int all_digits(char *string){
if( *string == 0) // empty string - wrong
return 1;
for( ; *string != 0; string++) // scan the string till its end (a zero byte (char)0)
if (!isdigit(*string)) // test for a digit
return 1; // not a digit - return
return 0; // all characters are digits
}
However that only tests if the string consists of digits and does not make you any closer to determining its numerical value...
The two arrays passed in are constants so I made two new arrays.
The first array stores a group of chars and the second array stores a second group of chars. So far I assume that the first group is bigger than the second ex. (a,b,c,d > x,y).
What the program hopes to accomplish is to make two new arrays that contain the same letters but the shorter array in this case arr2 (newarr2) has it's last char repeated until it matches the length of the first array.
examples of correct solutions.
(a,b,c,d < x,y) --> equate_arr --> (a,b,c,d = x,y,y,y)
void equate_arr(char arg2[], char arg1[]){
size_t i = 0;
size_t len1 = strlen(arg1);
size_t len2 = strlen(arg2);
char newarr2[512];
char newarr1[512];
while(i < (strlen2 - 1))
{
newarr2[i] = arg2[i];
i++;
}
i = 0;
while(i < (strlen1 - 1))
{
newarr1[i] = arg1[i];
i++;
}
i = 0;
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
}
Currently I have no idea what is happening because once I fiddle with this function in my code the program does not seem to run anymore. Sorry about asking about this project I'm working on so much but I really do need some assistance.
I can put the whole program in here if needed.
Revised
void tr_non_eq(char arg1[], char arg2[], int len1, int len2)
{
int i = 0;
char* arr2;
arr2 = (char*)calloc(len1+1,sizeof(char));
while(i < len2)
{
arr2[i] = arg2[i];
i++;
}
while(len2 < len1)
{
arr2[len2] = arg2[len2-1];
len2++;
}
tr_str(arg1, arr2);
}
Right now with inputs (a,b,c,d,e,f) and (x,y) and a string "cabbage" to translate the program prints out "yxyyx" and with string "abcdef" it prints out "xyy" which shows promise. I am not too sure why the arr2 array does not get filled with "y" chars as intended.
As de-duplicator says, as your code stands it effectively achieves nothing. More importantly, what it tries to do is fraught with peril.
The fact that you use strlen to determine the length of your arguments is a clear indicator that equate_arr does not expect to receive two arrays of char. Instead, it wants two NUL-terminated C-style strings. So the declaration should be more like:
void equate_arr(const char *arg2, const char *arg1)
This makes the contract a little clearer.
But note the return type: void. This says your function will not return any values to the caller. So, how did you plan to return the modified arrays?
The next big peril lies in these lines:
char newarr2[512];
char newarr1[512];
What happens if this function is called with a string which is larger than 511 characters (plus the NUL)? The phrase "buffer overrun" should be jumping out at you here.
What you need is to malloc buffers large enough to hold a duplicate of the longest string passed in. But that raises the question of how you will hand the new arrays back to the caller (remember that void return type?).
There are numerous other problems here, largely down to not having a clear definition of the contract this function is meant to meet.
One more for now while I look more closely
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
The very first pass through this loop overwrites the terminating NUL in newarr2, which means the next call to strlen is off into undefined behavior as it is completely at the mercy of whatever junk is sitting in your stack.
If you are unclear on C-style strings, take a look at my answer to this question which goes into great detail about them.
The following is whiteboard-code (i.e. not compiled, not tested) which would sort of do what you are wanting to achieve. It's purely for reference
// Pad a string so that it is the same length as another. Padding is done
// by replicating the final character.
//
// #param padThis: A C-style string in a non-constant buffer.
// #param bufLength: The size of the buffer containing padThis
// #param toMatchThis: A (possibly) const C-style string to act
// as a template for length
//
// Pre-conditions:
// - Both padThis and toMatchThis reference NUL-terminated sequences
// of chars
// - strlen(padThis) < bufLength. Violating this will exit the program.
// - strlen(toMatchThis) < bufLength. If not, padThis will be padded
// to bufLength characters.
//
// Post-conditons:
// - The string referenced by toMatchThis is unchanged
// - The original string at padThis has been padded if necessary to
// min(bufLength, strlen(toMatchThis))
void padString(char * padThis, size_t bufLength, const char * toMatchThis)
{
size_t targetLength = strlen(toMatchThis);
size_t originalLength = strlen(padThis);
if (originalLength >= bufLength)
{
fprintf(stderr, "padString called with an original which is longer than the buffer!\n");
exit(EXIT_FAILURE);
}
if (targetLength >= bufLength)
targetLength = bufLength -1; // Just pad until buffer full
if (targetLength <= strlen(padThis))
return; // Nothing to do
// At this point, we know that some padding needs to occur, and
// that the buffer is large enough (assuming the caller is not
// lying to us).
char padChar = padThis[originalLength-1];
size_t index = originalLength;
while (index < targetLength)
padThis[index++] = padChar;
padThis[index] = '\0';
}
Since you declared
char newarr2[512];
char newarr1[512];
as size 512 and not assigned any data, strlen will always return size of newarr1 and newarr2 as garbage since you not ended the string with a proper NULL character.
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
this while loop will not work properly.
for ( i = len2; i < len1; ++i )
newarr2[i] = newarr2[len2-1]
if len2 is always less than len1, you can use the above loop
if you do not know the which array will be bigger than,
size_t len1 = strlen(arg1);
size_t len2 = strlen(arg2);
char* newarr1;
char* newarr2;
int i;
if ( len1 >= len2 )
{
newarr1 = (char*)calloc(len1+1,sizeof(char));
newarr2 = (char*)calloc(len1+1,sizeof(char));
}
else
{
newarr1 = (char*)calloc(len2+1,sizeof(char));
newarr2 = (char*)calloc(len2+1,sizeof(char));
}
for ( i = 0; i < len1; ++i)
newarr1[i] = arg1[i];
for ( i = 0; i < len2; ++i)
newarr2[i] = arg2[i];
if( len1 >= len2 )
{
for ( i = len2; i < len1; ++i )
newarr2[i] = newarr2[len2-1];
}
else
{
for ( i = len1; i < len2; ++i )
newarr1[i] = newarr1[len1-1];
}
free the memory later