Returning an array of pointers to `char` - c

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

Related

C forever Loop after return from a sub function

I have a function parse, which I am calling in the main,
it reads the 2D array expense row one by one, if the total columns in any Row of expense are not equal to 5, it returns 1 and prints an error. but it's stuck in a forever loop. Since I am very new to c, I am unable to figure it out.
int parse (char* exp, char* exp_str) {
char d[] = " ";
char *cpyexp;
strcpy(cpyexp, exp);
printf("cpyexp %s \n", cpyexp);
printf("strlen(cpyexp) %lu \n", strlen(cpyexp));
if(strlen(cpyexp) != 9)
{
fprintf(stderr, "error1: parse() failed\n");
return 1;
}
return 0;
}
int main(int argc, char** argv) {
char* file = NULL ;
char expenses [ROWS][COLS] = {{"CAR,14,10"},{"INS,10,12"}} ;
char expenses_str [ROWS][17] ;
int i = 0;
while(expenses[i][0] != '\0' ){
if(parse (expenses[i], expenses_str[i]) == 1) {
fprintf(stderr, "error3: parse_instruction() failed\n");
return 1;
}
if (expenses[i]== NULL || expenses[i] == '\0'){
break;
}
i++;
}
}
int parse (char* exp, char* exp_str) {
char d[] = " ";
char *cpyexp =malloc(strlen(exp)+1)* sizeof(char)) \\this is initialized as NULL and hats why getting an error
strcpy(cpyexp, exp);
printf("cpyexp %s \n", cpyexp);
printf("strlen(cpyexp) %lu \n", strlen(cpyexp));
if(strlen(cpyexp) != 9)
{
fprintf(stderr, "error1: parse() failed\n");
return 1;
}
return 0;
}
int main(int argc, char** argv) {
char* file = NULL ;
char expenses [ROWS][COLS] = {{"CAR,14,10"},{"INS,10,12"}} ;
char expenses_str [ROWS][17] ;
int i = 0;
while(expenses[i][0] != '\0' ){
if(parse (expenses[i], expenses_str[i]) == 1) {
fprintf(stderr, "error3: parse_instruction() failed\n");
return 1;
}
if (expenses[i]== NULL || expenses[i] == '\0'){
break;
}
i++;
}
}

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.

Update array of strings in function

I have a working example of copy lines from a file into an array of strings. I want to move the code to copy the lines into a function to which I simply pass a pointer to the array of strings, where the lines will be stored, and a pointer to the file. However, I have tried to move the code into a function and keep getting seg faults. I have tried debugging using GDB and it seems like the problem is with the memory allocation to rows. But I can't work out what the problem is. realloc seems to be working correctly since I find the size of row increases on the 3rd iteration (using malloc_usable_size(*rows)), but then seg faults. I'm compiling with gcc -Wall -Wextra -pedantic -std=c99 -g c_programs/read_file_function.c on Linux.
Working example
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
rows[i] = (char *)malloc(lineLength + 1);
strcpy(rows[i], lineBuf);
i++;
nLines = i;
rows = (char **)realloc(rows, (nLines + 1) * sizeof(char *));
}
printf("nLines: %lu\n", nLines);
printf("row 1: %s\n", rows[0]);
printf("row 2: %s\n", rows[1]);
printf("row 2: %s\n", rows[10]);
return 0;
}
Non working function version
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t readFile(FILE **fp, char ***rows)
{
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, *fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
*rows[i] = (char *)malloc(lineLength + 1);
strcpy(*rows[i], lineBuf);
i++;
nLines = i;
*rows = (char **)realloc(*rows, (nLines + 1) * sizeof(char *));
}
return nLines;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
size_t nLines = readFile(&fp, &rows);
printf("nLines: %lu", nLines);
printf("row 1: %s", rows[0]);
printf("row 2: %s", rows[1]);
return 0;
}
*rows[i] is doing *(rows[i]) - accessing ith element in the array of rows, and then dereferencing it. You want to do (*rows)[i] - dereference rows and then access ith element.
I advise to:
readFile(..., char ***rows0) {
char **rows = NULL; // temporary internal variable
...
// use rows normally
rows = stuff();
...
// when finished, assign once
*rows0 = rows;
return nLines;
}
But do not be a 3-star programmer. At best, use a structure, -> is easy to use. Like:
struct string {
char *str;
};
struct lines {
struct string *strs;
size_t cnt;
};
// #return 0 on success, otherwise error
int readFile(...., struct lines *p) {
// initialization
p->cnt = 0;
p->strs = NULL;
...
void *pnt = realloc(p->strs, (p->cnt + 1) * ....);
if (!pnt) { /* handle error */ return -1; }
p->strs = pnt;
p->strs[p->cnt]->str = malloc(lineLenght + 1);
if (!p->strs[p->cnt]->str) { /* handle error */ return -2; }
strcpy(p->strs[p->cnt]->str, lineBuf);
p->cnt++;
...
return 0; /* success */
}
int main(int argc, char **argv) {
struct lines p = {0};
if (readFile(..., &p)) {
/* handle error */
}
printf("nLines: %zu\n", p.cnt);
Do not pre-allocate memory. Initialize memory with NULL and call realloc before using memory. realloc(NULL is the same as malloc().
Check for allocation errors.

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;
}

How to reformat code to output properly?

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;
}

Resources