Insert a string inside of another string (without an intermediate string) - c

I came across this question and it asks if it's possible to write the function
void insert(char* M, char* T, int i)
that inserts the string T inside M starting from the index i, without using an intermediate string... I tried to use realloc but I think there's a problem when the original string M is a lot smaller than the result, my theory is that realloc changes the address of the string to be able to represent the new string.
For example: M="Wg" T="ron" and i=1; the result should be M="Wrong".
I'm using the following code:
void insert(char* M,char* T,int i)
{
int l;
l=strlen(M);
M=realloc(M,l+strlen(T)+1);
for(int j = l-1; j >= i; j--)
{
M[j+strlen(T)]=M[j];
}
for(int j = 0;j < strlen(T); j++)
{
M[i+j]=T[j];
}
M[l+strlen(T)]='\0'; //from what i've tested the string M is correct.
}
and using this declaration:
char *s=malloc(3);
char *c=malloc(18);
strcpy(s,"as");
strcpy(c,"bcdefghijklmnopqr");
insert(s,c,1); //this example does not work on my machine.
I hope this clarifies the question.
So is there a way to do it?

Example of a possible implementation using memmove. Explanations are in the comments
#include <stdio.h>
#include <string.h>
void insertString(char* M, const char* T, size_t index)
{
// ASSUMES there's enough space in M for this operation
// get the original lengths of each string
size_t Mlen = strlen(M);
size_t Tlen = strlen(T);
if (index < Mlen)
{
// M+index+Tlen is the destination position where the remaining characters in M will start
// M+index is the index where T will be inserted
// Mlen-index is the remaining number of characters in M that need to move
memmove(M+index+Tlen, M+index, Mlen-index);
// copy the T string to the space we just created
memcpy(M+index, T, Tlen);
// NUL terminate the new string
M[Mlen + Tlen] = '\0';
}
else
{
// simply strcat if the index falls outside the range of M
strcat(M, T);
}
}
If you're not allowed to use memmove or memcpy, it's simple enough to roll your own.
Demo

[This isn't really an answer; it's a clarification that's too complicated for a comment.]
If you can assume that the caller looks like
char string[6] = "Wg";
insert(string, "ron", 1);
(or with the string array having any size greater than 5), then you can write insert() easily.
If you can assume that the caller looks like
char *string = malloc(3);
strcpy(string, "Wg");
insert(string, "ron", 1);
then you can almost write insert() using realloc to make the string larger, except you have no way to return the possibly-new (that is, possibly moved) value of string.
If the caller might look like
char *string = "Wg";
insert(string, "ron", 1);
or even
char *string = "Wg\0\0\0";
insert(string, "ron", 1);
than you definitely cannot write insert(), because you cannot assume that the pointed-to string is writable (and on many platforms it will not be).
So, in general, the answer is: "No". You cannot write a general-purpose version of insert() that will work under all circumstances.
Note, too, that if you were to assume that the string were in malloc'ed memory and that you could use realloc (as in my second example), that code would not work for strings that were not malloc'ed (that is, it would not work for callers like my first example), and it would have no portable way of knowing, based on the pointer passed to it, whether it would be abe to safely use realloc or not.

Related

Creating a function to allocate a array of strings in C

I'm working on a minisql code in C and i having some issues to allocate array of strings. I made a function called "alocaString" to do this (bc i'm using that a lot), but i don't think is working.
When the code reaches the line "strncpy(lista[qtnPalavras], splitStr, 100);" in the function "listaPalavras" (that have the purpose of split a string in different types of characters) a file named "strcpy-avx2.S" is created, one of the arguments of that function (**lista) is allocated with "alocaString" so i think the problem is in that function.
I already try to use valgrind and shows "is used uninitialized in this function [-Werror=uninitialized]" to all arrays of strings that i tried to use on that function, but i'm initializing them inside of the function
int alocaString (char **string, int tamanho, int posicoes){
string = malloc (posicoes * sizeof(char*));
for (int i = 0; i < posicoes; i++){
string [i] = malloc (tamanho * sizeof(char));
if (string[i] == NULL){return 0;}
}
return **string;
}
void desalocaString (char **string, int posicoes){
for (int i = 0; i < (posicoes); i++){
free (string[i]);
}
free (string);
}
int listaPalavras(char *entrada, char **lista, char *separador){ // lista as palavras
char *splitStr;
int qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, 100);
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
I assume that you are using these functions like this:
alocaString(lista, tamanho, posicoes);
listaPalavras(some_string, lista, some_delimiters);
desalocaString(arr);
Even without looking at the code, it seems logically wrong to allocate an array of strings first and then populate it if you do not already know how many strings it will need to fit. If you happen to allocate an array of n strings, but your listaPalavras() functions splits the provided string into n+1 or more substrings, you're going to overflow your previously allocated array. Nonetheless, this can be done taking the appropriate precautions, like carrying around sizes and checking them to avoid overflow.
The only sane way to achieve what you want is therefore to either (A) count the number of delimiters in the string first to know in advantage how many pointers you will need or (B) dynamically allocate the needed amount in listaPalavras() while splitting. You seem to be going with something similar to option A, but your code is flawed.
The desalocaString() is the only function that seems correct.
A correct implementation of alocaString() would return the allocated array (or NULL in case of failure), but you are returning **string which is just the first character of the first string. Needless to say, this does not make much sense. You don't need to take a char ** parameter, just the sizes. Secondly, in case of failure of any of the calls to malloc() you should free the previously allocated ones before returning NULL.
char **alocaString (unsigned tamanho, unsigned posicoes) {
char **lista = malloc(posicoes * sizeof(char*));
if (lista == NULL)
return NULL;
for (unsigned i = 0; i < posicoes; i++) {
lista[i] = malloc(tamanho * sizeof(char));
if (lista[i] == NULL) {
for (unsigned j = 0; j < i; j++)
free(lista[j]);
free(lista);
return NULL;
}
}
return lista;
}
As per listaPalavras(), which has the job of splitting the given string into other strings and copying them into the previously allocated array, to avoid overflowing the given array of strings you will need to also provide its length as well as the length of the previously allocated strings as argument (let's call them posicoes and tamanho like for the above function). Moreover, strncpy() will not add a NUL-terminator (\0) to the destination string if it is not found in the source string within the first n characters (n being the third argument), so you will need to add it yourself to make sure your strings are correctly terminated.
unsigned listaPalavras(const char *entrada, char *separador, char **lista, unsigned posicoes, unsigned tamanho) {
char *splitStr;
unsigned qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (qtnPalavras < posicoes && splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, tamanho);
lista[qtnPalavras][tamanho - 1] = '\0';
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
Finally the code of the caller should look something like this:
char **lista;
unsigned tamanho = 100;
unsigned posicoes = 10;
unsigned palavras;
lista = alocaString(tamanho, posicoes);
if (lista == NULL) {
// handle the error somehow
}
palavras = listaPalavras(YOUR_STRING, YOUR_DELIMITERS, lista, posicoes, tamanho);
desalocaString(lista);
This should work fine, however you are limited by the fact that:
You cannot know beforehand the number of substrings that strtok() will find.
You cannot know beforehand the length of any of those substrings.
Therefore, allocating the needed lista dynamically inside listaPalavras() would make more sense.
Finally, as a side note, the names of your functions are misleading: if you need to allocate an array of strings, you might want to choose a better name than alocaString() which seems to imply that you are allocating a single string. Maybe alocaLista() and dealocaLista() would be better choices.

Abort trap: 6 error with arrays in c

The following code compiled fine yesterday for a while, started giving the abort trap: 6 error at one point, then worked fine again for a while, and again started giving the same error. All the answers I've looked up deal with strings of some fixed specified length. I'm not very experienced in programming so any help as to why this is happening is appreciated. (The code is for computing the Zeckendorf representation.)
If I simply use printf to print the digits one by one instead of using strings the code works fine.
#include <string.h>
// helper function to compute the largest fibonacci number <= n
// this works fine
void maxfib(int n, int *index, int *fib) {
int fib1 = 0;
int fib2 = 1;
int new = fib1 + fib2;
*index = 2;
while (new <= n) {
fib1 = fib2;
fib2 = new;
new = fib1 + fib2;
(*index)++;
if (new == n) {
*fib = new;
}
}
*fib = fib2;
(*index)--;
}
char *zeckendorf(int n) {
int index;
int newindex;
int fib;
char *ans = ""; // I'm guessing the error is coming from here
while (n > 0) {
maxfib(n, &index, &fib);
n -= fib;
maxfib(n, &newindex, &fib);
strcat(ans, "1");
for (int j = index - 1; j > newindex; j--) {
strcat(ans, "0");
}
}
return ans;
}
Your guess is quite correct:
char *ans = ""; // I'm guessing the error is coming from here
That makes ans point to a read-only array of one character, whose only element is the string terminator. Trying to append to this will write out of bounds and give you undefined behavior.
One solution is to dynamically allocate memory for the string, and if you don't know the size beforehand then you need to reallocate to increase the size. If you do this, don't forget to add space for the string terminator, and to free the memory once you're done with it.
Basically, you have two approaches when you want to receive a string from function in C
Caller allocates buffer (either statically or dynamically) and passes it to the callee as a pointer and size. Callee writes data to buffer. If it fits, it returns success as a status. If it does not fit, returns error. You may decide that in such case either buffer is untouched or it contains all data fitting in the size. You can choose whatever suits you better, just document it properly for future users (including you in future).
Callee allocates buffer dynamically, fills the buffer and returns pointer to the buffer. Caller must free the memory to avoid memory leak.
In your case the zeckendorf() function can determine how much memory is needed for the string. The index of first Fibonacci number less than parameter determines the length of result. Add 1 for terminating zero and you know how much memory you need to allocate.
So, if you choose first approach, you need to pass additional two parameters to zeckendorf() function: char *buffer and int size and write to the buffer instead of ans. And you need to have some marker to know if it's first iteration of the while() loop. If it is, after maxfib(n, &index, &fib); check the condition index+1<=size. If condition is true, you can proceed with your function. If not, you can return error immediately.
For second approach initialize the ans as:
char *ans = NULL;
after maxfib(n, &index, &fib); add:
if(ans==NULL) {
ans=malloc(index+1);
}
and continue as you did. Return ans from function. Remember to call free() in caller, when result is no longer needed to avoid memory leak.
In both cases remember to write the terminating \0 to buffer.
There is also a third approach. You can declare ans as:
static char ans[20];
inside zeckendorf(). Function shall behave as in first approach, but the buffer and its size is already hardcoded. I recommend to #define BUFSIZE 20 and either declare variable as static char ans[BUFSIZE]; and use BUFSIZE when checking available size. Please be aware that it works only in single threaded environment. And every call to zeckendorf() will overwrite the previous result. Consider following code.
char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);
The zeckendorf() function always return the same pointer. So a and b would pointer to the same buffer, where the string for 15 would be stored. So, you either need to store the result somewhere, or do processing in proper order:
a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);
As a rule of thumb majority (if not all) Linux standard C library function uses either first or third approach.

How to create an array of strings in C dynamically without knowing the size of strings and characters?

I have tried everything and my code looks perfectly fine to me (it obviously isn't if it's not working).
I am trying to read from some text a list of words separated by a comma, and each word will be an element of an array of strings. I don't know how many elements there will be or how long it will be.
The for loop is grand, as I count how many characters there is before. The main problem is allocation memory, sometimes I get "Segmentation Fault: 11" when I run it (as it compiles grand), sometimes when I read the items it get something like:
P?? adios (null) heyya
When it should give me something like:
hola adios bye heyya
I think I am accessing memory I am not supposed to. Anyway, here the code:
// We allocate memory for one string
variables = (char**)calloc(1, sizeof(char*));
variables[0] = (char*)calloc(100, sizeof(char));
if (variables == NULL) {
return NULL;
}
// Now we start looking for the variables
for (int i = comma_pos+1; i < *(second_pos + pos); i++) {
deleteSpaces(string, &i);
// If the character is not a comma, we copy the character
if (*(string + i) != ',') {
*(variables[stringnum] + j) = *(string + i);
j++;
} else {
// If the character is a comma, we have to allocate more memory for a new string
*(variables[stringnum] + j) = '\0';
stringnum++;
j = 0;
char **temp = variables;
// We allocate more memory for a second array
variables = realloc(variables, sizeof(char*) * stringnum);
variables[stringnum] = (char*)calloc(100, sizeof(char));
// If we cannot allocate more memory then get out
if (variables == NULL) {
return temp;
}
} // end else
} // end for
*(variables[stringnum] + j) = '\0';
It's not immediately clear to me what is wrong with your code, but it's not at all how I would approach the problem.
I would start by determining how many substrings there are by counting delimiters in the source string and adding one. This does require a pre-scan of the string, but it's likely to be much cheaper than any alternative that requires performing multiple memory allocations.
As for space for the strings themselves, if you do not need to keep the comma-delimited form of the list, then you may be able to re-use that space. Use the strtok() function to tokenize it, and store the resulting pointers.
If you must preserve the original comma-delimited string, then I suggest making a copy of the whole thing, and then tokenizing as I suggested before (and you will know how long it is already from counting delimiters). You do not need more space overall for the individual strings than the original comma-delimited one occupies.
If you prefer to avoid strtok() then it's not hard to implement the same thing manually.
you have to alloc in both directions and maybe you are already.
you need to allocate the depth, an array of pointers, then for each pointer in that array need to allocate the width for that row.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
char **x;
x=malloc(100*sizeof(char *));
printf("%p\n",x);
for(ra=0;ra<100;ra++)
{
x[ra]=malloc(ra*sizeof(char));
}
for(ra=0;ra<100;ra++)
{
printf("%p\n",x[ra]);
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++) x[ra][rb]=rb;
}
for(ra=0;ra<100;ra++)
{
for(rb=0;rb<ra;rb++)
{
printf("%u ",x[ra][rb]);
}
printf("\n");
}
return(0);
}

To know the size of an array in c

I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)

To find the substring in a given text.. C programm

char *substring(char *text, int position, int length)
{
int i, j=0;
char *temp ;
for(i=position-1; i<position+length-1; i++)
{
temp[j++] = text[i];
}
temp[j] = '\0';
return temp;
}
Hi What is the error in the following code.. I am trying to run this on Fedora Machine.. And its giving me a run-time error "Segmentation Fault". What is this error all about.. and why is it giving this error..
Thanks..
temp is uninitialized.
You need to allocate memory for temp - currently it's just a dangling pointer. You can use malloc for this but note that the caller will need to ensure that this storage is subsequently freed.
For example:
char *substring(const char *text, int position, int length)
{
char *temp = malloc(length + 1);
int i, j;
for (i = position, j = 0; i < position + length; i++, j++)
{
temp[j] = text[i];
}
temp[j] = '\0';
return temp;
}
It means that your code has violated some restriction set up by the operating system, in this case you are writing to memory that you do not have the right to write to.
This is because your temp variable is just an uninitialized pointer, it doesn't contain the address of memory where you are allowed to write.
If you expect to write length + 1 characters, it must be pointing to at least that many bytes worth of space.
Since you expect to return the string, you need to either make it static (but that can be dangerous), or allocate the space dynamically:
if((temp = malloc(length + 1)) == NULL)
return NULL;
I am making a copy of the sub-string into another pointer, this is the just the simple way of finding one substring of a given string..
Hope i am that very simple way in the correct manner..
Also, The methods given by SysAdmin,, looks pretty complex ones, but still thanx for the suggestion.. I will try and learn those as well.. But if you can tell me whether i have implemented the very basic pattern searching algorithm correctly, then it would be very kind..
Thanks..
while the answer is obvious - i.e temp is not initialized,
here is a suggetion.
If your intention is to find a substring in another string,
few alternatives are,
1. use C strstr(...)
2. Robin-Karp method
3. Knuth-Morris-Pratt method
4. Boyer Moore method
Update:
Initialy I thought this question was related to finding the substring (based on the title).
Anyway, this looks like strchr() implementation.
It is obvious from the code that you missed to allocate / initialize the pointer *temp. It is pointing to nowhere.
You either have to use malloc or strdup and do the rest. But yeah , you may also want to explore using strncpy (null terminate) to simplify the code.

Resources