2

For C++ - I can add each char to each index in string array:

   string *x=new string[10];
    x[0] += "a";
    x[0] += "b";
    x[0] += "c";
    x[1] += "x";
    x[1] += "y";
    x[1] += "z";
    cout << "x[0]=" << x[0] << endl; // would be "abc"
    cout << "x[1]=" << x[1] << endl; // would be "xyz"

How can I do same functionality in C? I have buff2 pointer to a char array and am trying to add char value from each index of buf. I keep getting weird values when I print out buff2 value.

char buf[255];
char *buff2;
int i=0, count=0;
buff2=(char*)malloc(512*sizeof(char));

  while((n = read(fd, buf, sizeof(buf[g]))) > 0){
    for(i=0; i<n; i++){
      if(buf[i] == '\n'){
        l++;
        count2++;
      }
       else
     {   
       buff2[count2]+=buf[i];
     }
  }
8
  • 2
    having a and b being std::string the equivalent of a+=b; in C can be strcat(a,b);is C ... supposing a enough long. You use lib in C++ why not using lib too in C ? If needed you can increase result string length using realloc Commented Sep 21, 2020 at 7:50
  • 2
    First off, what is this: l++? This is an L, not an i. Also, it seems you are adding char values together in an array - you are not concatenating strings when you do buff2[count2]+=buf[i];. Commented Sep 21, 2020 at 7:50
  • 2
    Create an array of pointers, for each location as suggested use realloc and strcat(a,b) and you can then print the pointers using %s. Commented Sep 21, 2020 at 7:59
  • 2
    read(fd, buf, sizeof(buf[g])) in the best case reads only one char into buf[0], what interrest to have an array of 255 ? Commented Sep 21, 2020 at 7:59
  • 1
    warning @MohitSharma print the pointers using %s is wrong, that format write the contains of a (supposed) string, use %p for a pointer Commented Sep 21, 2020 at 8:02

3 Answers 3

5

There are several problems in your C code

  • buff is an array for nothing because you only use buff[0]
  • the variable l seems never defined/initialized, and you modify it for nothing
  • buff2[count2]+=buf[i]; always modify the same buff2[count2] until a newline because you do not increase buff2 in that case but only when reading a newline, are you sure you want that ?
  • you do not end buff2 with a null character, that probably explain I keep getting weird values when I print out buff2 value.
  • you do not have a protection in case you write out of buff2 producing an undefined behavior

string *x=new string[10];

can be in C

char ** x = calloc(10, sizeof(char *));

I use calloc to initialize with null pointers

and an equivalent of :

x[0] += "a";

can be

 strCat(&x[0], "a");

with:

char * const strCat(char ** p, const char * s)
{
   if (s != NULL) {
     if (*p == NULL)
       *p = strdup(s);
     else { 
       size_t len = strlen(*p);

       *p = realloc(*p, len + strlen(s) + 1); /* may be detect realloc returns NULL on error */
       strcpy(*p + len, s);
     }
   }

   return *p;
}

So for instance :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * const strCat(char ** p, const char * s)
{
   if (s != NULL) {
     if (*p == NULL)
       *p = strdup(s);
     else { 
       size_t len = strlen(*p);

       *p = realloc(*p, len + strlen(s) + 1); /* may be detect realloc returns NULL on error */
       strcpy(*p + len, s);
     }
   }

   return *p;
}

int main()
{
  char ** x = calloc(10, sizeof(char *));

  strCat(&x[0], "a");
  strCat(&x[0], "b");
  strCat(&x[0], "c");
  
  strCat(&x[1], "x");
  strCat(&x[1], "y");
  strCat(&x[1], "z");
  
  printf("x[0]=%s\n", x[0]);
  printf("x[1]=%s\n", x[1]);
  
  free(x[0]);
  free(x[1]);
  free(x);
  
  return 0;
}

Compilation and execution:

% gcc -Wall a.c
% ./a.out
x[0]=abc
x[1]=xyz
%

Running under valgrind:

% valgrind ./a.out
==113490== Memcheck, a memory error detector
==113490== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==113490== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==113490== Command: ./a.out
==113490== 
x[0]=abc
x[1]=xyz
==113490== 
==113490== HEAP SUMMARY:
==113490==     in use at exit: 0 bytes in 0 blocks
==113490==   total heap usage: 7 allocs, 7 frees, 98 bytes allocated
==113490== 
==113490== All heap blocks were freed -- no leaks are possible
==113490== 
==113490== For counts of detected and suppressed errors, rerun with: -v
==113490== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
%

Note however each time you concatenate a new string it is needed to go through the current string to know its length, this is not done by std::string whose knows the used length whatever the way for that, as this is the case in the answer of KamilCuk

Sign up to request clarification or add additional context in comments.

Comments

1

How can I do same functionality in C?

First implement/invent a "string".

After that you can implement the functionality. Remember about proper error handling. I just used abort() for brevity below, in normal code destructors should be run.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct string {
    char *begin;
    char *end;
    size_t free;
} string;
void string_init(string *t) {
   t->begin = t->end = NULL;
   t->free = 0;
}
void string_fini(string *t) {
   free(t->begin);
}
// iadd convention from python
int string_iadd_cstr(string *t, const char *str) {
   const size_t addlen = strlen(str);
   if (t->free < addlen + 1) {
       const size_t curlen = t->end - t->begin;
       const size_t newlen = curlen + 1 + addlen;
       void *tmp = realloc(t->begin, newlen);
       if (tmp == NULL) {
           return -1;
       }
       t->begin = tmp;
       t->end = t->begin + curlen;
       t->free = newlen - curlen;
   }
   memcpy(t->end, str, addlen + 1);
   t->end += addlen;
   t->free -= addlen;
   return 0;
}
int string_print(string *t) {
    return printf("%s", t->begin);
}

int main() {
    // string *x=new string[10];
    string *x = malloc(10 * sizeof(*x));
    if (x == NULL) abort();
    for (size_t i = 0; i < 10; ++i) {
        string_init(&x[i]);
    }

    if (string_iadd_cstr(&x[0], "a")) abort();
    if (string_iadd_cstr(&x[0], "b")) abort();
    if (string_iadd_cstr(&x[0], "c")) abort();
    if (string_iadd_cstr(&x[1], "x")) abort();
    if (string_iadd_cstr(&x[1], "y")) abort();
    if (string_iadd_cstr(&x[1], "z")) abort();

    // cout << "x[0]=" << x[0] << endl;
    printf("%s", "x[0]=");
    string_print(&x[0]);
    printf("\n");
    fflush(stdout);

    // cout << "x[1]=" << x[1] << endl;
    printf("%s", "x[1]=");
    string_print(&x[1]);
    printf("\n");
    fflush(stdout);

    // run destructors
    for (size_t i = 0; i < 10; ++i) {
        string_fini(&x[i]);
    }
    free(x);
}

2 Comments

so strange your answer was not UV, too complicated for non C++ user ? So I do ;-)
Two comments: Poster needs to add a char to a string, even if his c++ example is appending a string. It is typically not needed to allocate more space than you need, just do a realloc on each append. In extreme cases (tyny increments/huge buffer) you may get a maximum of 10x speedup doing pre-allocation. Unless you are not working with strings in a tight loop, that is not worth the extra complexity
-1

Here is a simple example if you do not want to use strcat. This is a minimal example to demonstrate how one could concatenate strings, things like reallocation of memory have not been implemented.

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    char buf[30] = "LOREM \n IPSUM DOLOR SIT AMET\0";
    char *buff2;
    int i = 0, n = 30;
    buff2 = (char*)malloc(512 * sizeof(char));

    //set first element of buff2 to be terminating null char
    buff2[0] = '\0';
    
    for(i = 0; i < n; i++) {
        if(buf[i] != '\n') {    
            buff2[i + 1] = '\0'; // shift terminating null char forward
            buff2[i] = buf[i];
        } else {
            buff2[i + 1] = '\0'; // shift terminating null char forward
            buff2[i] = 'n';
        }
    }
    
    printf("%s\n",buff2);
    
    return EXIT_SUCCESS;
}

It replaces newlines with an "n" character; you can change this if you want. Of course, you want to be careful only to address elements which have actually been allocated. Does not include function to read from file because we don't have the file; this is easily implemented. I suggest you look into fgetc.

4 Comments

You are forgetting to realloc whatever buff2 is pointing at. The fact that the poster is doing multiple reads of 512 bytes, is a hint that he wants to be able to end up with more than 512 bytes.
"Of course, you want to be careful only to address elements which have actually been allocated." It is a minimal example. My answer also doesn't include the filestream. OP wanted to know how to concatenate strings - this is an answer to that question. I even included a warning concerning memory allocation.
Yes, you did show him "a way to concatenate strings", except that in c, there is no best way to do it. Concatenating when you know the buffer is large enough, and concatenating with buffer resize is totally different. Based on the context the poster provided, he obviously wanted the latter. He asked for something similar to to std::string +=, and had no explicit limit of 512 bytes.
Ok, I think this is some kind of misunderstanding. I get your point. I may or may not have misunderstood OP's question. What I felt was most important was the string concatenation. I still feel my answer provides value here because it is the shortest one. I am also thinking about people who will read this in the future, who may only want to know about the strings, not the memory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.