George Go
George Go

Reputation: 77

C Adding each char into array

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

Upvotes: 2

Views: 135

Answers (3)

NXP5Z
NXP5Z

Reputation: 173

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.

Upvotes: -1

bruno
bruno

Reputation: 32586

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

Upvotes: 5

KamilCuk
KamilCuk

Reputation: 140970

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

Upvotes: 1

Related Questions