Garbled string output - c

I'm currently working on an assignment which asks me to censor words of argv and input redirection.
My problem is obvious in my output which can be found below. I have a lot of tracing print statements which may or may not help you point out my issue.
My intention is:
Get file.txt
Copy contents of file.txt into buffer[x][y], where [x] is a string of word and [y] is a char of [x].
Compare argv[] arguments to buffer[][].
Create newstr[size2]. For every argv[] arguement found in buffer[][], replace it with replace[9] = "CENSORED".
Print the string of newstr[0 to (size2-1)].
Here is my code:
// censored.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define SIZE 128
int main ( int argc, char* argv[])
{
int i = 0;
int j = 0;
int k = 0;
char buffer[SIZE][SIZE];
char x;
int count = 0;
int size1 = sizeof(buffer);
int size2 = 0;
char replace[9] = "CENSORED";
int buffersize=0;
printf("tracing: size1: %d.\n", size1);
printf("tracing: argc: %d.\n", argc);
while((fscanf(stdin, "%c", &x)!=EOF))
{
if(isalpha(x))
{
buffer[i][j]=x;
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j++;
}
else if(isspace(x)) // if whitespace
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j = 0;
i++;
}
else if(ispunct(x)) // if x is a punctuation
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
}
else if(iscntrl(x)) // if control key (\n, \r etc...)
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c", i,j, buffer[i][j]);
j = 0;
i++;
}
else if(isdigit(x))
{
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j++;
}
else
{
break;
}
}
size2 = i;
printf("tracing: buffer[8][0]:%s\n",buffer[8]);
char newstr[size2][SIZE];
i = 0;
j = 0;
// tracing:
printf("tracing: line 72\n");
printf("tracing: size2: %d.\n", size2);
while(i < size2) //print buffer[]
{
printf("%s", buffer[i]);
i++;
}
printf("tracing: line 80\n");
for(k=1; k < argc; k++)
{
printf("%s\n", argv[k]);
}
// end tracing
i = 0; //reinitialize i
j = 0; //reinitialize j
// creating newstr[SIZE] and censoring words
printf("tracing: line 89\n");
for(i = 0; i < size2; i++)
{
for(j=1; j < argc; j++)
{
if(strcmp(buffer[i], argv[j])==0)
{
strcpy(newstr[i], &replace[0]);
printf("tracing: replaced at [%d]\n", i);
break;
}
else
{
strcpy(newstr[i], buffer[i]);
printf("tracing: copied at [%d]\n", i);
}
}
}
i = 0; //reinitialize i
while(i < size2)
{
printf("%s", newstr[i]);
i++;
}
return 0;
}
Assuming I have input redirection file named file.txt and its contents:
Said Hamlet to Ophelia,
I'll draw a sketch of thee,
What kind of pencil shall I use?
2B or not 2B?
my input is:
./censored Ophelia thee 2B < file.txt
this is the weird output I got:
Said Hamlet to CENSORED, Ill draw a sketch ???)ofoQ? ?"h?CENSORED,2oQ?
What? /oQ?kind? of 6oQ?pencil +oQ?shall ?"h?I-oQ? ???)use? ???2BoQ?
7oQoroQ Qnot 1oQ?CENSORED?4oQ?
Any help is appreciated, I know my code is messy, this is my first semester learning C.

I have good and bad news, the bad one is: I found a few errors and mistake.
The good one is: all of these are common for a beginner!
First one: The strings in buffer[] aren't terminated with a '\0' which is the end of string indicator. This is the one cause of your problem.
And here are the other ones:
char buffer[SIZE][SIZE];
Here you are considering that number of words and word's length can't be longer that 128 which will cause Segmentation Fault whenever this condition is wrong. I suggest you learn about dynamic allocation (malloc()).
for(j=1; j < argc; j++) If argc == 1, you won't enter this loop which would result in newstr being empty. Usually we end arrays with a NULL pointer and then check for every string of the array being non-null while reading the array so that we won't try to use undefined content.
As you pointed at, your code is quite messy, next time, try separating your code in functions and not coding in main().
Try reducing this, the fewer lines your write, the easier your code is to read and debug:
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j = 0;
i++;
This advice isn't really relevant for that kind of program designed to read a lot of data but remember: try to avoid storing data whenever you can.
I think this is enough for now, I wish you good luck and to apologize for my poor English.

Related

How do I read a list of strings from file into a dynamic two-dimensional array and then sort it in C

I'm new to C and am having difficulty with reading a file of names into a two-dimensional array to then sort. I figure I should be using malloc, but I'm not quite sure if I have to. The following is the code I have right now which reads the file and prints it out but when I go to sort it only sorts one name with some extra characters added to it. If I could get a hand I would appreciate it.
The file just contains a list of names such as:
John
Alex
George
Beasley
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 128
#define TOT 10
void selectionSort_str(char arr[][MAX_LEN], int n)
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
char minStr[MAX_LEN];
for (i = 0; i < n-1; i++)
{
// Find the minimum element in unsorted array
int min_idx = i;
strcpy(minStr, arr[i]);
for (j = i+1; j < n; j++)
{
// If min is greater than arr[j]
if (strcmp(minStr, arr[j]) > 0)
{
// Make arr[j] as minStr and update min_idx
strcpy(minStr, arr[j]);
min_idx = j;
}
}
// Swap the found minimum element with the first element
if (min_idx != i)
{
char temp[MAX_LEN];
strcpy(temp, arr[i]); //swap item[pos] and item[i]
strcpy(arr[i], arr[min_idx]);
strcpy(arr[min_idx], temp);
}
}
}
int main(void) {
char line[TOT][MAX_LEN];
FILE *plist = NULL;
int i = 0;
int total = 0;
int k = sizeof(line)/sizeof(line[0]);
plist = fopen("plist1.txt", "r");
while(fgets(line[i], MAX_LEN, plist)) {
line[i][strlen(line[i]) - 1] = '\0';
i++;
}
total = i;
for(i = 0; i < total; ++i){
printf("%s\n", line[i]);
}
//sort strings
selectionSort_str(line, k);
printf("*****Sorted array is: \n");
for(i = 0; i < k; i++)
{
printf("%s ", line[i]);
}
return 0;
}
you are possibly a victim of stale \r\n , this hack below should help
while(fgets(line[i], sizeof(line[i]), plist)) {
line[i][strlen(line[i]) - 1] = '\0';
// these stale '/r' s when used in strcmp will give unwanted results
// so strip those aswell..
if( line[i][strlen(line[i]) - 1] == '\r' )
line[i][strlen(line[i]) - 1] = '\0';
i++;
}

How to convert array contents into a single string C

So the following is a sandbox program. The issue I'm having is combining an array into a single string. I would like to do something similar to the code below:
for (i = 0; i < size_of_array; i++)
{
string += A[i]; // print array
}
The goal is to run a command using popen() and capture the output into a single string. the reason for this is so that I can return the output to a separate function for example:
run_command()
{
return output;
}
main()
{
run_command()
}
Now the exact code that the "sandbox" program is using is down below:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *in;
extern FILE *popen();
char buff[512];
int i, size_of_array;
char A[512][512];
in = popen("ls -lt", "r"); // run command
i = 0;
while(fgets(buff, sizeof(buff), in)!=NULL) // get output into buff
{
strcpy(A[i], buff); // copy buff into array
i ++;
}
pclose(in);
size_of_array = i; // get length or size of array
for (i = 0; i < size_of_array; i++)
{
printf("A[%d]= %s", i, A[i]); // print array
}
return 0;
}
I apologize if this is a noob question, I appreciate the help, thank you!
strcat, strcat_s, or strncat append a string at the end of a destination string (cf. cppreference for strcat). The only thing is to make sure that the destination buffer is large enough. strcat_s can be used to avoid buffer overflows, but is not available on all systems. strncat can be used to avoid buffer overflows, too, yet one needs to track the length of the string within the buffer:
#define maxSize 512*512
char result[maxSize] = { 0x0 };
for (int i = 0; i < size_of_array; i++) {
strcat(result, A[i]);
}
or:
char result[maxSize] = { 0x0 };
for (int i = 0; i < size_of_array; i++) {
strcat_s(result, maxSize, A[i]);
}
or:
char result[maxSize] = { 0x0 };
for (int i = 0; i < size_of_array; i++) {
strncat(result, A[i], maxSize-strlen(result)-1);
}

Char** arrays of string [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I tried to do a code that gets number from the user and create array of strings (char**) by the number but for some reason it didn't work and the code crashed. After inputting the strings, the code sorts the strings using strcmp() and then I want to print the whole array. Could anyone help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LENGTH 20
int main(void)
{
int players = 0,i=0,j=0;
char switchString[LENGTH];
printf("Hello user, Welcome to your basketball team!\nplease enter a number of players that plays in your team\n");
scanf("%d", &players);
char** team = (char**)malloc(players*sizeof(char));
for (i = 0; i < players; i++)
{
*(team+i) = (char*)malloc(LENGTH*sizeof(char));
printf("enter name of player %d\n",i+1);
fgets(*(team+i), LENGTH, stdin);
*(team+i)[strcspn(*(team+i), "\n")] = "\0";
}
for (i = 0; i <players; i++)
{
for (j = 0; j < players; j++)
{
if (strcmp(team[j - 1], team[j]) > 0)
{
strcpy(switchString, team[j-1]);
strcpy(team[j-1], team[j]);
strcpy(team[j], switchString);
}
}
}
for (i = 0; i <players; i++)
{
for (j = 0; j < players; j++)
{
printf("%c",team[i][j]);
}
printf("\n");
}
system("PAUSE");
free(team);
return 0;
}
This memory allocation
char** team = (char**)malloc(players*sizeof(char));
^^^^^^^^^^^^
is wrong. There shall be
char** team = (char**)malloc(players*sizeof(char *));
^^^^^^^^^^^^^^
This assignment
*(team+i)[strcspn(*(team+i), "\n")] = "\0";
^^^^^^^^^ ^^^^
is also wrong
There shall be
( *(team+i) )[strcspn(*(team+i), "\n")] = '\0';
^^^^^^^^^^^^^ ^^^^
Or you could just write
team[i][strcspn(team[i], "\n")] = '\0';
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
Also this loop
for (j = 0; j < players; j++)
{
if (strcmp(team[j - 1], team[j]) > 0)
{
strcpy(switchString, team[j-1]);
strcpy(team[j-1], team[j]);
strcpy(team[j], switchString);
}
}
also incorrect because when j is equal to 0 then in the if statement in expression team[j - 1] there is an attempt to access memory beyond the array.
The loop should look at least like
for (j = 1; j < players; j++)
^^^^^
{
if (strcmp(team[j - 1], team[j]) > 0)
{
strcpy(switchString, team[j-1]);
strcpy(team[j-1], team[j]);
strcpy(team[j], switchString);
}
}
And at last these loops are also nvalid
for (i = 0; i <players; i++)
{
for (j = 0; j < players; j++)
{
printf("%c",team[i][j]);
}
printf("\n");
}
because in the inner loop there are attempts to output characters after the terminating zero.
Just write
for (i = 0; i <players; i++)
{
puts( team[i] );
}
Or you could write for example
for (i = 0; i <players; i++)
{
for (j = 0; players[i][j] != '\0'; j++)
{
printf("%c",team[i][j]);
}
printf("\n");
}
And at the end of the program you need to free the allocated memory.
For example
for (i = 0; i <players; i++)
{
free( team[i] );
}
free( team );
char** team = (char**)malloc(players*sizeof(char));
(Allocate memory of players bytes)
Should be
char** team = malloc(players*sizeof(char*));
(Allocate memory to store players pointers to character)
Replace line
char** team = (char**)malloc(players*sizeof(char));
with
char** team = malloc(players*sizeof(char*));
int i;
for (i = 0; i < players; i++)
team[i] = malloc(LENGTH*sizeof(char));
Assuming you have fixed the memory allocation for the main array of pointers, then the test in the inner loop like this:
if (strcmp(team[j - 1], team[j]) > 0)
is going to lead to unhappiness when j is equal to 0, as it is on the first iteration. That's because you don't have an element with index -1. This is a major problem, even if it isn't the only remaining cause of your crash.
There's a variety of ways to do this, and a variety of issues with the code given.
Here's a working example.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LENGTH 20
int main(void)
{
int players = 0;
char switchString[LENGTH];
printf("Hello user, welcome to your basketball team!\n"
"Please enter the number of players on your team.\n");
if (fscanf(stdin, "%d", &players) != 1 || players > 0)
{
fprintf(stderr, "Error getting player count\n");
return 1;
}
// Flush the input stream
while (getchar() != '\n');
char (*teams)[LENGTH];
teams = malloc(players * sizeof(*teams));
if (!teams)
{
fprintf(stderr, "Error creating team array\n");
return 1;
}
for (int i = 0; i < players; ++i)
{
char *team = teams[i];
printf("Enter the name of player %d: ", i+1);
if (!fgets(team, LENGTH, stdin))
{
fprintf(stderr, "Error getting name of player\n");
free(team);
return 1;
}
char *endline = strchr(team, '\n');
if (endline)
*endline = '\0';
}
// Bubble sort
for (int i = 0; i < players; ++i)
{
for (int j = i; j < players; ++j)
{
if (strcmp(teams[j - 1], teams[j]) > 0)
{
strncpy(switchString, teams[j-1], LENGTH);
strncpy(teams[j-1], teams[j], LENGTH);
strncpy(teams[j], switchString, LENGTH);
}
}
}
for (int i = 0; i < players; i++)
{
printf("%s\n", teams[i]);
}
free(teams);
return 0;
Let's go through this solution piece by piece.
if (fscanf(stdin, "%d", &players) != 1 || players > 0)
{
fprintf(stderr, "Error getting player count\n");
return 1;
}
// Flush the input stream
while (getchar() != '\n');
This will get the number of players and make sure that we the newline we gave doesn't mess with the following inputs.
char (*teams)[LENGTH];
teams = malloc(players * sizeof(*teams));
if (!teams)
{
fprintf(stderr, "Error creating team array\n");
return 1;
}
This completely changes how we store teams.
Why do more mallocs than you have to?
This declares teams as a pointer to an array of LENGTH.
This means that when we malloc, we store all of the memory for the names next to each other, and teams[0] points to the char * of the first team, teams[1] points to the char * of the second team, and so on.
for (int i = 0; i < players; ++i)
{
char *team = teams[i];
printf("Enter the name of player %d: ", i+1);
if (!fgets(team, LENGTH, stdin))
{
fprintf(stderr, "Error getting name of player\n");
free(team);
return 1;
}
char *endline = strchr(team, '\n');
if (endline)
*endline = '\0';
}
Instead of using *(team + i) everywhere, the type of teams allows us to naturally refer to each element like an array of arrays.
We also do a check that fgets succeeds.
We also use strchr to remove the newline as it is clearer to read.
// Bubble sort
for (int i = 0; i < players; ++i)
{
for (int j = 0; j < players; ++j)
{
if (strcmp(teams[j - 1], teams[j]) > 0)
{
strncpy(switchString, teams[j-1], LENGTH);
strncpy(teams[j-1], teams[j], LENGTH);
strncpy(teams[j], switchString, LENGTH);
}
}
}
We now use strncpy for safety. Bubble sort can also be made more efficient.
Notice that in the original code, free was only called for the array of pointers (char **), and not each char * pointer.

Getting most frequent characters in array in c

I am trying to get the most frequent characters from an array.
Here's my code
#include <stdio.h>
int main(void)
{
int c[1000];
char input[] = "abcdab";
int i;
for(i=0; input[i]; i++)
{
c[input[i]]++;
}
int j = 0;
char str = 0;
for(i=0; i<256; i++)
{
if(c[i] > j)
{
j = c[i];
str = i;
}
}
printf("%c\n", str);
return 0;
}
It returns 'a'
But I want to get 'a' and 'b' since they are the most frequent characters in the array.
Any help would be appreciated, thank you.
You are passing through the entire array looking for a maximum, and remembering the first one. With the solution you have, you need an additional loop:
for(i=0; i<256; i++){ // Look for all maximums
if(c[i] == j) // If it is the maximum
{
printf("%c\n", i); // print the character
}
}
Note that your array c is not initialized to all zeroes, so it is purely by chance (not really) that the code is working. If you want c to be all zeroes, you need to declare it as int c[1000] = {0}; or to call memset on it.

Shuffle characters in an array in C programming

Using an online tutorial I worked on trying to shuffle characters in an array. The tutorial I used was using integers and also didn't include any user input, but when I try and replicate it and change it to do what I would like in the code I made below something is not working out.
There is no error message at all. When I run the program it only prompts the user to enter a word and then ends.
Just in case you can't understand what I wanted from the code I would like the user to be able to insert a word and then the 'shuffled' word is printed at the end. (ex. Hello > elHol)
I am still a very new programmer and have a very hard time with the subject in general so please understand any 'dumb' mistakes you'll likely come across that I've made.
Thanks in advance for any help!
#include <stdio.h>
#include <time.h>
int main ()
{
char word[15];
int i,length,j, temp;
srand(time(NULL));
printf("Insert word\n");
scanf("%s", word);
for(i=0; word[i] != '\0'; )
{
i = i + 1;
}
i = length;
for(i = 0; i < length; i++)
{
j = (rand()%length);
temp = word[i];
word[i] = word[j];
word[j] = temp;
}
for(i=0; i<length; i++)
{
printf("%c", word[i]);
}
}
Welcome ;). In addition to the other engineers's solution to your problem, I have modified your code not to use the temporary variable to swap.[ since you mentioned new programmer, i felt this should help to some extend. ;) ]
Look at the below source code.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main ()
{
char word[15];
int i,length,j, temp;
srand(time(NULL));
printf("Insert word\n");
scanf("%s", word);
for(length=0; word[length++] != '\0';);
for(i = 0; i < length; i++)
{
j = (rand()%length);
word[i] = word[i] ^ word[j];
word[j] = word[i] ^ word[j];
word[i] = word[i] ^ word[j];
}
for(i=0; i<length; i++)
{
printf("%c", word[i]);
}
}
Few changes to your code:
Make temp as char :
char temp;
Assign length to i you are doing it the other way where you are assigning i to length and since length is uninitialized and you are using it this value to assign to some other variable causes undefined behavior.
length = i;
Try my revision of your code!
This will fix the spaces and lost of vowels in printing the shuffle string. SORRY FOR MY BAD ENLISH :)
#include<stdio.h>
#include<stdlib.h>
int main(){
char word[100];
srand(time(NULL));
int i,j,length,temp;
printf("Enter a string: ");
scanf("%s",&word);
for(i = 0; word[i] != '\0'; ++i){
length = i;
}
length+=1;
i = length;
while(--i>0){
j = (rand()%length);
temp= word[j];
word[j]= word[i];
word[i]= temp;
}
for(i=0; i<=length; i++)
{
printf("%c", word[i]);
}
}

Resources