copy pointer to pointer (an array containting pointer) to another one - c

I tried to copy a pointer to pointer (an array containing pointer) but when I ran it get weird result:
here is my code:
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
void mycopy(char *c[], char *o[], int olen);
char *alloc(int n);
int main() {
char *o[] = { "12", "13", "14" };
char *c[3];
mycopy(c, o, 3);
for (int i = 0; i < 3; i++) {
printf("%s\n", o[i]);
printf("%s\n", c[i]);
}
return 0;
}
void mycopy(char *c[], char *o[], int olen) {
char *t;
for (int i = 0; i < olen; i++) {
//printf("%d\n", strlen(o[i]));
if ((t = alloc(strlen(o[i]))) == NULL) {
printf("don't use copy cause there isn't enough space\n");
return;
}
//printf("%s\n", o[i]);
strcpy(t, o[i]);
//printf("%s\n", t);
*c++ = t;
}
}
#define MAXBUF 1000000
char buf[MAXBUF]; /* Maximum space which we can allocate */
char *bufc = buf;
/* alloc: allocate space to a pointer */
char *alloc(int n) {
if (buf + MAXBUF - bufc >= n) {
bufc += n;
return bufc - n;
}
else
return 0;
}
weirdly the result for c is:
121314 1314 14
while I checked the process by commented printfs in mycopy function and every thing seems right.
is there anyway other way to copy ?
oh and I'm a beginner in c so while I tried to solve an example in K&R2 this problem came up to me.

t = alloc(strlen(o[i]))
But the length of a string is strlen+1, because you need one byte for the trailing nul terminator.
If you're not sure, just use strdup instead.
NB. You can see exactly why this gives the output it does, by examining the address stored in each of your three pointers. Either use your debugger, or just print the addresses.

Each element is in the form: '1' '2' '\0' (the last is the terminator).
Your buffer at the end contains: ['1', '2', '1', '3', '1', '4', '\0', ..........] and when you print you're actually printing from the beginning of your current element up to the first '\0'. Each time you overwrite the last '\0' (printf stops there). You just should "alloc(strlen(o[i] + 1)".

Related

excess # in printing array elements in c

I've written a c program to recursively reverse a 10 char array:
#include<stdio.h>
void rev(char *, char *);
int a = 0;
void main()
{
char in[10], out[10];
scanf("%s", in);
rev(in, out);
printf("in is:%s\n", in);
printf("out is:%s\n", out);
for(a = 0; a < 10; a++)
{
printf("out[%d] is:%c\n", a, out[a]);
}
}
void rev(char *in, char *out)
{
if(a < 10)
{
a++;
rev(in, out);
out[9 - (--a)] = in[a];
}
}
but it returns an # at the end of array when I print the whole array while when I print array elements one by one, it doesn't exists.
please tell me what it is?
rev is reversing the entire in array, not just the part that contains the user's input. So it's copying the uninitialized values after the input.
The reason you're seeing different output when you print out than when you print the individual characters is because you're not adding a null byte to out. So printing the string goes past the end of the array when it looks for the null byte.
You should only reverse the part of the array up to strlen(in) rather than the entire array.
You also should pass a as a parameter, not use a global variable.
And finally, when you reach the end you need to add a null byte to the output string.
void rev(char *in, char *out, start, len)
{
if(start < len)
{
rev(in, out, start + 1, len);
out[len - start-1] = in[start];
} else {
out[start] = '\0';
}
}
And call it:
rev(in, out, 0, strlen(in));

loop to reverse string in C

So I've looked around on SO and can't find code that answers my question. I have written a function that is supposed to reverse a string as input in cmd-line. Here is the function:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x > 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
string = line;
}
When I call my reverse() function, the string stays the same. i.e., 'abc' remains 'abc'
If more info is needed or question is inappropriate, let me know.
Thanks!!
You're declaring your line array one char shorter remember the null at the end.
Another point, it should be for (x = strlen(string) - 1; x >= 0; x--) since you need to copy the character at 0.
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string) + 1];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
for(x = 0; x < strlen(string); x++)
{
string[x] = line[x];
}
}
Note that this function will cause an apocalypse when passed an empty string or a string literal (as Bobby Sacamano said).
Suggestion you can probably do: void reverse(char source[], char[] dest) and do checks if the source string is empty.
I think that your answer is almost correct. You don't actually need an extra slot for the null character in line. You just need two minor changes:
Change the assignment statement at the bottom of the procedure to a memcpy.
Change the loop condition to <-
So, your correct code is this:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
memcpy(string, line, sizeof(char) * strlen(line));
}
Since you want to reverse a string, you first must decide whether you want to reverse a copy of the string, or reverse the string in-situ (in place). Since you asked about this in 'C' context, assume you mean to change the existing string (reverse the existing string) and make a copy of the string in the calling function if you want to preserve the original.
You will need the string library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Array indexing works, and this version takes that approach,
/* this first version uses array indexing */
char*
streverse_a(char string[])
{
int len; /*how big is your string*/
int ndx; /*because 'i' is hard to search for*/
char tmp; /*hold character to swap*/
if(!string) return(string); /*avoid NULL*/
if( (len=strlen(string)) < 2 ) return(string); /*one and done*/
for( ndx=0; ndx<len/2; ndx++ ) {
tmp=string[ndx];
string[ndx]=string[len-1-ndx];
string[len-1-ndx]=tmp;
}
return(string);
}
But you can do the same with pointers,
/* this is how K&R would write the function with pointers */
char*
streverse(char* sp)
{
int len, ndx; /*how big is your string */
char tmp, *bp, *ep; /*pointers to begin/end, swap temporary*/
if(!sp) return(sp); /*avoid NULL*/
if( (len=strlen(bp=sp)) < 2 ) return(sp); /*one and done*/
for( ep=bp+len-1; bp<ep; bp++, ep-- ) {
tmp=*bp; *bp=*ep; *ep=tmp; /*swap*/
}
return(sp);
}
(No, really, the compiler does not charge less for returning void.)
And because you always test your code,
char s[][100] = {
"", "A", "AB", "ABC", "ABCD", "ABCDE",
"hello, world", "goodbye, cruel world", "pwnz0r3d", "enough"
};
int
main()
{
/* suppose your string is declared as 'a' */
char a[100];
strcpy(a,"reverse string");
/*make a copy of 'a', declared the same as a[]*/
char b[100];
strcpy(b,a);
streverse_a(b);
printf("a:%s, r:%s\n",a,b);
/*duplicate 'a'*/
char *rp = strdup(a);
streverse(rp);
printf("a:%s, r:%s\n",a,rp);
free(rp);
int ndx;
for( ndx=0; ndx<10; ++ndx ) {
/*make a copy of 's', declared the same as s[]*/
char b[100];
strcpy(b,s[ndx]);
streverse_a(b);
printf("s:%s, r:%s\n",s[ndx],b);
/*duplicate 's'*/
char *rp = strdup(s[ndx]);
streverse(rp);
printf("s:%s, r:%s\n",s[ndx],rp);
free(rp);
}
}
The last line in your code does nothing
string = line;
Parameters are passed by value, so if you change their value, that is only local to the function. Pointers are the value of the address of memory they are pointing to. If you want to modify the pointer that the function was passed, you need to take a pointer to that pointer.
Here is a short example of how you could do that.
void reverse (char **string) {
char line = malloc(strlen(*string) + 1);
//automatic arrays are deallocated once the function ends
//so line needs to be dynamically or statically allocated
// do something to line
*string = line;
}
The obvious issue with this is that you can initialize the string with static memory, then this method will replace the static memory with dynamic memory, and then you'll have to free the dynamic memory. There's nothing functionally wrong with that, it's just a bit dangerous, since accidentally freeing the string literal is illegal.
char *test = "hello";
reverse(test);
free(test); //this is pretty scary
Also, if test was allocated as dynamic memory, the pointer to it would be lost and then it would become a memory leak.

How to replace the last index of a string using C language?

The code below tries to increment the last index in a string, eg: if label = "1_1_9", find_next_label (label ) will return "1_1_10".
This works. However, I also want to alter the original label, increment it as well. eg: if label = "1_1_9", find_next_label(label) will return "1_1_10" and during this procedure, label also becomes "1_1_10".
This code below is unable to do this. The result from main() function shows that label is still "1_1_9".
Could anyone help find where the problem is?
char * find_next_lable(char * label)
{
int length = strlen(label);
char * last_index = label + length - 1;
int num = atoi(last_index);
num = num + 1;
char * next_lable = malloc(sizeof(label));
strncpy(next_label, label, length-1);
*(next_label + length - 1) = '\0';
sprintf(next_label, "%s%d", next_label, num);
label = next_label;
return label;
}
int main()
{
char * s = malloc(6);
strcpy(s, "1_1_9");
char * n = find_next_label(s);
printf("%s\n", s);
printf("%s\n", n);
return 0;
}
The last_index() and atoi() code block assumes that the final number is only one digit long; clearly this is not very general. You could search for the last underscore instead, and convert a number from the character following that. Use strrchr() to look for the last underscore.
Also you must think a lot about buffer sizes and overruns, you should probably make the function accept the available buffer size as an additional argument especially if you want to modify the input. If you want that, there's of course no point in allocating additional space either, just return the input.
If you don't need to create a new string you can just do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 20
int main()
{
char *s = malloc(MAX_LEN); /* You must have enough memory if the number of chars grows! */
char *n;
int i;
strcpy(s, "1_1_9");
printf("%s\n", s);
n = strrchr(s, '_'); /* find the last '_' */
n++; /* and move to the number */
i = atoi(n);
sprintf(n, "%d", i+1); /* write the new value instead of the old one */
printf("%s\n", s);
free(s);
return 0;
}
else you can have the function:
char * find_next_lable(char *label)
{
char *n, *next_lable = malloc(sizeof(MAX_LEN));
int i;
strcpy(next_lable, label);
n = strrchr(next_lable, '_');
n++;
i = atoi(n);
sprintf(n, "%d", i+1);
return next_lable;
}
The result from main() function shows that lable is still 1_1_9.
That's because you are not changing the dynamically allocated array pointed to by s in main. Instead, you allocate new memory in the function find_next_lable. Also,
sprintf(next_lable, "%s%d", next_lable, num);
won't work since %s conversion specifier means that sprintf will read from the buffer pointed to by next_lable till and including the terminating null byte.
You must allocate enough memory so as to contain the incremented integer part.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// make sure MAX is large enough to
// contain the modified string
#define MAX 20
void find_next_lable(char *label);
int main(void)
{
char *s = malloc(MAX);
strcpy(s, "1_1_90");
printf("%s\n", s);
find_next_lable(s);
printf("%s\n", s); // prints 1_1_91
free(s);
return 0;
}
void find_next_lable(char *label)
{
// strrchr returns a pointer to the last
// occurrence of the character _ in label
char *last_index = strrchr(label, '_');
if(last_index == NULL)
{
last_index = label;
}
else
{
last_index++;
}
int num = atoi(last_index);
num = num + 1;
sprintf(last_index, "%d", num);
}

Returning arrays and pointers in C?

I'm relatively a beginner in programming in C and am getting super confused with arrays and pointers.
Basically what I'm trying to do is extend a string that contains binary to the designated length len; (i.e. len=8 for num[]=101 would produce "00000101").
Can someone help me understand what's wrong with this?
const char * extendBinary(char num[], int len) {
char *number = &num;
int length = len;
int difference;
if(strlen(*num)<len) {
difference = len-strlen(num);
while(difference>0)
{
&number = strcat("0", &number);
difference--;
}
}
return number;
}
Your problems start with your specification. If I understand you correctly, you want to have a function where you pass an array of characters and a length. The size of your array of input characters will be between 1 and len? However, your function has no way of knowing what the size of your array num is. If you wanted this to work, you would need to define your function as
const char * extendBinary(char *num, size_t num_len, int len);
so that your function doesn't overrun your buffer pointed to by num. Note that I replaced char num[] with char *num as this is the common mechanism for passing a pointer. You cant pass pointers to arrays and then dereference that pointer and get back the original type (that includes its size) -- that's just one thing that C doesn't let you do, so just use a normal pointer and a separate size variable.
Finally, you'll have to deal with memory allocation unless you want a memory leak. Thus, you could simply say that whom ever calls extendBinary should free it's return value when done with it.
const char * extendBinary(char *num, size_t num_len, int len) {
char *ret = malloc(len + 1);
int i;
memset(ret, '0', len);
ret[len] = 0;
strncpy(&ret[len - num_len], num, num_len);
return ret;
}
int main(void) {
char arr[] = {'1', '0', '1'};
const char *formatted = extendBinary(arr, sizeof(arr), 8);
printf("%s\n", formatted);
free(formatted);
return 0;
}
this is wrong.
strcat("0", &number);
A weird way to fix you code would be this:
char temp[32] = {};
...
...
while(difference>0)
{
strncat(temp, "0", 31 - strlen(temp));
difference--;
}
strncat(temp, num, 31 - strlen(temp));
strncpy(num, temp, len);
Note, I am writing this code just to help you understand how strcat() works, there is much better ways to do what you are trying to do.
You cannot concatenate something to a const string, you must have entire control of what is happening into you code, and where your code is writing. Do you know where is the pointer to "0" in your source?
How do you set up num? If it's really an array of characters rather than a string, there's no requirement that it be null terminated, unless it's a global/static. If you set it up like so in a function:
char str[10];
str[0] = '1';
str[1] = '0';
str[2] = '1';
than your strlen will get whatever, depending upon whatever junk happens to be in num.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//case 1: for num[9]="101";
char *extendBinary1(char num[], int len) {
int num_len = strlen(num);
memmove(num + (len - num_len), num, num_len);
memset(num, '0', (len - num_len));
return num;
}
//case 2: for "101";//pointer to const char
char *extendBinary2(const char num[], int len) {
int num_len = strlen(num);
char *number = calloc(len + 1, sizeof(char));
memset(number, '0', (len - num_len));
return strcat(number, num);
}
int main(void){
char num[9] = "101";
char *number = extendBinary2("101", 8);//dynamic allocate
printf("%s\n", extendBinary1(num, 8));
printf("%s\n", number);//free(number);
return 0;
}

qsort segmentation fault

So I'm working on a program where the function reads in from stdio, and keeps reading in characters in chunks of n characters.
So far I've gotten it so that everything is stored in a character array called buffer. For the next step, I need to sort each chunk of n characters. For example the string cats/ndogs/n should be split as cats/n dogs/n if n =5, and then qsort() needs to alphabetize it. This is how I'm calling qsort():
qsort (buffer, (line-2)*n*(sizeof(char)),n,compare);
Where (line-2)*n*sizeof(char) gives the total number of items in the array buffer; 10 in this case.
This is my compare function:
int compare (const void * a, const void * b)
{
return (strcmp(*(char **)a, *(char **)b));
}
When I run this, however, I always get a seg fault in strcmp(). Any ideas why?
This is the loading code:
while (!feof(stdin))
{
for (i = 0; i < n; i++)
{
char l = getchar();
if (l != EOF)
{
if ((i == 0) && (line != 1))
{
success = (int *)realloc(buffer, line*n*(sizeof(char)));
}
buffer[(n*(line-1))+i] = l;
}
}
line = line + 1;
}
Silly question, but are your strings null terminated? You seem to only have a newline on the end.
Also, you probably only need "strcmp((char *)a, (char *)b)" as the extra *s look to be redundant to me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buffer[] ="333000222555111777888666999444";
int mycmp(void *l, void*r);
int main(void)
{
/* note: sizeof buffer is 31,
** but the integer division will round down
** , ignoring the extra nul-byte */
qsort(buffer, (sizeof buffer/3), 3, mycmp);
printf ("[%s]\n", buffer);
return 0;
}
int mycmp(void *l, void *r)
{
return memcmp(l,r,3);
}

Resources