How to reformat code to output properly? - c

I have code that looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
int x;
if (argc != 2) {
printf("error\n");
return -1;
}
char *ptr = argv[1];
int count[256] = {0};
while (*ptr) {
if(!isdigit(*ptr)){
count[(unsigned char)*ptr]++;
ptr++;
}
else{
printf("error\n");
return -1;
}
}
int i;
int compCount = 0;
for (i = 0 ; i != 256 ; i++) {
if (count[i]) {
// compCount += printf("%c%d",i,count[i]);
compCount +=2;
}
}
int j;
if(compCount > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
for(j=0; j!=256;j++){
if(count[j]){
printf("%c%d",j,count[j]);
}
}
}
}
I am trying to work through some test cases that I was provided. For example, my code breaks at this test case:
INPUT: ./program aabccccccggeeecccccd
EXPECTED: a2b1c6g2e3c5d1
OUTPUT: a2b1c11d1e3g2
Any suggestions as to how I can fix this?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// dst needs to at least strlen(src)*2+1 in size.
void encode(char* dst, const char* src) {
while (1) {
char ch = *src;
if (!ch) {
*dst = 0;
return;
}
size_t count = 1;
while (*(++src) == ch)
++count;
*(dst++) = ch;
dst += sprintf(dst, "%zu", count);
}
}
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "usage\n");
return 1;
}
const char* src = argv[1];
char* dst = malloc(strlen(src)*2+1);
encode(dst, src);
printf("%s\n", dst);
free(dst);
return 0;
}
$ gcc -Wall -Wextra -pedantic -std=c99 -o a a.c
$ ./a aabccccccggeeecccccd
a2b1c6g2e3c5d1
$ ./a abc
a1b1c1

The code does not even compile, because it had 2 errors. The main one was that the esdigit function was defined but the liberia that mentions this procedure, which is ctype (#include <ctype.h>), was not included.
Another error was that a variable x was declared but not used
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "error\n");
return 1;
}
char *ptr = argv[1];
int count[256] = {0};
while (*ptr) {
if(!isdigit(*ptr)){
count[(unsigned char)*ptr]++;
ptr++;
}
else{
printf("error\n");
return -1;
}
}
int i;
size_t compCount = 0;
for (i = 0 ; i != 256 ; i++) {
if (count[i]) {
compCount +=2;
}
}
int j;
if(compCount > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
for(j=0; j!=256;j++){
if(count[j]){
printf("%c%d",j,count[j]);
}
}
}
printf("\n");
return 0;
}

Related

Cannot use both Argv's, cannot run Move twice segmentation fault

Ive been trying various ways to get my program to work. regardless of weather i try argv1 or argv2 first, the second one will segmentation fault. even if i try to print SOURCE2DEFINE or argv[2] AFTER a move() it will segmentation fault. i cannot move both files trying to run move twice will result in a segmentation fault. im assuming that it has to be something to do with pointers and allocation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define SOURCEDEFINE argv[1]
#define SOURCE2DEFINE argv[2]
#define DESTDEFINE argv[argc - 1]
#define ARGCDEFINE argc
#define COMMANDDEFINE argv[0]
int getIndex(char, char*);
char* fileGetName(char*);
void move(char*, char*);
void copy(char*, char*);
int main(int argc, char** argv)
{
printf("Test Argc: %d\n", argc);
int lengthArray = argc-2;
printf("Test Length: %d\n", lengthArray);
printf(" command %s\n", COMMANDDEFINE);
printf("%s\n", DESTDEFINE);
if(strcmp("./copy", COMMANDDEFINE) == 0)
{
// copy(source, dest);
}
else if(strcmp("./move", COMMANDDEFINE) == 0)
{
int i = 1;
printf("Test 1: %s\n", argv[i]);
printf("Test 2: %s\n", argv[argc-1]);
move(SOURCEDEFINE, DESTDEFINE);
printf("%s Filename debug \n", SOURCE2DEFINE);
move(SOURCE2DEFINE, DESTDEFINE);
// i++;
}
return 0;
}
void moveMultiple(int argc, char** argv){
int index = 1;
while(argv[index] != NULL){
if(index < argc - 1){
move(argv[index],argv[argc - 1]);
index++;
}
}
}
void move(char *source, char* dest)
{
printf("Running Move\n");
// FILE *s = fopen(source, "r");
// FILE *s;
//FILE *s = fopen(source, "r");
strcat(dest, fileGetName(source));
int l = link(source, dest);
//if(s == NULL)
if(l)
{
printf("Error, File Not Found");
perror("Link");
fflush(stdout);
exit(1);
}
remove(source);
}
void copy(char *source, char* dest)
{
printf("Running Copy\n");
strcat(dest, fileGetName(source));
int l = link(source, dest);
//if(s == NULL)
if(l)
{
printf("Error, File Not Found");
perror("Link");
fflush(stdout);
exit(1);
}
}
char* fileGetName(char *filename)
{
int i = 0;
int length = strlen(filename);
char *catString;
int index = getIndex('/', filename);
index--;
memcpy(catString,&filename[index], length);
return catString;
}
int getIndex(char i, char *s)
{
printf("Running getIndex\n");
int index = -1;
for(int l =0; l<strlen(s); l++){
if(s[l] == i) {
index = l;
}
}
return index;
}
Your move method changes dest (which is really argv[i]), and overwrites the memory after it: strcat(dest, fileGetName(source));. This destroys the other parameter and probably some other things. Don't write strings into memory you don't own.

reading file`s lines char by char into char** array

I wrote the next function that tries to read and enter each line from text file into a string array in c :
int main(int argc,char* argv[])
{
char ** lines;
readFile(argv[1],lines);
}
int readFile(char* filePath,char** lines)
{
char file_char;
int letter_in_line=0;
int line=1;
char* line_string=malloc(1024);
int j=1;
int fd=open(filePath,O_RDONLY);
if (fd < 0)
{
return 0;
}
while (read(fd,&file_char,1) >0)
{
if(file_char != '\n' && file_char != '0x0')
{
line_string[letter_in_line] = file_char;
letter_in_line++;
}
else
{
if(lines != NULL)
{
lines=(char**)realloc(lines,sizeof(char*)*line);
}
else
{
lines=(char**)malloc(sizeof(char*));
}
char* line_s_copy=strdup(line_string);
lines[line-1]=line_s_copy;
line++;
letter_in_line=0;
memset(line_string,0,strlen(line_string));
}
j++;
}
printf("cell 0 : %s",lines[0]);
return 1;
}
I have 2 questions :
1)Whenever the code reaches the print of cell 0, I'm getting
Segmentation fault (core dumped) error. What is wrong ?
2)In case I
want to see the changes in the lines array in my main, I should pass
&lines to the func and get char*** lines as an argument ? In
addition, I will need to replace every 'line' keyword with '*line' ?
*I know that I can use fopen,fget, etc... I decided to implement it in this way for a reason.
There is many issues that make your code core dump.
Here a version very similar to your code. I hope it will help you to understand this.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* open the file */
const int fd = open(filename, O_RDONLY);
if (fd < 0) {
*result = NULL;
return -1;
}
/* read the file characters by characters */
char *buffer = (char *)malloc(sizeof(char) * 1024);
char c;
int column = 0;
int line = 0;
*result = NULL;
/* for each characters in the file */
while (read(fd, &c, 1) > 0) {
/* check for end of line */
if (c != '\n' && c != 0 && column < 1024 - 1)
buffer[column++] = c;
else {
/* string are null terminated in C */
buffer[column] = 0;
column = 0;
/* alloc memory for this line in result */
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
/* duplicate buffer and store it in result */
(*result)[line++] = strdup(buffer);
}
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}
Here an other version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* init result */
*result = NULL;
/* open the file */
FILE *file = fopen(filename, "r");
if (file == NULL)
return -1;
/* read the file line by line */
char *buffer = (char *)malloc(sizeof(char) * 1024);
int line = 0;
while (fgets(buffer, 1024, file)) {
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
(*result)[line++] = strdup(buffer);
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}

File redirection loops in custom shell c

Trying make a custom shell in c that executes (among others) this command
ls -l >> text.txt
Now this used to work, but after changes in getArgs() it either loops endlessly printing success messages without creating a file, or terminates abnormally.
Here is the immediately relevant code
else if(option == 3){
directory=" ";
if(A[0]=='.' || A[0]=='/'){
directory="./";
}
getArgs(&A,args,directory,&size);
for(i=0;i<size;i++){
printf("arg[%d] : %s\n",i,args[i]);
}
directory=concat(directory,args[0]);
printf("directory %s\n",directory );
fp = open(args[3],O_RDWR | O_CREAT|O_TRUNC,S_IRWXU);
pid=fork();
if(pid==0){
com = args[0];
dup2(fp,STDOUT_FILENO);
readCommand(args,directory,com,0);
return 1;
}
waitpid(-1,&status,0);
dup2(output,STDOUT_FILENO);
if(WIFEXITED(status)){
printf("Data successfully saved in file");
}else{
printf("Abnormal termination\n");
}
close(fp);
close(output);
clean(args);
}
Here is the mylib.c file including getArgs()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "mylib.h"
#define MAX_SIZE 50
void getArgs(char **A,char *args[10], char *directory,int *sizeA){
int i,j,num,slash,size;
char *token,*s,*dummy;
trim(*A,&size);
*A=(char*)realloc(*A,(size) * sizeof(char*));
token = strtok (*A, " ");
num=0;
while (token != NULL)
{
args[num] = token;
token = strtok (NULL, " ");
num++;
}
s=args[0];
for(i=num;i<10;i++){
args[i]="\0";
}
if(*A[0]=='.' || *A[0]=='/'){
for(i=0;*args[i]!='\0';i++){
if(args[0][i]=='/'){
slash=i;
}
}
slash+=1;
j=0;
if(*A[0]=='.'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
else if(*A[0]=='/'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
}
*sizeA=num;
}
//resets args array
void clean(char *args[10]){
int i;
for(i=0;i<10;i++){
args[i] = '\0';
}
}
//reads and executes command
void readCommand(char *args[10],char *directory,char *com, int i){
if(execl(directory, args[i],args[i+1], NULL)==-1){
execl("/bin/sh", "/bin/sh", "-c", com, NULL);
perror("execlp");
}
else{
execl(directory, args[0],args[1],args[2],args[3],args[4], NULL); //max number of args=4
perror("execlp");
}
}
//concatenates 2 strings
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1);
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
return result;
}
//trims the /n from the argument
void trim(char *A,int *size) {
int i=0;
do{
*size=i;
if(A[i]=='\n'){
A[i]='\0';
}
i++;
}while(A[i]!='\n');
}

Returning an array of pointers to `char`

This program should concatenate strings, But I don't know how return the string array back to main.
char **conca(char *a[], int n)
{
char buff[200];
char **conc[n];
for (int i = 0; i < n; i++)
{
strcpy(buff,a[i]);
strcat(buff,"-");
int l = strlen(buff);
*conc[i] = malloc((l+1)*sizeof(char));
strcpy(*conc[i],buff);
}
return *conc;
In main.c:
char **conca(char *a[], int n);
int main(int argc, char *argv[])
{
if(argc == 1)
{
printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
return 1;
}
int dim = argc - 1;
int pos = 0;
char *array[dim];
for(int i = 1; i <= dim; i++ )
{
array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
strcpy(array[pos],argv[i]);
pos++;
}
char **f = conca(array, dim);
}
The program triggers a segmentation fault (core dump).
How can I print the concatenated string in main?
You need return char* instead of array of pointer to char.
Like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *join(char *a[], int n, char sep){
size_t lens[n], total_length = 0;
for (int i = 0; i < n; i++){
total_length += (lens[i] = strlen(a[i]));
}
total_length += n;//sep * (n-1) + NUL
char *ret = malloc(total_length);
char *wk = ret;
for (int i = 0; i < n; i++){
if(i)
*wk++ = sep;
memcpy(wk, a[i], lens[i]);
wk += lens[i];
}
*wk = 0;
return ret;
}
int main(int argc, char *argv[]){
if(argc == 1){
printf("Uso: %s <stringa> <stringa> ... <stringa> \n", argv[0]);
return 1;
}
int dim = argc - 1;
char *concata = join(argv+1, dim, '-');
puts(concata);
free(concata);
}
Reason of segfault is you can not initialize memory for *conc[i] like that :
*conc[i] = malloc((l+1)*sizeof(char))
instead you have to do
conc[i] = malloc((l+1)*sizeof(char))
But you have another problem here. You're declaring the array as a local variable. conc is an array of pointers which is stored in conca()'s stack frame, so this is, technically speaking, undefined behavior. The solution is to change conc to a char ** and use malloc() to allocate the whole array
(and remember to free it later)
So i modified your char **conca(char *a[], int n) function. so i used **conc instead of array of pointer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **conca(char *a[], int n)
{
char buff[200];
char **conc = (char **)malloc(n*sizeof(char *));
int i=0;
for (i = 0; i < n; i++)
{
strcpy(buff,a[i]);
strcat(buff,"-");
int l = strlen(buff);
conc[i]=(char *)malloc((l+1)*sizeof(char));
strcpy(conc[i],buff);
}
return conc;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
return 1;
}
int dim = argc - 1;
int pos = 0;
char *array[dim];
int i=0;
for(i = 1; i <= dim; i++ )
{
array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
strcpy(array[pos],argv[i]);
pos++;
pos++;
}
char **f = conca(array, dim);
for(i=0;i<dim;i++)
printf("%s",f[i]);
printf("\n\n");
}
Instead of returning char **, You should return char *.
There is also no error checking on malloc, which is needed since you can return a NULL pointer if unsuccessful.
Here is an example that shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *join(char *argv[], int n);
int main(int argc, char *argv[]){
char *result;
if(argc == 1){
printf("Uso: %s <stringa> <stringa> ... <stringa> \n", argv[0]);
return 1;
}
result = join(argv, argc);
printf("%s\n", result);
free(result);
result = NULL;
return 0;
}
char *join(char *argv[], int n) {
int i;
const char *sep = "-";
char *string;
size_t strsize = 0;
for (i = 1; i < n; i++) {
strsize += strlen(argv[i])+1;
}
string = malloc(strsize);
if (!string) {
printf("Cannot allocate memory for string.\n");
exit(EXIT_FAILURE);
}
*string = '\0';
for (i = 1; i < n; i++) {
strcat(string, argv[i]);
if (i < n-1) {
strcat(string, sep);
}
}
return string;
}
Input:
$ gcc -Wall -Wextra -Wpedantic -std=c99 -o concat concat.c
$ ./concat Always check return of malloc
Output:
Always-check-return-of-malloc
the following code:
cleanly compiles
performs the desired functionality
properly outputs error messages to stderr
properly checks for errors
includes the proper #include statements
is appropriately commented
contains some the original posted code as comments to highlite where changes were made
avoids unnecessary variables
displays the resulting concatenated string
cleans up after itself
and now the code
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), realloc(), free()
#include <string.h> // strlen(), strcat()
//char **conca(char *a[], int n);
// function prototypes
char *concat(char *argv[], int argc);
int main(int argc, char *argv[])
{
if(argc == 1)
{
fprintf( stderr, "Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
//printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
exit( EXIT_FAILURE );
//return 1;
}
char *newCat = concat( argv, argc );
printf( "%s\n", newCat );
free( newCat );
} // end function: main
char *concat(char *argv[], int argc)
{
char *newString = malloc(1);
if( !newString )
{ // then malloc failed
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
newString[0] = '\0';
for( int i = 1; i <= argc; i++ )
//for(int i = 1; i <= dim; i++ )
{
char * tempptr = realloc( newString, strlen( newString) + strlen(argv[i])+2 );
if( !tempptr )
{ // then realloc failed
perror( "realloc failed" );
free( newString );
exit( EXIT_FAILURE );
}
// implied else, realloc successful
newString = tempptr;
//array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
//strcpy(array[pos],argv[i]);
strcat( newString, argv[i] );
// avoid a trailing '-' in final string
if( i < (argc-1) )
{
strcat( newString, "-" );
}
} // end for
return newString;
} // end function: concat

main not recognizing my function

#include <stdio.h>
#include <stdlib.h>
void reverse(char* lines[], int count)
{
for (int i = count-1; i >= 0; i--)
{
printf("%s", lines[i]);
}
}
.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sortutil.h"
#include "reverse.h"
int getarray(char *lines[]);
void printarray(char *lines[], int max);
int main(int argc, char* argv[])
{
char* arr[100];
int numlines = getarray(arr);
printf("There are %d lines\n", numlines);
printarray(arr, numlines);
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-s") == 0)
{
sortutil(arr);
printarray(arr, numlines);
}
if (strcmp(argv[i], "-r") == 0)
{
reverse(arr, numlines);
printarray(arr, numlines);
}
}
}
int getarray(char *lines[])
{
int i = 0;
char *text = (char *)malloc(200);
while (fgets(text, 200, stdin) != NULL)
{
lines[i] = text;
i++;
text = (char *)malloc(200);
}
return i;
}
void printarray(char *lines[], int max)
{
for (int i = 0; i < max; i++)
{
printf("%s\n\n", lines[i]);
}
}
when i compile the main function it is telling me that there is an undefined reference to 'reverse'. I did #include "reverse.h" so it shouldn't have a problem seeing the reverse function. Am I missing something
You're missing the implementation. You defined the prototype, but the function body itself is missing. It is in a separate file, and you need to tell the linker about it. When you compile your main.cc - add the other file to the command line as well.

Resources