How to fix custom insertString function in C - c

#include <stdio.h>
int strLength(char *strP)
{
int i = 0;
while(*(strP + i) != '\0') i++;
return i;
}
// insert the second string into the first starting
// at the specified index
// if failure, do nothing
void insertString(char *str1P, char *str2P, int index)
{
int i = 0,
str1Length = strLength(str1P), str2Length = strLength(str2P);
*(str1P + str1Length + str2Length) = '\0';
while(i < (str1Length - index))
{
*(str1P + index + str2Length + i) = *(str1P + index + i);
*(str1P + index + i) = *(str2P + i);
i++;
}
}
int main()
{
//insert
char str8[20] = "the wrong son";
insertString(str8, "per", 14 );
printf("\nAfter insert1 = %s\n", str8);
insertString(str8, "per", 10 );
printf("After insert2 = %s\n", str8);
insertString(str8, "You are ", 0);
printf("After insert3 = %s\n\n", str8);
return 0;
}
I am learning about pointers and strings in C for my Algorithms and Program Design class, and we were recently given this as part of an assignment. I have everything else complete, but I am still having trouble with the insertString function. The first two calls from main produce a desirable result, but the third seems to break. Could someone help me find what could be causing this?

The third call fails beacuse the size of str8 is 20. and third string insertion needs more memory than that allocated to str8[20].
So allocate more memory to support third string insertion or you can use dynamic allocation to string variable to have a general solution.

Related

Trying to delete product from my list using pointer and struct

In this function, I trying to delete a product from a list. Visual Studio shows me a red line under
list->itemList[i].productName = list->itemList[i + 1].productName;
and
list->itemList[i].unit = list->itemList[i + 1].unit;
but not under
list->itemList[i].amount = list->itemList[i + 1].amount;
The productName and unit is char, and the amount is float.
void removeItem(struct ShoppingList *list){
int itemToDelet;
while (1) {
for (int i = 0; i < list->length; i++) {
printf("%d. %s \t %.2f \t %s\n", i + 1, list->itemList[i].productName, list->itemList[i].amount, list->itemList[i].unit);
}
printf("\n\nWhich product do you want to remove? ");
scanf("%d", &itemToDelet);
if (itemToDelet <= list->length) {
for (int i = 0; i < list->length; i++) {
if (itemToDelet == i + 1) {
for (int i = 0; i < list->length; i++) {
list->itemList[i].productName = list->itemList[i + 1].productName;
list->itemList[i].amount = list->itemList[i + 1].amount;
list->itemList[i].unit = list->itemList[i + 1].unit;
list->length--;
}
break;
}
break;
}
}
else {
printf("\nThe list contains only %d items!", list->length);
}
break;
}
}
To copy the contents of a string (e.g. type char[10]), use strcpy. Arrays of characters cannot be assigned, just copied.
strcpy(list->itemList[i].productName,list->itemList[i + 1].productName);
It seems that the data members productName and unit are character arrays and arrays do not have the assignment operator.
To copy strings stored in character arrays you should use the standard C function strcpy declared in the header <string.h> as for example
strcpy( list->itemList[i].productName, list->itemList[i + 1].productName );
But in any case your function is incorrect and invokes undefined behavior. The for loops within the function do not make a sense.
Instead of the for loops you could use another standard C function memmove declared in the same header <string.h> as for example
memmove( list->itemList + itemToDelet - 1,
list->itemList + itemToDelet,
( list->length - itemToDelet ) * sizeof( *list->itemList ) );
--list->length;
Also before the call of memmove you need to check that the value of itemToDelet is greater than 0.

what happens when i use malloc() twice in the same pointer?

I write a code to split string by delimiter.
I want the function get a string and return its strings divided.
It actually works except for one thing.
when I give string "test", it works.
but when I give string "1234 4567", I can access the value '4567', but not '1234'. (garbage value.)
also "1234 2345 3456 ..." results garbage value in only first argument '1234'.
I thought that using malloc() twice causes problem in the same pointer, but it doesn't.
What is the problem for my codes?
char **ft_set_char(char *str)
{
int i;
int j;
int k;
char *str_c;
char **ret;
k = 0;
j = 0;
ret = (char **)malloc(10);
str_c = (char *)malloc(5);
i = 0;
while (*(str + i) != '\0')
{
if (*(str + i) == ' ')
{
*(str_c + k) = '\0';
k = 0;
*(ret + j) = str_c;
j++;
i++;
str_c = (char *)malloc(5);
}
*(str_c + k) = *(str + i);
i++;
k++;
}
*(str_c + k) = '\0';
*(ret + j) = str_c;
*(ret + j + 1) = NULL;
return (ret);
}
ret = (char **)malloc(10);
That is not correct because it allocates 10 bytes and not 10 char * elements. It should be:
ret = malloc(10 * sizeof *ret);
Other unrelated issues but should be noted for best practice:
Don't cast the result of malloc
Don't use magic numbers like 10 and 5. For the former at least use a #define MAX_ARRAY_SIZE 10. For the latter, you can keep work out the exact size of the string to be copied from the original str - that will make your code more robust in case it is ever used with longer sub-strings.

Error when freeing calloc'd memory: free invalid next size (fast)

I'm writing a function to get text from a file and I'm encountering an issue when I try and free some calloc'd memory.
ye. wee.\n
when a txt file with the above is passed, the function allocates memory for the 3 char characters of ye. and copies them in. Then allocates memory for the other 6 characters and copies them in. Then it prints the respective strings and frees the memory.
testFor() is a function that returns the index of the first '.' in a string.
I've examined the program in gdb and when it hits free(key) it causes a segfault with the following error (sorry, can't embed images yet).
//more above
while ((fgets(line, 256, source_fp)) != NULL) {
if (line[0] == '\n') {
if (pflag) {
int first = testFor(definition);
int second = strlen(definition);
printf("%d %d\n", first, second);
key = calloc(first + 1, sizeof(char));
defn = calloc((second - (first + 1)), sizeof(char));
for (i = 0; i < (first + 1); i++) {
key[i] = definition[i];
}
int x = i + 1;
for (; i < second; i++) {
defn[i-x] = definition[i];
}
printf(">%s<\n", key);
printf(">%s<\n", defn);
free(key);
free(defn);
}
//more
I'm still new to using the memory allocation so this has me confused.
When defn[i-x] = definition[i]; is evaluated the first time, x has the value i+1, so i-x is -1.

Attempting to split and store arrays similar to strtok

For an assignment in class, we have been instructed to write a program which takes a string and a delimiter and then takes "words" and stores them in a new array of strings. i.e., the input ("my name is", " ") would return an array with elements "my" "name" "is".
Roughly, what I've attempted is to:
Use a separate helper called number_of_delimeters() to determine the size of the array of strings
Iterate through the initial array to find the number of elements in a given string which would be placed in the array
Allocate storage within my array for each string
Store the elements within the allocated memory
Include directives:
#include <stdlib.h>
#include <stdio.h>
This is the separate helper:
int number_of_delimiters (char* s, int d)
{
int numdelim = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] == d)
{
numdelim++;
}
}
return numdelim;
}
`This is the function itself:
char** split_at (char* s, char d)
{
int numdelim = number_of_delimiters(s, d);
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while (s[a] != d)
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
b++;
final[i][j+1] = '\0';
}
return final;
}
To print:
void print_string_array(char* a[], unsigned int alen)
{
printf("{");
for (int i = 0; i < alen; i++)
{
if (i == alen - 1)
{
printf("%s", a[i]);
}
else
{
printf("%s ", a[i]);
}
}
printf("}");
}
int main(int argc, char *argv[])
{
print_string_array(split_at("Hi, my name is none.", ' '), 5);
return 0;
}
This currently returns {Hi, my name is none.}
After doing some research, I realized that the purpose of this function is either similar or identical to strtok. However, looking at the source code for this proved to be little help because it included concepts we have not yet used in class.
I know the question is vague, and the code rough to read, but what can you point to as immediately problematic with this approach to the problem?
The program has several problems.
while (s[a] != d) is wrong, there is no delimiter after the last word in the string.
final[i][j+1] = '\0'; is wrong, j+1 is one position too much.
The returned array is unusable, unless you know beforehand how many elements are there.
Just for explanation:
strtok will modify the array you pass in! After
char test[] = "a b c ";
for(char* t = test; strtok(t, " "); t = NULL);
test content will be:
{ 'a', 0, 'b', 0, 'c', 0, 0 }
You get subsequently these pointers to your test array: test + 0, test + 2, test + 4, NULL.
strtok remembers the pointer you pass to it internally (most likely, you saw a static variable in your source code...) so you can (and must) pass NULL the next time you call it (as long as you want to operate on the same source string).
You, in contrast, apparently want to copy the data. Fine, one can do so. But here we get a problem:
char** final = //...
return final;
void print_string_array(char* a[], unsigned int alen)
You just return the array, but you are losing length information!
How do you want to pass the length to your print function then?
char** tokens = split_at(...);
print_string_array(tokens, sizeof(tokens));
will fail, because sizeof(tokens) will always return the size of a pointer on your local system (most likely 8, possibly 4 on older hardware)!
My personal recommendation: create a null terminated array of c strings:
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
// ^ (!)
// ...
final[numdelim + 1] = NULL;
Then your print function could look like this:
void print_string_array(char* a[]) // no len parameter any more!
{
printf("{");
if(*a)
{
printf("%s", *a); // printing first element without space
for (++a; *a; ++a) // *a: checking, if current pointer is not NULL
{
printf(" %s", *a); // next elements with spaces
}
}
printf("}");
}
No problems with length any more. Actually, this is exactly the same principle C strings use themselves (the terminating null character, remember?).
Additionally, here is a problem in your own code:
while (j < sizeofj)
{
final[i][j] = s[b];
j++; // j will always point behind your string!
b++;
}
b++;
// thus, you need:
final[i][j] = '\0'; // no +1 !
For completeness (this was discovered by n.m. already, see the other answer): If there is no trailing delimiter in your source string,
while (s[a] != d)
will read beyond your input string (which is undefined behaviour and could result in your program crashing). You need to check for the terminating null character, too:
while(s[a] && s[a] != d)
Finally: how do you want to handle subsequent delimiters? Currently, you will insert empty strings into your array? Print out your strings as follows (with two delimiting symbols - I used * and + like birth and death...):
printf("*%s+", *a);
and you will see. Is this intended?
Edit 2: The variant with pointer arithmetic (only):
char** split_at (char* s, char d)
{
int numdelim = 0;
char* t = s; // need a copy
while(*t)
{
numdelim += *t == d;
++t;
}
char** final = (char**)malloc((numdelim + 2) * sizeof(char*));
char** f = final; // pointer to current position within final
t = s; // re-assign t, using s as start pointer for new strings
while(*t) // see above
{
if(*t == d) // delimiter found!
{
// can subtract pointers --
// as long as they point to the same array!!!
char* n = (char*)malloc(t - s + 1); // +1: terminating null
*f++ = n; // store in position pointer and increment it
while(s != t) // copy the string from start to current t
*n++ = *s++;
*n = 0; // terminate the new string
}
++t; // next character...
}
*f = NULL; // and finally terminate the string array
return final;
}
While I've now been shown a more elegant solution, I've found and rectified the issues in my code:
char** split_at (char* s, char d)
{
int numdelim = 0;
int x;
for (x = 0; s[x] != '\0'; x++)
{
if (s[x] == d)
{
numdelim++;
}
}
int a = 0;
int b = 0;
char** final = (char**)malloc((numdelim+1) * sizeof(char*));
for (int i = 0; i <= numdelim; i++)
{
int sizeofj = 0;
while ((s[a] != d) && (a < x))
{
sizeofj++;
a++;
}
final[i] = (char*)malloc(sizeofj);
a++;
int j = 0;
while (j < sizeofj)
{
final[i][j] = s[b];
j++;
b++;
}
final[i][j] = '\0';
b++;
}
return final;
}
I consolidated what I previously had as a helper function, and modified some points where I incorrectly incremented .

Access to a specific element on an array using pointers C

I am working to replace '.' by '::' in a phrase.
I am given a phrase with 30 caracteres, without using other array. I would like to access to the last element using a pointer.
However,
First I count the dots in my phrase.
actualSize= 0; i= 0; dotNumb= 0;
while (i<actualSize){
if (tab[i]=='.') dotNumb++
i++
}
Now I should start by the end; whenever I find an element I move it, whenever I find a '.' I make an operation two times, by copying ':' two times.
Now I need to access to this element tab[dotNumb+actualSize]
Can I do it this way, or should I use pointers .
int newSize = dotNumb+actualSize ;
int j=newSize ;
int cursor=actualSize;
while (j>0){
if (tab[i]!='.') {tab[j]=tab[cursor]; }
else{tab[j]=':';tab[--j]=':';}
cursor--; j--;
}
The code you wrote does not work, (you made some typos, for example actualSize is set to 0 so the loop counting the dots will never execute. and the logic of your code would delete the character preceding a dot in the original array). You probably want something like that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char *tab = malloc(30 + 1);
if (tab == NULL) {
return -1;
}
strcpy(tab, "123456789.123456789.123456789.");
printf("Original string: %s\n", tab);
size_t actualSize = strlen(tab);
int dotNumb = 0;
for (int i = 0; i < actualSize; i++) {
if (tab[i]=='.') {
dotNumb++;
}
}
const size_t newSize = dotNumb + actualSize + 1;
tab = realloc (tab, newSize);
if (tab == NULL) {
/* leak memory previously allocated in tab */
return -1;
}
tab[newSize] = '\0'; /* termination character */
int j = newSize ;
for (size_t cursor = actualSize; cursor > 0; cursor--) {
if (tab[cursor] != '.') {
tab[j--] = tab[cursor];
}
else {
tab[j--] = ':';
tab[j--] = ':';
}
}
printf("Modified string: %s\n", tab);
return 0;
}
You can test the code here:
http://ideone.com/YOxJKo

Resources