Program works but outputs trailing garbage values - c

I am working on a code that gives the steps to change one string into another and it works fine but gives garbage values.
The code is:
void steps(char str1[],char str2[]) {
int belongs,req;
strlwr(str1);
strlwr(str2);
if(strlen(str1)==strlen(str2)) {
for(int i=0;i<=strlen(str1);i++) {
if(str2[i]!=str1[i]) {
++changes;
printf("%d::SUBSTITUTION:: %c <--- %c\n",changes,str1[i],str2[i]);
str1[i]=str2[i];
printf("--->%s\n",str1);
}
}
}
if(strlen(str1)>strlen(str2)){
for(int i=strlen(str1);i>=strlen(str2);i--) {
if(str1[i]=='\0') {
}
else {
++changes;
printf("%d::DELETE:: %c\n",changes,str1[i]);
str1[i]=0;
printf("--->%s\n",str1);
}
}
}
if(strlen(str1)<strlen(str2)) {
for(int i=(strlen(str1));i<=(strlen(str2)-1);i++) {
++changes;
printf("%d::ADD:: %c\n",changes,str2[i]);
str1[i]=str2[i];
printf("-->%s\n",str1);
}
}
steps(str1,str2);
}
The output for the input strings, suppose 'sym' and 'symbiosis' is:
1::ADD:: b
-->symb
2::ADD:: i
-->symbi
3::ADD:: o
-->symbio
4::ADD:: s
-->symbios
5::ADD:: i
*-->symbiosiDzb
6::ADD:: s
-->symbiosis²b
7::DELETE:: b
--->symbiosis²
8::DELETE:: ²
--->symbiosis*
At step 5 and beyond, why is it showing me garbage values?
I tried the best I could and due to my limited knowledge in C (and
pointers) I am reluctant to use pointers and hence hesitate a bit
with DMA. Also, a strange thing that I noticed is that the garbage
values occur only when the difference between the strings is large.
Please help me fix it!

if(strlen(str1)<strlen(str2)){
for(int i=(strlen(str1));i<=(strlen(str2)-1);i++){
++changes;
printf("%d::ADD:: %c\n",changes,str2[i]);
str1[i]=str2[i];
printf("-->%s\n",str1);
}}
In that snippet, the part where you do str1[i]=str2[i]; is probably illegal.
First, strings in C are nullterminated. That means a string ends when a nullbyte comes. So if you add a character, you are overwriting the nullbyte. Therefore, you have to make sure that the character following it is a nullbyte, otherwise the string ends when the next nullbyte comes in memory. That's where the garbage data comes from.
So it would be:
str1[i]=str2[i];
str1[i + 1]=0;
Additionally, you have to make sure that the buffer is large enough. That means that the memory you reserved for str1 when calling steps might not be enough for you to append characters. Technically you can still add new characters, but what you are probably doing is overflowing the buffer and writing to memory that you don't 'own'. Which could be critical.
What you could do is allocate a new buffer with enough memory which holds your new string. You can then copy str1 into it and then append the characters from str2.
For example like this:
char buffer[512];
buffer[0] = 0;
// Write str1 into the buffer
strcat(buffer, str1);
// [...]
// Instead of 'str1[i]=str2[i];'
buffer[i]=str2[i];
buffer[i + 1] = 0;
In this example, you still have to make sure that both str1 and str2 are smaller than 512 bytes though, otherwhise you have to increase the buffer or allocate buffer on the heap using malloc (and free afterwards).
To provide a better example on how to do it, it might be helpful to see how you call the steps function.

Thanks everybody!
I was able to resolve the problem...
The working code is:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int changes=0;
void steps(char str1[],char str2[]){
char* temp;
temp=(char *)malloc((strlen(str2)));//Buffer of size of string 2 to store string 1
unsigned int length_1=strlen(str1);
unsigned int length_2=strlen(str2);
int belongs,req;
strlwr(str1);
strlwr(str2);//To avoid conversion of same letters but in different cases
//Strings of equal length:
if(strlen(str1)==strlen(str2)){
for(int i=0;i<=strlen(str1);i++){
//Strings with no swapping possible:
if(str2[i]!=str1[i]){
++changes;
printf("%d::SUBSTITUTION:: %c <--- %c\n",changes,str1[i],str2[i]);
str1[i]=str2[i];
printf("--->%s\n",str1);
}}}
//String 1 is longer than string 2, hence deletion:
if(strlen(str1)>strlen(str2)){
for(int i=strlen(str1);i>=strlen(str2);i--){
++changes;
printf("%d::DELETE:: %c\n",changes,str1[i]);
str1[i]=0;
printf("--->%s\n",str1);
}
}
//String 2 is longer than string 1, hence addition:
if(strlen(str1)<strlen(str2)){
strcpy(temp,str1);
for(int i=(strlen(str1));i<strlen(str2);i++){
if (str2[i]=='\0'){
}
else{
++changes;
printf("%d::ADD:: %c\n",changes,str2[i]);
*(temp+i)=str2[i];
*(temp+1+i)=0;
printf("-->%s\n",temp);
}}
char newstr[length_2];//Use to store 'temp' and use in steps function again
strcpy(newstr,temp);
steps(newstr,str2);
}
free(temp); //Release memory
}//End!

Related

Why is my for loop increasing the size of my array in C?

I'm trying to make a binary number calculator in c and I'm running into issues of my for loops doubling the size of my second array and adding the first array onto the end. I'm really confused because I thought you couldn't increase the size after already declaring it. It is happening in my equation reading function as well but in this ones complement function it's a bit simpler to see. Any ideas of how to fix this?the codethe output
welcome to stack-overflow. From next time please use inline code editor to put your code instead of images. I have taken effort put your code in the answer itself to explain the problem. Please consider this as courtesy. Its very unusual to do it. But as you are a new member, I'm doing it.
// Cole carson's original code from image:
char * onescomp(char x[16], char y[16]){
int i;
for(i=0;i<=15;i++){
if(x[i] == '0'){
y[i] = '1';
continue;
}
else if(x[i] == '1'){
y[i] = '0';
continue;
}
}
return y;
}
int main()
{
char b3n[16]={'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
char cb3n[16];
puts(b3n);
onescomp(b3n,cb3n);
puts(cb3n);
return 0;
}
Answer:
You don't need continue; in if-else blocks.
You need to add '\0' in the last cell of cb3n array. so puts() knows when string ends & stop printing.
so to quickly fix this issue you can create array with extra cell and assign all values as '\0'. so after copying fifteen 1's there will be '\0' in the end. I think in your case those extra zeros being printed might be garbage values. It looks like array is doubling but it isn't, its just printing values beyond allocated memory because '\0' has not been provided.
//Quick fix
int main()
{
char b3n[16]={'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
char cb3n[17]={'\0'}; // <--- quick fix
puts(b3n);
onescomp(b3n,cb3n);
puts(cb3n);
return 0;
}

How to correctly allocate memory for an array of char pointers (strings of different length)?

Sorry if it sounds like a duplicate, but I have checked similar questions and to my eye my approach is correct, therefore I would like to ask you for advice.
I want to allocate the memory for an array of pointers to the first elements of char arrays (in other words: this is an array of strings). Additionally, these strings may differ in length. I use realloc() for specific char arrays in order not to allocate unnecessary memory.
Here I present the fragments of the code that seem to be troublesome for me:
#define NUM_SEQ 4
#define MIN_BUFFER 1000
#define MAX_BUFFER 10000
char** read_the_file(char* file_name) {
//opens the file
char** sequences = malloc(NUM_SEQ*sizeof(char*));
printf("all: %ld\n", sizeof(sequences)); //OUTPUT: 8
for (int i = 0; i < NUM_SEQ; i++) {
sequences[i] = malloc(MIN_BUFFER);
printf("seq %d: %ld\n", i, sizeof(sequences[i])); //OUTPUT: 8, for each of them
}
int num_of_seq = 0; //Number of the sequence in the array of sequences
int counter = 0; //Indicates the position of the character in the string
//Loop irrelevant to the problem is omitted
if (counter == sizeof(sequences[num_of_seq])) {
printf("%ld\n", sizeof(sequences[num_of_seq]));
printf("Here\n");
if (sizeof(sequences[num_of_seq])*2 < MAX_BUFFER) {
char* temp = realloc(sequences[num_of_seq], sizeof(sequences[num_of_seq])*2);
if (temp != NULL) {
sequences[num_of_seq] = temp;
} else {
printf("Allocating memory failure\n");
exit(EXIT_FAILURE);
}
} else {
printf("The sequence is too long\n");
exit(EXIT_FAILURE);
}
}
//Let this loop die in loneliness
return sequences;
}
Reallocating of the memory is a recent modification. Without it (simply allocating with malloc) the program works fine, even under valgrind. Now the results are correct, but the valgrind returns multiply times an error:
Address 0x4a5b810 is 0 bytes after a block of size 16 alloc'd
in various functions and always refer to this realloc
Another issue: the sequences don't exceed the length of 10. The counter shouldn't be equal to the size of the array, but the loop with realloc IS entered - which shouldn't have happened.
Sorry for terrible indentation, I have a problem with keeping the text in code style on this site and thank you for your much appreciated suggestions.
As #MikeCAT suggested, the issue was the improper use of sizeof(), which returns the size of the given expression or type. The solution to this problem is tracking the actual size of the object, i.e.: using the variable actual_size_of_seq1, initialized at MIN_BUFFER for the first sequence (I use an array of sizes, though).

How to set the values from the token character to this array called customerData[][] in C?

I just started learning C language and I need some help with a program. Here is the code.
Questions:
What is this? customerData[NUM_FIELDS][FIELD_LENGTH];
Is it a char 2D array?
How do you input data into the array? fgetC, putchar, getchar ?
#include <stdio.h> #include <string.h> #include <stdlib.h>
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
int main()
{
FILE *data=NULL;
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element=0;
char *next;
char ch;
data= fopen("data.txt","r");
if(data!=NULL)
{
//token=strtok(input,"|");
/*while loop will go through line by line and stored it in an input array*/
while(fgets(input,INPUT_LENGTH,data)!= NULL)
{
next=strtok(input,"|");
while(next!=NULL)
{
//ch=getchar()
//>probably a get char for ch
strcpy(next,customerData[element][strlen(next)]);
/*need to put the values into customer data one by one*/
printf("%s\n",next);
//element+=1;
next=strtok(NULL,"|");
}
//element=0;
}
printf("program is done\n");
}
fclose(data);
return 0;
}
In general, "help me with my code" questions are off-topic on Stack Overflow. In order to keep the question on-topic, I'm going to focus only on the question of how to access 2D char arrays.
Yes, this is a 2D char array. Or, put another way, it's an array with NUM_FIELDS elements, where each element of the array is a char array with FIELD_LENGTH elements.
There are loads of ways to insert data into a 2D char array, but there are probably two I've encountered most often. Which one you choose to use will depend on how you want to think of this array.
Option 1: A 2D array of single chars
The first way to think about this variable is simply as a 2D array of chars - a grid of elements that you can access. Here, you can simply input values using the normal assignment operator. You'll want to make sure that your indexes are in range, or you'll start accessing invalid memory.
//Set a known element that's definitely in range
customerData[1][2] = 'A';
//Loop through all the elements
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
for (int jj = 0; jj < FIELD_LENGTH; jj++)
{
customerData[i][j] = 'B';
}
}
//Set an element from variables
char nextInput = getNextCharFromInput();
if(x < NUM_FIELD && y < FIELD_LENGTH)
{
customerData[x][y] = nextInput;
}
//Bad. This could corrupt memory
customerData[100][60] = 'X';
//Risky without check. How do you know x and y are in range?
cusomterData[x][y] = 'X';
You could certainly write your code by assigning these elements on character at a time. However, the broader context of your program heavily implies to me that the next option is better.
Option 2: A 1D array of fixed-length strings
In C, a "string" is simply an array of chars. So another way to look at this variable (and the one that makes the most sense for this program) is to treat it as a 1D array of length NUM_FIELDS, where each element is a string of length FIELD_LENGTH.
Looking at this this way, you can start using the C string functions to input data into the array, rather than needing to deal character by character. As before, you still need to be careful of lengths so that you don't go off the end of the strings.
Also be aware that all array decay into pointers, so char* is also a string (just of unknown length).
//Set a specific field to a known string, which is short enough to fit
strcpy(customerData[2], "date");
//Loop through all fields and wipe their data
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
memset(customerData[ii], 0, FIELD_LENGTH);
}
//Set field based on variables
if(x < NUM_FIELDS)
{
//Will truncate next if it is too long
strncpy(customerData[x], next, FIELD_LENGTH);
//Will not input anything if field is too long
if(strlen(next) < FIELD_LENGTH)
{
strcpy(customerData[x], next);
}
}
//Bad. Could corrupt memory
strcpy(customerData[100], "date");
strcpy(customerData[1], "this string is definitely much longer than FIELD_LENGTH");
//Risky. Without a check, how do you know either variable in in range?
strcpy(customerData[x], next);
getchar and fgetC both deal with reading characters, from stdout and a file respectively, so can't be used to put data into a variable. putchar does deal with put character into things, but only stdout, so can't be used here.

C strcpy crashes code

I have the following code, the code crashes whenever the strcpy function is called. When these lines are commented out the code does not crash. What is wrong?
char cities[80][17];
char char_distances[40][2];
int distances[40];
char cities_sorted[20][17];
while (!feof(Text)) {
fscanf(Text, "%[^\t]\t%[^\t]\t%[^\n]\n",
cities[i], cities[i + 1], char_distances[i]);
distances[i] = atoi(char_distances[i]);
printf("City_start: %s City_end: %s Distance: %d \n",
cities[i], cities[i + 1], distances[i]);
static char uniqueCities[21][17];
int uniqueCitiesCount;
for (int j = 0; j < 21; j++) {
printf("%s\n", uniqueCities[i]);
bool start_unique = !areEqual(cities[i], cities[j]);
bool end_unique = !areEqual(cities[i], cities[j + 1]);
if (start_unique) {
strcpy(uniqueCities[uniqueCitiesCount], cities[i]);
uniqueCitiesCount++;
}
if (end_unique) {
strcpy(uniqueCities[uniqueCitiesCount], cities[i + 1]);
strcpy(uniqueCities[uniqueCitiesCount], cities[i + 1]);
uniqueCitiesCount++;
}
}
i++;
}
Thanks
What's wrong?
Well many things:
you posted a code fragment: this is not enough information to get help diagnosing your problem. The code posted cannot be compiled and tested, does not even have definitions for all the symbols in the fragment: how is Text defined? how was it opened? is it guaranteed to be different from NULL?
i is not defined in the fragment, how is it defined? is it initialized?
while (!feof(Text)) is not a good way to test for end of input, you should instead compare the result of fscanf() with the expected number of conversions.
fscanf(Text, "%[^\t]\t%[^\t]\t%[^\n]\n", does not have enough information to avoid buffer overflows. The maximum number of characters to store into the arrays should be specified this way: fscanf(Text, "%16[^\t]\t%16[^\t]\t%1[^\n]\n",. Note however that if the input is not consistent with these limitations, conversions will fail and the rest of the input file will be read out of sync. You shoud read the lines into a line buffer and use sscanf() to parse the lines.
char char_distances[40][2]; defines an array of array that can only contain 1 character and a null terminator. The distances must all be expressed as a single digit in the input file. You should probably define the arrays with a larger size or convert the distance directly into the distances array with a %d conversion specifier.
int uniqueCitiesCount; defines a local variable that is not initialized. Using it in your loop invokes undefined behavior as you probably try to access beyond the end of the 2D array.
printf("%s\n", uniqueCities[i]); will print an empty string as no city has yet been copied to this array.
bool start_unique = !areEqual(cities[i], cities[j]); how are bool and areEqual() defined?
strcpy(uniqueCities[uniqueCitiesCount], cities[i + 1]); is duplicated. The index i + 1 is incorrect.
The logic in the loop is contorted and probably flawed. You should just compare the city name with all entries in the uniqueCities and only add it the this array after the loop if it has not been found.

Alphabetically Ordering an array of words

I'm studying C on my own in preparation for my upcoming semester of school and was wondering what I was doing wrong with my code so far.
If Things look weird it is because this is part of a much bigger grab bag of sorting functions I'm creating to get a sense of how to sort numbers,letters,arrays,and the like! I'm basically having some troubles with the manipulation of strings in C currently.
Also, I'm quite limited in my knowledge of C at the moment!
My main Consists of this:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
int numbers[10];
int size;
int main(void){
setvbuf(stdout,NULL,_IONBF,0); //This is magical code that allows me to input.
int wordNumber;
int lengthOfWord = 50;
printf("How many words do you want to enter: ");
scanf("%i", &wordNumber);
printf("%i\n",wordNumber);
char words[wordNumber][lengthOfWord];
printf("Enter %i words:",wordNumber);
int i;
for(i=0;i<wordNumber+1;i++){ //+1 is because my words[0] is blank.
fgets(&words[i], 50, stdin);
}
for(i=1;i<wordNumber+1;i++){ // Same as the above comment!
printf("%s", words[i]); //prints my words out!
}
alphabetize(words,wordNumber); //I want to sort these arrays with this function.
}
My sorting "method" I am trying to construct is below! This function is seriously flawed, but I'd thought I'd keep it all to show you where my mind was headed when writing this.
void alphabetize(char a[][],int size){ // This wont fly.
size = size+1;
int wordNumber;
int lengthOfWord;
char sortedWords[wordNumber][lengthOfWord]; //In effort for the for loop
int i;
int j;
for(i=1;i<size;i++){ //My effort to copy over this array for manipulation
for(j=1;j<size;j++){
sortedWords[i][j] = a[i][j];
}
}
//This should be kinda what I want when ordering words alphabetically, right?
for(i=1;i<size;i++){
for(j=2;j<size;j++){
if(strcmp(sortedWords[i],sortedWords[j]) > 0){
char* temp = sortedWords[i];
sortedWords[i] = sortedWords[j];
sortedWords[j] = temp;
}
}
}
for(i=1;i<size;i++){
printf("%s, ",sortedWords[i]);
}
}
I guess I also have another question as well...
When I use fgets() it's doing this thing where I get a null word for the first spot of the array. I have had other issues recently trying to scanf() char[] in certain ways specifically spacing my input word variables which "magically" gets rid of the first null space before the character. An example of this is using scanf() to write "Hello" and getting " Hello" or " ""Hello"...
Appreciate any thoughts on this, I've got all summer to study up so this doesn't need to be answered with haste! Also, thank you stack overflow as a whole for being so helpful in the past. This may be my first post, but I have been a frequent visitor for the past couple of years and it's been one of the best places for helpful advice/tips.
You're going to like this - it's a derivation of QSort, adapted to your situation. It may not work quite perfectly for you without a touchup here or there (TEST FIRST!):
void qsort (Strings[], NumberOfItems)
{
char Temp[51]; // Assumes your max string length of 50
int I1 = 0; // Primary index
int I2 = 0; // Index + 1
int NumberOfItems_1 = 0;
bool Swapped = false;
do // Outer loop
{
Swapped = false;
// Decrement our limit
NumberOfItems--;
// Save time not performing this subtraction many times
NumberOfItems_1 = NumberOfItems - 1;
// Repeatedly scan the list
for (I1 = 0; I1 < NumberOfItems_1; I1++)
{
// Save time not performing this addition many times
// I1 points to the current string
// This points to the next string
I2 = I1 + 1;
// If the current string is greater than the next string in the list,
// swap the two strings
if (strcmp(Strings[I1], Strings[I2]) > 0)
{
strcpy (Temp, Strings[I1]);
strcpy (Strings[I1], Strings[I2]);
strcpy (Strings[I2], Temp);
Swapped = true;
}
}
}
while (Swapped); // Break out when we've got nothing left to swap
}
I see a few things wrong with your code off the bat. First, you declare sortedWords as a multidimensional array (since you have sortedWords[wordnumber][lengthofword], but you try to use it with only one index later on.. this doesn't work! Also, your passing of the 2D array is not valid. Check out this post to see the valid ways to pass a 2D array: Passing a 2D array to a C++ function
Function declaration and definition
The function declaration is invalid, as you've found out. You must specify the size of every dimension of the array except the first, so you might write:
void alphabetize(char a[][SOMESIZE], int size)
However, you have a non-constant second dimension (so you're using a VLA or variable length array), which means that you need to pass both sizes to the function, and pass them before you pass the array:
void alphabetize(int size, int length, char a[size][length])
and then invoke it:
alphabetize(wordNumber, lengthOfWords, words);
Of course, you should also declare the function before you try calling it.
There are probably other issues to be addressed, but this is the immediate one that jumps out. For example, you need to use size and length to control the loops in the function. You probably don't need to copy the data into the local array (in which case you don't need the local array). Etc.
You should consider compiling with options such as:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Wold-style-declaration -Werror …
Note that note all versions of GCC support all those options, but use as many as are supported.
Input issue
You have:
int i;
for (i = 0; i < wordNumber + 1; i++) { //+1 is because my words[0] is blank.
fgets(&words[i], 50, stdin);
}
You're stepping out of bounds of your array, which potentially wreaks havoc on your code. The first entry is blank because scanf() leaves the newline in the input buffer. You should read to the end of line before going to line-based input:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
You should also check the fgets() returns a non-null pointer; don't continue if it does.

Resources