Problems with dynamic array and pointer in C - c

I want to read the following lines from STDIN and save the values in c:
A:2
B:3
C:AAAA1
C:AASC2
C:aade3
D:1
D:199
Here is my c program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
int main(int argc, char **argv)
{
char buf[BUFSIZ];
short a = 0;
short b = 0;
short anzb=0;
short anza=0;
char *c
short *d;
short i;
while (fgets(buf, BUFSIZ, stdin) != NULL)
{
if (buf[strlen(buf)-1] == '\n') {
char *isa = strstr(buf, "A:");
char *isb = strstr(buf, "B:");
char *isc = strstr(buf, "C:");
char *isd = strstr(buf, "D:");
if(isa){
char *sep = substring(isa,3,strlen(isa));
a = atoi(sep);
d = malloc(a * sizeof(short));
}else if(isb){
char *sep = substring(isb,3,strlen(isb));
b = atoi(sep);
c = malloc(b * sizeof(char));
}else if(isc){
char *sep = substring(isc,3,strlen(isc));
c[anzc] = sep;
anzc++;
}else if(isd){
char *sep = substring(isd,3,strlen(isd));
d[anzd] = sep;
anzd++;
}
}
}
printf("%i\n", a);
printf("%i\n", b);
for(i=0; i<=anzc-1;i++){
printf("%c", c[i]);
}
return 0;
}
I am new in c so i dont't have much knowledge about pointers and arrays so i hope you could help me.
After the values A: and B: are read and stored in a and b i could create my array for the lines of c and d. And i think here is my problem. I dont know how i could create an array at this time in my program. I tried with malloc and other things but there is my knowledge zu small for.
I only want to create an array at the time if i have read the values (sizes) for c and d (A and B).
And then i want to save the values in the array.
I hope you could help me to fix my code. I have tried much at this day but nothing worked and i am now very helpless.
EDIT:
New try where i get an segmentation fault 11:
else if(isb){
char *sep = substring(isb,8,strlen(isb));
b = atoi(sep);
c = malloc(b * sizeof(char*));
int i;
for (i = 0; i < subst; i++)
{
c[i] = malloc(13);
}
}else if(isc){
char *sep = substring(isc,8,strlen(isc));
strcpy(c[anzc], &buf[3]);
anzc++;
}

Your allocation is more or less correct however you're overlooking some details. B provides you a value of 3, that is how many entries there are for C, not the length of each. You then allocated a single array when you in fact need a 2-D array which should be of type char* this array will point to 3 other arrays which will contain each of the values on the C lines. So;
This line c = malloc(b * sizeof(char)); needs to be c = malloc(b * sizeof(char*));
Then you need to do;
int i;
for (i = 0; i < b; i++)
{
c[i] = malloc(length); // where length is some arbitrary buffer length
// because you have no way of knowing the length of the individual strings.
}
After this you can use strcpy to copy the lines into each of the char arrays you've allocated in the for loop.
So to accomplish the copy you need to do something like this;
int iC = 0;
// outside of the while loop we need a control var track the index
// of the c array. it needs to work independent of the normal iteration.
//inside the while loop
else if(isc){
strcpy(c[iC], &buf[3])
iC++;
}

Related

Error on hand-coded concatenate function (Segmentation fault (core dumped)) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm trying to make a function that concatenates a, b, and c in a single variable called result.
#include <stdio.h>
const char* concat(char* a, char* b, char* c) {
char *result; // Concatenated variable (A + B)
int i; // Index of A, B and C
int ir; // Index of result
// result = A
for(i=0; a[i] != '\0'; i++) {
ir = i;
result[ir] = a[i];
} // → for
// result = A + B
ir++;
for(i = 0; b[i] != '\0'; i++) {
if (i == 0)
ir = ir + i;
result[ir] = b[i];
} // → for
// result = A + B + C
ir++;
for(i = 0; c[i] != '\0'; i++) {
ir = ir + i;
result[ir] = c[i];
} // → for
return result;
} // → concatenate()
But when I compile and run with the following block it results in Segmentation fault (core dumped) error. I've already searched about it (What is a segmentation fault?) but the insight didn't come. What am I doing wrong?
int main() {
char* a = "1234567";
char* b = "abcdefg";
char* c = "_______";
printf("%s", concat(a, b, c));
}
ERROR:
Segmentation fault (core dumped)
The code shown is trying to store data into an undefined buffer (result), and that's not not kosher. SOMEBODY has to allocate the space, either your function, or the caller by passing in a bounded output buffer.
Using the allocate-memory mechanism, you have to get the full size of all the strings in advance so you can allocate the full chunk at once. After allocating the full chunk, copy in the strings one at a time.
char *concat3(const char *a, const char *b, const char *c)
{
// get the required size in advance
size_t n = 0;
for (const char *ap = a; *ap; ap++) n++;
for (const char *bp = b; *bp; bp++) n++;
for (const char *cp = c; *cp; cp++) n++;
char *result = malloc(n + 1);
char *op = result;
while (*op = *a++) op++;
while (*op = *b++) op++;
while (*op = *c++) op++;
return result;
}
Also note that the parameters are const char * rather than char * to make sure everybody knows that concat3 - I changed the name - will not write to these input buffers.
However, the return value cannot be const because you have to free it, which I hope you remember to do.
EDIT I added a different version that writes into a bounded output buffer so there's no memory allocation required in the function because the caller is responsible for it:
char *concat(char *obuf, size_t osize, const char *a, const char *b, const char *c)
{
char *obuf_save = obuf;
const char *obuf_max = obuf + osize - 1;
while (obuf < obuf_max && (*obuf = *a++)) obuf++;
while (obuf < obuf_max && (*obuf = *b++)) obuf++;
while (obuf < obuf_max && (*obuf = *c++)) obuf++;
*obuf = 0;
return obuf_save;
}
The key part is passing the output buffer and size, and it promises not to overwrite the end of the buffer.
Key downside: you can't tell if it truncated or not. Depends on your application if this matters.
You're never initializing result, so it will have a random value, so you've got UB (undefined behavior), which can result in a segfault.
You have to do a malloc for result. And, it needs to have enough space to hold the length of all the concatenated strings.
Here's some updated code. Note that I did not thoroughly check your for loops, but, at first glance they seem to be okay.
But, you have to add an EOS at the end of result because the for loops do not do that.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t
mystrlen(const char *buf)
{
const char *bp;
for (bp = buf; *bp != 0; ++bp);
return bp - buf;
}
#if 0
const char *
concat(char *a, char *b, char *c)
#else
char *
concat(const char *a, const char *b, const char *c)
#endif
{
char *result; // Concatenated variable (A + B)
int i; // Index of A, B and C
int ir; // Index of result
// NOTE/BUG: result is _never_ given a value
#if 1
size_t totlen = 0;
// we need to determine the total length of the result string
totlen += mystrlen(a);
totlen += mystrlen(b);
totlen += mystrlen(c);
result = malloc(totlen + 1);
*result = 0;
#endif
// result = A
for (i = 0; a[i] != '\0'; i++) {
ir = i;
result[ir] = a[i];
}
// result = A + B
ir++;
for (i = 0; b[i] != '\0'; i++) {
if (i == 0)
ir = ir + i;
result[ir] = b[i];
}
// result = A + B + C
ir++;
for (i = 0; c[i] != '\0'; i++) {
ir = ir + i;
result[ir] = c[i];
}
result[totlen] = 0;
return result;
}
Edit: This was my original post. But, as others have pointed out, it was not the real issue.
So, disregard this section altogether!
I'm leaving it in because several responders here also misread the intent of your function at first glance. So, you may wish to add more comments to clarify the use of arguments and return value.
When you do:
char* a = "1234567";
You are creating a pointer that points to a string literal. On most/many systems, the literal will be placed in read only memory.
So, you will segfault on a protection exception [because you're trying to write to read only memory].
Also, the target buffer needs to be large enough to contain the size of all the concatenated strings. As you have it, a is too short/small.
You could try:
char a[100] = "1234567";
This creates a writable buffer of length 100 that is initialized with the string. But, you'll still have extra space to accomodate the concatenated strings [up to a total length of 100].

exercise 9.7 Kochan. strange output

I am working to learn C using Kochan's Programming in C 4th edition. problem 9.7 the goal is to insert a string of characters into another array. I am supposed to write a function to accomplish this. I have two problems.
When I have the algorithm print the result as it goes through the if statements, it produces the desired output, however when I change it to an %s, I only get a partial output. My hunch is that a null character is being placed where i do not want it, but I simply cannot see it.
To see what was happening, I added a printf that would track the letter and the array space it was occupying. I was surprised to see that the first letter was not 0, but was blank, and the next letter was assigned the 0. Any insight into this would be appreciated.
The funtion of interest is "insertString".
#include <stdio.h>
#include <stdbool.h>
char x[] = {"the wrong son was shot that day"};
char text[] = {"per"};
int countString (char x[])
{
int counter, z;
for (counter = 0; x[counter] != '\0'; ++counter)
z = counter+1;
return z;
}
void insertString (char text[],char x[],int n) //source, text to input, where
{
int count, clock, i = countString(text), q = countString(x);
int counter = 0;
char y[i + q];
for(count = 0; x[count] != '\0'; ++count){
if (count < n){
y[count] = x[count];
printf("%c %i", y[count], count); //The integer call is just to put a number next to the
//letter. This is where my second issue is shown.
}
else if (counter <= i){
y[count] = text[counter];
++counter;
printf("%c", y[count]);
}
else{
y[count]= x[count - counter];
printf("%c", y[count]);
}
}
printf("\n\n");
y[count-counter] = '\0';
printf("%s", y);
}
int main (void)
{
void insertString(char text[], char x[], int i);
int countString(char x[]);
int i;
insertString(text, x, 10);
return 0;
}
10 out of 10 times I post here it is because im doing something dumb, so I use SO as an absolute last resort if i am getting into the territory of just randomly trying stuff with no methodology. Thanks for your patience in advance.
Your condition is wrong in the for. It should be x[count - counter] != '\0'
In the second condition use just < to avoid overindexing. (else if (counter < i))
You put the terminating NULL char at wrong place. You should do this: y[count] = '\0'
printf inside a string routine like this is fine for debugging, but it's a poor way to write a general-purpose function because it makes it impossible to use its output for further programmatic manipulation. It can also make it difficult to reason about how the state of the function interacts in unpredictable ways with the state of the printed data.
I assume you haven't learned about dynamic memory allocation which is a prerequisite to returning strings from functions. You can inline the function logic into main or printf only at the end of the function in the meantime.
Adding to this point, a void function would need to reallocate space in the string to insert into and would be in-place. This seems likely less generally useful than allocating a new string to hold the result.
Using global variables like char x[] when there's no need is poor practice. It's better to put those strings scoped to main. Since your function can access these variables in addition to its parameters, confusion can ensue when scope and encapsulation is breached.
Use consistent formatting and avoid variable names like q that mean virtually nothing. Instead of adding comments to explain poor var names:
void insertString (char text[],char x[],int n) //source, text to input, where
You can simply name the variables exactly what they represent:
void insertString(char *dest, char *source, int add_index)
Also, now that you've mastered countString, you can abstract this by calling the builtin strlen.
Be sure to allocate enough space in buffers: char y[i + q]; should be y[i+q+1] to allow room for the null terminator '\0'.
As for the logic, I think it's easier to break into three loops without conditions instead of one loop with conditions. This makes it easier to break the problem down into the three constituent steps:
Add everything up until add_index from the dest string to the result.
Add everything in the source string to the result.
Add everything after add_index from the dest string to the result.
Using this approach, all that's left is figuring out how to map the indexes appropriately. Here it is in code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
int result_size = source_len + dest_len + 1;
char *result = malloc(result_size);
for (int i = 0; i < add_index; i++) {
result[i] = dest[i];
}
for (int i = 0; i < source_len; i++) {
result[i+add_index] = source[i];
}
for (int i = add_index; i < dest_len; i++) {
result[i+add_index] = dest[i];
}
result[result_size-1] = '\0';
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Although this is likely for instructional purposes, these operations can be abstracted further using builtin string functions like strncpy and sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int result_size = strlen(dest) + strlen(source) + 1;
char *result = malloc(result_size);
char pre[add_index+1];
pre[add_index] = '\0';
strncpy(pre, dest, add_index);
sprintf(result, "%s%s%s", pre, source, dest + add_index);
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Doing this in-place is more straightforward. Since the result already has the prefix, you can copy the destination postfix to create a source-sized gap in the middle and then overwrite the gap using the source string. It's up to the caller to make sure that the destination buffer is large enough to hold the insertion.
#include <stdio.h>
#include <string.h>
void insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
for (int i = add_index; i < dest_len; i++) {
dest[i+add_index] = dest[i];
}
for (int i = 0; i < source_len; i++) {
dest[i+add_index] = source[i];
}
}
int main(void) {
// allocate extra space in the string to hold the insertion
char greeting[32] = "hello world";
insert_string(greeting, "cruel ", 6);
printf("%s\n", greeting);
return 0;
}
A note of caution: none of these functions handle errors at all, so they're unsafe. Correct functions should check that the add_index falls within the bounds of the dest string. This is an exercise for the reader.
The original exercise is here:
Your function is not doing it. You need to insert the string into another string not to create a new one with both mixed. You can do it this way of course and then copy it into the original one - but it is the most uneficient way to archive it (memory & timewise).
Use the correct types.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
char *strinsert(char *dest, size_t pos, const char *istr)
{
char *temp = dest, *work;
size_t ilen = mystrlen(istr);
size_t nmove;
while(*temp) temp++;
nmove = temp - dest - pos + 1;
work = temp;
temp += ilen;
while(nmove--) *temp-- = *work--;
work = dest + pos;
while(*istr) *work++ = *istr++;
return dest;
}
int main()
{
char dest[128] = "0123456789012345678901234567890123456789";
printf("%s", strinsert(dest, 7, "ABCD"));
}
https://godbolt.org/z/KMnLU2

how to make two array strings into one array string in C

How do you make 2 array strings into 1 array string, where I can print out all the 52 playing cards?
my code:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main() {
char deck[52];
char suits[] = {"Hearts","Diamonds","Clubs","Spades"};
char values[]= {"Ace","Two","Three","Four","Five","Six",\
"Seven","Eight","Nine","Ten","Jack",\
"Queen","King"};
int V, S, d = 0;
char string;
for ( S= 0; S <4; S++) {
for (V =0; V< 13; V++) {
string = strcat( values[V], suits[S]);
deck[d] = string;
printf("%s\n", string);//prints out all the 52 playing cards
d++;
}
}
return 0;
}
When I executed the program, the problem comes up which asks me to debug the program or close the program, where I closed the program in the end, which returns nothing. Can you please give me the answer which works?
Check the below code which fixes the issues in your code:
The problem with your code is you try to modify the actual string before printing and because of this there is a modified string in the next iteration. So just copy the values and suits to array and print it out as shown below.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main()
{
int i=0;
char deck[30] = "";
char suits[][30] = {"Hearts","Diamonds","Clubs","Spades"};
char values[][30]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int V, S;
for ( S= 0; S <13; S++)
{
for (V =0; V< 4; V++){
memset(deck,0,sizeof(deck));/* Clear the buffer before writing new value*/
strcpy( deck, values[S]);
strcat(deck,suits[V]);
printf("%s\n", deck);//prints out all the 52 playing cards
i++;
}
}
printf("Number of playing cards: %d\n",i);
return 0;
}
strcat() returns a char *, a pointer to a char, not a char.
You are not even required to even consider the return value of strcat() since the destination pointer (first argument) will now contain the concatenated string, assuming enough memory is already allocated.
So here in your code, you are trying to put the concatenated string to values[V] which could fail when memory already allocated to it becomes insufficient.
The best method would be to allocate some memory (as you did with deck[]) and set it all to zeroes. Then keep strcat()ing there.
strcat(deck, values[V]);
strcat(deck, suits[S]);
An alternative to using strcpy and strcat is to use sprintf.
#include<stdio.h>
#include<string.h>
#define NUM_SUITS 4
#define CARDS_PER_SUIT 13
#define TOTAL_CARDS (NUM_SUITS * CARDS_PER_SUIT)
int main()
{
char deck[TOTAL_CARDS][24];
char* suits[NUM_SUITS] = {"Hearts","Diamonds","Clubs","Spades"};
char* values[CARDS_PER_SUIT]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int s, c, i;
for(s = 0; s < NUM_SUITS; s++)
{
for(c = 0; c < CARDS_PER_SUIT; c++)
{
sprintf(deck[(s * CARDS_PER_SUIT) + c], "%s of %s", values[c], suits[s]);
}
}
for(i = 0; i < TOTAL_CARDS; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}

copying portions of string, which are stored in a char array, to another array

I wanted to try and copy parts of strings which are already stored in one array of strings to another empty array. (I think called array of pointers to char arrays )
I would like to copy the first 3 characters of each string and store them in the second array and then print them out - like so
AAA
BBB
CCC
DDD
EEE
FFF
Here is my code.
void main()
{
/*ARRAY 1*/
char *line1 = "AAAAA";
char *line2 = "BBBBB";
char *line3 = "CCCCC";
char *line4 = "DDDDD";
char *line5 = "EEEEE";
char *line6 = "FFFFF";
char *array1[6];
array1[0] = line1;
array1[1] = line2;
array1[2] = line3;
array1[3] = line4;
array1[4] = line5;
array1[5] = line6;
int i;
char *array_main[6];
for(i = 0; i<6 ; i++ ) {
array_main[i] = ("%*.*s\n",1,3,array1[i]);
printf("%s", array_main[i]);
printf("\n");
}
}
do i need to do a malloc here ? (for array_main[i]) from what i understand, I am basically just copying the address of the particular characters to array_main's elements.
EDIT - Sorry, I should have made this clearer, I want to collect the strings in array_main and then print them in order outside of the loop which actually copies the data.
You are copying pointers to statically declared strings to an array. That's theoretically fine. Howevery, you want to cut off the remainder of the strings, so you need to prepare memory for the target strings, because if you write to the strings you will invoke undefined behaviour.
This line:
array_main[i] = ("%*.*s\n",1,3,array1[i]);
definitely doesn't do what you want though. I think this shouldn't even compile.
You loop over the array and malloc the appropriate size of bytes (3+1), then copy over the parts of the string that you want (don't forget the 0-byte at the end).
So it should look like this:
for(i = 0; i < 6; i++)
{
array_main[i] = malloc(4);
snprintf(array_main[i], 4, "%.3s", array[i]);
printf("%s\n", array_main[i]);
free(array_main[i]);
}
A simpler version (with unneccessary memeory overhead) would be this:
for(i = 0; i < 6; i++)
{
array_main[i] = strdup(array[i]);
array_main[i][3] = 0;
printf("%s\n", array_main[i]);
free(array_main[i]);
}
#include <stdio.h>
#include <string.h>
int main(void){
const char *array1[6] = {"AAAAA", "BBBBB", "CCCCC", "DDDDD", "EEEEE", "FFFFF" };
char array_main[6][4] = {{0}};//4 : 3 + 1 (+1 for End of string('\0'))
int i;
for(i = 0; i<6 ; i++ ) {
strncpy(array_main[i], array1[i], 3);
printf("%s\n", array_main[i]);
}
return 0;
}

C Library function for converting a string of hex digits to ints?

I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}

Resources