helloeveryone. I am fairly new to programming and currently trying to learn C programming to advance further in any of my projects. I've just learned how to use malloc and realloc, and all seemed good until I attempted to use strcat to combine two given strings from multidimensional array.
I am supposed to get combination of two strings based on the user inputs, and strangely, the first character is either missing or replaced by other characters...
I'll include the source code as well as the output below. I'd really appreciate you help. Thanks in advance!! ( don't mind the Korean at the end... I am korean :P)
enter code here
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int i, j;
const int row = 3;
char *pstr[3];
char temp[100];
int k,p = 0;
printf("Type in any three characters\n");
for (i = 0; i < row; i++)
{
pstr[i] = (char *)malloc(strlen(temp) + 1); //initialize the lenght of the elements in 2 part of 2D array of char b[ROW] via length of the given string
}
for (i = 0; i < row; i++)
{
scanf("%s", temp);
strcpy(pstr[i], temp);
}
printf("\n");
for (i = 0; i < row; i++)
{
printf("%s\n", pstr[i]);
}
scanf("%d", &p);
scanf("%d", &k);
printf("%s\n", pstr[p]);
printf("%s\n", pstr[k]);
*pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
strcat(pstr[k], pstr[p]);
printf("%s", pstr[k]);
for (i = 0; i < row; i++)
{
free(pstr[i]);
}
return 0;
}
\
output::LINK IS AN INTERNATIONAL SIGN FOR , IMAGE OVER HERE!!!
Two major problems:
You use temp before it have been initialized, when its contents is indeterminate and that will lead to undefined behavior.
When you do *pstr[k] = realloc(...) you dereference the pointer in pstr[k] and gets it's first element, which is a single character. You then assign the result of the realloc call to this char element. So you basically lose the actual pointer and pstr[k] will still point to the same memory (which might now be invalid).
There are other problems, but these two are the worst.
I found these in your code
1) if k or p is greater than 2 it will give runtime error
2) *pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
but this line can give error in compile time also(mac at least) - as they are not same
so you may change like this -
*pstr[k] = *(char *)realloc(pstr[k], strlen(pstr[p])+100);
3) After realloc you will get exception in free. see this - How free memory after of realloc
Related
I'm trying to do a program that get number of names from the user, then it get the names from the user and save them in array in strings. After it, it sort the names in the array by abc and then print the names ordered. The program work good, but the problem is when I try to free the dynamic memory I defined.
Here is the code:
#include <stdio.h>
#include <string.h>
#define STR_LEN 51
void myFgets(char str[], int n);
void sortString(char** arr, int numberOfStrings);
int main(void)
{
int i = 0, numberOfFriends = 0, sizeOfMemory = 0;
char name[STR_LEN] = { 0 };
char** arrOfNames = (char*)malloc(sizeof(int) * sizeOfMemory);
printf("Enter number of friends: ");
scanf("%d", &numberOfFriends);
getchar();
for (i = 0; i < numberOfFriends; i++) // In this loop we save the names into the array.
{
printf("Enter name of friend %d: ", i + 1);
myFgets(name, STR_LEN); // Get the name from the user.
sizeOfMemory += 1;
arrOfNames = (char*)realloc(arrOfNames, sizeof(int) * sizeOfMemory); // Change the size of the memory to more place to pointer from the last time.
arrOfNames[i] = (char*)malloc(sizeof(char) * strlen(name) + 1); // Set dynamic size to the name.
*(arrOfNames[i]) = '\0'; // We remove the string in the currnet name.
strncat(arrOfNames[i], name, strlen(name) + 1); // Then, we save the name of the user into the string.
}
sortString(arrOfNames, numberOfFriends); // We use this function to sort the array.
for (i = 0; i < numberOfFriends; i++)
{
printf("Friend %d: %s\n", i + 1, arrOfNames[i]);
}
for (i = 0; i < numberOfFriends; i++)
{
free(arrOfNames[i]);
}
free(arrOfNames);
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
/*In this function we get array of strings and sort the array by abc.
Input: The array and the long.
Output: None*/
void sortString(char** arr, int numberOfStrings)
{
int i = 0, x = 0;
char tmp[STR_LEN] = { 0 };
for (i = 0; i < numberOfStrings; i++) // In this loop we run on all the indexes of the array. From the first string to the last.
{
for (x = i + 1; x < numberOfStrings; x++) // In this loop we run on the next indexes and check if is there smaller string than the currnet.
{
if (strcmp(arr[i], arr[x]) > 0) // If the original string is bigger than the currnet string.
{
strncat(tmp, arr[i], strlen(arr[i])); // Save the original string to temp string.
// Switch between the orginal to the smaller string.
arr[i][0] = '\0';
strncat(arr[i], arr[x], strlen(arr[x]));
arr[x][0] = '\0';
strncat(arr[x], tmp, strlen(tmp));
tmp[0] = '\0';
}
}
}
}
After the print of the names, when I want to free the names and the array, in the first try to free, I get an error of: "HEAP CORRUPTION DETECTED: after normal block(#87)". By the way, I get this error only when I enter 4 or more players. If I enter 3 or less players, the program work properly.
Why does that happen and what I should do to fix it?
First of all remove the unnecessary (and partly wrong) casts of the return value of malloc and realloc. In other words: replace (char*)malloc(... with malloc(..., and the same for realloc.
Then there is a big problem here: realloc(arrOfNames, sizeof(int) * sizeOfMemory) : you want to allocate an array of pointers not an array of int and the size of a pointer may or may not be the same as the size of an int. You need sizeof(char**) or rather the less error prone sizeof(*arrOfNames) here.
Furthermore this in too convoluted (but not actually wrong):
*(arrOfNames[i]) = '\0';
strncat(arrOfNames[i], name, strlen(name) + 1);
instead you can simply use this:
strcpy(arrOfNames[i], name);
Same thing in the sort function.
Keep your code simple.
But actually there are more problems in your sort function. You naively swap the contents of the strings (which by the way is inefficient), but the real problem is that if you copy a longer string, say "Walter" into a shorter one, say "Joe", you'll write beyond the end of the allocated memory for "Joe".
Instead of swapping the content of the strings just swap the pointers.
I suggest you take a pencil and a piece of paper and draw the pointers and the memory they point to.
I'm looking for converting each ordinal value returned from web_reg using web_convert_param in for loop and do some operations. Below is my code:
char str1[] = "";
web_reg_save_param("fetch", "LB=XXXXX", "RB=YYYYY", "ORD=ALL", LAST);
lr_param_sprintf("c_final_buf", "");
for (k = 1; k <= atoi(lr_eval_string("{fetch_count}")); k++){
sprintf(str1, "%s", lr_paramarr_idx("fetch",k));
lr_save_string(str1, "buffer1");
web_convert_param("buffer1Conv", "SourceString={buffer1}", "SourceEncoding=PLAIN", "TargetEncoding=URL",LAST);
lr_param_sprintf("c_buffer", "ABC%s=%s&",
lr_paramarr_idx("c_param",k), lr_eval_string("{CovPunchVal}"));
lr_param_sprintf("c_final_buf", "%s%s", lr_eval_string("{c_final_buf}"), lr_eval_string("{c_buffer}"));
}
By using above code sometime's I am getting MEMORY VIOLATION EXCEPTION at sprintf(str1, "%s", lr_paramarr_idx("fetch",k));. Can someone please suggest how can I achieve above without involving any external variables.
EDIT1: Would like to avoid using lr_paramarr_idx("c_param",k) as well as it may cause memory exceptions during run times as per few online forms.
The reason you are getting MEMORY VIOLATION EXCEPTION at sprintf(str1, "%s", lr_paramarr_idx("fetch",k)); may be related to str1 declaration.
It should be fixed size character array like char str1[256]; rather than char str1[] = "";
Also, maybe the follwing code may be of use to you as an alternative:
int k;
int count;
//web_reg_save_param("fetch", "LB=XXXXX", "RB=YYYYY", "ORD=ALL", LAST);
// simulation of parameters array
lr_save_string("101:abc","fetch_1");
lr_save_string("102:abc","fetch_2");
lr_save_string("103:abc","fetch_3");
lr_save_string("104:abc","fetch_4");
lr_save_string("105:abc","fetch_5");
lr_save_string("106:abc","fetch_6");
lr_save_string("107:abc","fetch_7");
lr_save_string("108:abc","fetch_8");
lr_save_string("109:abc","fetch_9");
lr_save_string("110:abc","fetch_10");
lr_save_string("111:abc","fetch_11");
lr_save_string("112:abc","fetch_12");
lr_save_string("113:abc","fetch_13");
lr_save_string("114:abc","fetch_14");
lr_save_string("115:abc","fetch_15");
lr_save_string("116:abc","fetch_16");
lr_save_string("117:abc","fetch_17");
lr_save_string("118:abc","fetch_18");
lr_save_string("119:abc","fetch_19");
lr_save_string("120:abc","fetch_20");
lr_save_string("20","fetch_count");
// convert values inside array
count = atoi(lr_eval_string("{fetch_count}"));
for (k = 1; k <= count; k++){
lr_save_int(k,"ParamIndex");
web_convert_param(lr_eval_string("fetch_{ParamIndex}"), "SourceEncoding=PLAIN", "TargetEncoding=URL",LAST);
}
// continue the required manipulations…
Issue got resolved now. Below is the update code:
char tmpbuf[256];
for (k = 1; k <= atoi(lr_eval_string("{fetch_count}")); k++){
// sprintf(str1, "%s", lr_paramarr_idx("fetch",k));
// lr_save_string(str1, "buffer1");
sprintf(tmpbuf, lr_paramarr_idx("fetch",k));
lr_save_string(tmpbuf, "buffer1");
web_convert_param("buffer1Conv", "SourceString={buffer1}", "SourceEncoding=PLAIN", "TargetEncoding=URL",LAST);
lr_param_sprintf("c_buffer", "ABC%s=%s&",
lr_paramarr_idx("c_param",k), lr_eval_string("{CovPunchVal}"));
lr_param_sprintf("c_final_buf", "%s%s", lr_eval_string("{c_final_buf}"), lr_eval_string("{c_buffer}"));
}
Regards
I want to remove some elements from my array and re-size it.
for example my array is:
char get_res[6] = {0x32,0x32,0x34,0x16,0x00,0x00};
Now I want to remove elements after 0x16, so my desire array is:
get_res[] = {0x32,0x32,0x34,0x16};
what is solution?
You cannot resize arrays in C (unlike Python, for example). For real resizing, at least from an API user's point of view, use malloc, calloc, realloc, and free (realloc specifically).
Anyway, "resizing" an array can be imitated using
a delimiter; for example, a delimiter like 0xff could mark the end of the valid data in the array
Example:
#define DELIMITER 0xff
print_data(char* data) {
for (size_t i = 0; data[i] != DELIMITER; ++i)
printf("%x", data[i]);
}
a member counter; count the number of valid data from the beginning of the array onward
Example:
size_t counter = 5;
print_data(char* data) {
for (size_t i = 0; i < counter; ++i)
printf("%x", data[i]);
}
Notes:
Use unsigned char for binary data. char may be aliasing signed char, which you might run into problems with because signed char contains a sign bit.
There is no need to "remove" them. Just don't access them. Pretend like they don't exist. Same like in stacks, when you "pop" a value from the top of the stack, you just decrement the stack pointer.
Manipulating arrays in C isn't easy as it is for vector in C++ or List in Java. There is no "remove element" in C. I mean that you have to do the job yourself, that is, create another array, copy only the elements you want to this new array, and free the memory occupied by the previous one.
Can you do that? Do you want the code?
EDIT:
Try that. It's just a simple program that simulates the situation. Now, you have to see the example and adapt it to your code.
#include <stdio.h>
#include <stdlib.h>
int main() {
char get_res[6] = {0x32,0x32,0x34,0x16,0x00,0x00};
char target = 0x16;
int pos, i, length = 6; // or specify some way to get this number
for(i = 0; i < length; i++)
if(get_res[i] == target) {
pos = i;
break;
}
pos = pos + 1; // as you have to ignore the target itself
char *new_arr = malloc(pos);
for(i = 0; i < length; i++) {
new_arr[i] = get_res[i];
i++;
}
for(i = 0; i < pos; i++)
printf("%c ", new_arr[i]);
return 0;
}
I've been reading around and I've been applying what I've been reading to my code but I am not sure if I am missing something.. the 2d array is suppose to mirror sudoku.
I know the problem area is in my arrayMake function.
My professor recommended using a cast with the malloc call so:
sudoku = (int**)malloc(sudokus*sizeof(int*)); but that did not work for me.
int main(){
int sudokus;
int** sudoku;
sudokus = getUserInfo();
sudoku = arrayMake(sudokus);
/*for (int i = 0; i < (SIZE*sudokus), i++;){
for (int j = 0; j < SIZE, j++;){
printf("Numbers[%d][%d]:%d", i, j, sudoku[i][j]);
}
}*/
system("pause");
return 0;
}
int getUserInfo(){
int sudokus;
printf("How many Sudokus are you checking today?\n");
scanf("%d{^\n]\n", &sudokus);
return sudokus;
}
int** arrayMake(int sudokus){
int **sudoku;
int realsize;
realsize = 9 * sudokus;
sudoku = malloc(realsize*sizeof(int*));
if (sudoku == NULL){
printf("Memory allocation failed");
return 0;
}
for (int i = 0; i < realsize, i++;){
sudoku[i] = malloc(9 * sizeof(int));
if (sudoku[i] == NULL){
printf("Memory allocaiton failed");
return 0;
}
}
return sudoku;
}
My professor recommended using a cast with the malloc call so: sudoku = (int**)malloc(sudokus * sizeof(int*)); but that did not work for me.
To dynamically allocate for 2D array, you usually need to do two steps. Your code is not clear as you include a realsize = 9 * sudokus which doesn't make sense. Anyway, for simplicity, lets assume your sudoku is a 3x3 matrix. You'll need to:
Allocate for the pointer to pointer to int:
int **sudoku = malloc( 3 * sizeof( int * ) );
Allocate for each of the individual pointer to int:
for( int i = 0; i < 3; i++ )
sudoku[i] = malloc( 3 * sizeof( int ) );
From what I see your problem exists in your for loops where you have:
for (i = 0;i < realsize , i++)
when you really meant:
for (i = 0;i < realsize ; i++)
^
Note the change of , to ;
scanf("%d{^\n]\n", &sudokus); is a mistake.
I guess you meant the { to actually be a [ but the format string is still wrong even after that change. I think you intended to consume the rest of the input, up to and including a newline character. However, your format string does not actually do that.
Scanf'ing for \n actually means consume any amount of whitespace, so in fact this code (with the [ fix) would continue waiting for input until there was a newline, and also another non-whitespace character typed after the newline.
Better would be:
scanf("%d", &sudokus);
int ch;
while ( (ch = getchar()) != '\n' && ch != EOF ) { }
There are a few different ways to achieve the same goal. (Note that scanning for %d[^\n]%c is not one of them; that string is also broken).
Also I would suggest a different variable name than sudokus. It's confusing having two similarly-named variables sudoku and sudokus. Name it something that reflects its meaning.
For allocating your array, it would be much simpler to take out the arrayMake function and write something like:
int sudoku[9][9];
(I couldn't figure out what sudokus was supposed to mean or what realsize was going to be, but you could put your intended dimension inside the square brackets there).
I'm trying to create an array of patterns for a triangle that I'm also printing to the console. I do this by creating a 2d char array where
char patterns [number_of_patterns][pattern_lengths]. I pass this to a function that takes the array patterns along with the height of the triangle I'm trying to make.
void printTriangle (int rows, char rowPatterns[][rows]) {
int initialSpaces = rows - 1;
int numberOfAsterisks = 1;
int i;
for (i = 0; i < rows; i++) {
char temp[rows];
int spaceCounter = 0;
int asteriskCounter = 0;
while (spaceCounter < initialSpaces) {
printf(" ");
sprintf(temp, " ");
spaceCounter++;
}
while (asteriskCounter < numberOfAsterisks) {
sprintf(temp, "*");
printf("*");
asteriskCounter++;
}
while (spaceCounter < initialSpaces) {
spaceCounter = 0;
sprintf(temp, " ");
spaceCounter++;
}
strcpy(rowPatterns[i], temp);
printf("\n");
initialSpaces--;
numberOfAsterisks+=2;
}
}
For every row of the triangle that I'm printing, I create a string for that row called temp. At the end of the for loop that prints the row to the console and sprintf's it to the array temp, I strcpy temp into patterns[i]. Then I go back to the top of the loop, reinitialize temp to make it fresh, and loop again until I have all my rows. Except for some reason sprint won't fill in my array temp. Is this incorrect use of the function, or does it have to do w my parameter passing?
sprintf always writes to the start of the string. To append, you can maintain a pointer to the end of the string:
char *ptr = rowpatterns[i];
ptr += sprintf(ptr, "*");
You might also hear the suggestion to use strcat - avoid that function. When building strings, repeated strcat is very slow and is a common source of performance issues in string code.