Чистый СИ. Указатели.

cDLEON

Онанист РНРСlub
Хыхы))) Спасибо сделаем-с))
Я здесь что то вроде substr наколякал...
Тока не понятно каГ без malloc выделить память для строки...
Вот, то, что получилось, не работает конечно, но то, что я не понимаю отчётливо покажет...
PHP:
#include <stdio.h>

char *
substr(char *str,int start,int stop) {
	char tmp='\0';
	if(stop-start<=0) {
		return tmp;
	}
	char result[stop-start+1];

	int i=0,j=0;
	while(tmp=*str++) {
		if(i++<start) {
			continue;
		}
		result[j++]=tmp;
		if(i==stop) {
			break;
		}
	}
	result[j]='\0';
	return result;
}

int
main () {
	char *str="Asdddddddddddddd";
	printf("%s",substr(str,1,3));
	getch();
	return 0;
};
ЗЫ. У меня mingw компилятор стоит. Там есть маны...Сча будем искать прогу для чтения =))

-~{}~ 18.12.07 09:48:

ЗЫ.ЗЫ. Ещё один 2-ва вопроса возникло...
1) Можно ли чисто на указателях закинуть в результ нужные символы ? Т.е. без итератора j ?
2) Какую либу нужно подключить, что бы юзать malloc ?
 

fixxxer

К.О.
Партнер клуба
1) указатель это число, операции инкремента и декремента увеличивают/уменьшают его на sizeof типа, на который он указывает
2) stdlib.h, там где есть alloca.h достаточно его
3) открой для себя opennet.ru )
 

fixxxer

К.О.
Партнер клуба
ага. только нужно учитывать что это старое издание с доисторическим синтаксисом объявления функций, т.е.

int foo()
int a;
int b;
{ .. }

следует читать как int foo (int a, int b) { .. }
 

Pigmeich

Новичок
Автор оригинала: cDLEON
Pigmeich
Гыгы....Йа хател увеличить указатель на единичку.
Что бы на следующую итерацию указатель указывал уже на следующий символ.
В этом месте всё норм. 100%. Убираю tmp=*str; Всё работает как нужно. А вот присвоить текущий в итерации символ не получается. Потому как на операции присваивания моя программко и обваливается)
Да, не падает, но зачем разыменование писать?

-~{}~ 18.12.07 23:28:

Автор оригинала: cDLEON
-~{}~ 18.12.07 08:57:


Стоп. А почему увеличиваем не указатель на 1, а хз чо ?
И что в таком случае такое str ?
Я просто не могу до конца в логику этих указателей въехать...
Поэтому и мудрю)
Это как раз ты хз что пытаешься увеличить. Только длагодоря бубну ты нашел комбинацию в которой делается что надо, а не что ты хочешь.

Указатели реализуются простыми целымии, которые обозначают адрес в памяти. Соответсвенно str - это целое число, интерпретируемое как адрес памяти. И чтобы передвинуть его на 1 символ вперед увеличивают адрес памяти (C смотрит на тип указателя и автоматически прибаляет не 1, а размер (sizeof) переменной).

-~{}~ 18.12.07 23:37:

Автор оригинала: cDLEON
Хыхы))) Спасибо сделаем-с))
Я здесь что то вроде substr наколякал...
Тока не понятно каГ без malloc выделить память для строки...
Вот, то, что получилось, не работает конечно, но то, что я не понимаю отчётливо покажет...
PHP:
...
ЗЫ. У меня mingw компилятор стоит. Там есть маны...Сча будем искать прогу для чтения =))
Мы с одним опытным C-программером общались на одноименном IRC канале. Обсуждали аллокации в стеке. Обсуждали, обсуждали... а потом он убежал и прибежал с криком: "а я нашел баг в своей программе напианно 5 лет назад!".

Конструкция char[num] выделяет память в стеке процесса. Стек процесса освобождается по выходу из функции (переменная дальше функции не живет). Посколько ОС и компилятору лень чистить память - строку можно достать правиль, но можно с таким же успехом и достать мусор.
-~{}~ 18.12.07 09:48:

ЗЫ.ЗЫ. Ещё один 2-ва вопроса возникло...
1) Можно ли чисто на указателях закинуть в результ нужные символы ? Т.е. без итератора j ?
2) Какую либу нужно подключить, что бы юзать malloc ?
Без итератора ничего сделать нельзя :). Можно считерить и воспользоваться итерацией []: запись a - означает "обратиться к перменной по адресу a + b*sizeof(elem)".

2. malloc.h
 

cDLEON

Онанист РНРСlub
Кто-нить может подправить ф-ю, написанную мною ?
Либо хотя бы написать почему в моём случае...
Просто я обычно на примерах учиться привык.
Хочу все точки над Ы расставить)

-~{}~ 19.12.07 07:31:

ЗЫ. Тони, спасибо за ссылку, я как раз искал эту книгу...
Правда написана она слишком заковыристо (
Очень трудно вникать...
Вот переделал функцию немного...Теперь вообще падает при выполнении на операции присваивания...
PHP:
#include <stdio.h>
#include <stdlib.h>

char *
substr(char *str,int start,int stop) {
	char *tmp=" ";
	if(stop-start<=0) {
		return "";
	}
	//malloc(stop-start+1);
	char *result="aa";
	malloc(stop-start+1);
	int i=0,j=0;
	while(tmp=str++) {
		if(i++<start) {
			continue;
		}
		printf("%c %s\n",*tmp,result);
		//printf("%c\n",result[1]);
		result[j++]=*tmp;
		//result++;
		if(i==stop) {
			break;
		}
	}
	return result;
}

int
main () {
	char *str="Asdddddddddddddd";
	printf("%s",substr(str,1,3));
	getch();
	return 0;
};
 

fixxxer

К.О.
Партнер клуба
ох чо то у тебя страшное :)
пример говоришь. ладно в первый и последний раз показываю

как то так
PHP:
char *my_substr(char *str, unsigned int start, unsigned int stop)
{
    char *result, *from, *to;
    if (stop<start || !(result = malloc(stop-start+1))) return NULL;
    for (from=str+start, to=result; *from && from-str<=stop; ++to) 
        *to = *from++;
    *to = 0;
    return result;
}
ессно можно сделать и по другому, пока тут разберись
 

ys

отодвинутый новичок
cDLEON

Обычно, когда функция должна возвращать указатель на строку и что-то в ней пошло не так, принято возвращать NULL .

> char *tmp=" ";
Почему char *tmp определяется как указатель на строку из двух байт? (пробел и \0)?

> if(stop-start<=0)
Мммм. Проверкой:
if(start > stop && str) return NULL;
Мы можем убить больше зайцев: более наглядная проверка и, если у нас на входе пустой (NULL) указатель, то ничего не делаем.

Желательно, на входе уже знать длину полученной строки, ведь, если длина строки == 10, а start и stop равны 100 и 110, то это неправильно?

Итого, проверка меняется на:

char *tmp = NULL; /* tmp - просто указатель, которому НАДО в функции присвоить значение, NULL - это для красоты, в данном случае */

int lenstr;

if(str) return NULL;
lenstr = strlen(str);
if(start > stop && start > lenstr && stop > lenstr) return NULL;


Теперь, мы проверили все параметры.

Где будем мучаться со самой строкой?

Можем выделить память для новой строки или "корежить" полученную строку, которую получили в аргументе функции.

Можно выделить память и указать tmp смотреть на нее :)
tmp = malloc(start-stop +1);

Проверим, а дали ли нам эту память:
if (tmp == NULL)
return NULL;

Теперь, переносим ту часть строки, которая нам нужна в этот блок памяти:

memcpy(tmp, str+start, start-stop);

Затыкаем ее нуль-терминатором:

tmp[start-stop] = '\0'; /* Тут я уж не помню, вроде +1 не надо :) */


Все, вернем добро:

return tmp;


Rem: Не забываем освобождать память, которую вернула функция (если не NULL), когда она более не нужна, функцией free();
 

fixxxer

К.О.
Партнер клуба
> return "";

воооот! вот почему нельзя учиться на скриптовых языках типа php:)
как ты дальше поймешь надо ли делать free?
 

cDLEON

Онанист РНРСlub
Обьясни своими словами что делает этот код.
Эээ. Присваивает указателю tmp адрес str, после чего увеличивает его итератор на 1.
memcpy(tmp, str+start, start-stop);
Вспомогательных ф-й мне не нужно. У меня задача не решить эту задачу, а научиться использывать указатели )

ЗЫ. Ключевое нерабочее место было - не правильное выделение памяти)) А так ф-я моя пашеД )))
Ура))

-~{}~ 19.12.07 19:48:

Кстати. Ещё вопрос. Вот если задать stop большим интом, а строка будет меньше, получится так, что кусок выделяемой памяти как бы выделен, но не используется....
Как с этим бароться ?
ЗЫ. strlen не предлагать ))
 

ys

отодвинутый новичок
cDLEON

Какой в опу инт, ну думай об этом, int думает за тебя :)

>Ключевое нерабочее место было - не правильное выделение памяти

Если учесть, что его небыло - то да.

>Кстати. Ещё вопрос. ........
Т.е., вы считаете, что в "большом" int, например, 100, больше, чем в "маленьком :)

> ЗЫ. strlen не предлагать.

Ну напиши сам. :)
 

Pigmeich

Новичок
Эээ. Присваивает указателю tmp адрес str, после чего увеличивает его итератор на 1.
Во-первых можно просто ++tmp делать.

во вторых при чем тут условие while?

Кстати. Ещё вопрос. Вот если задать stop большим интом, а строка будет меньше, получится так, что кусок выделяемой памяти как бы выделен, но не используется....
Как с этим бароться ?
ЗЫ. strlen не предлагать ))
Останавливаться если копируемая строчка кончилась. Ну и выдавать предупреждение по вкусу.
 

cDLEON

Онанист РНРСlub
Т.е., вы считаете, что в "большом" int, например, 100, больше, чем в "маленьком
Пожалуйсто, не делайте с меня дурачка.
Я говорил про malloc - именно туда поступает аттрибут стоп.
Останавливаться если копируемая строчка кончилась. Ну и выдавать предупреждение по вкусу.
Предупреждение - предупреждением) А память то не вернуть )) Нужно будет сегодня поиграться с фри....

-~{}~ 20.12.07 09:21:

во вторых при чем тут условие while?
Хех...Ну повторять пока tmp не равен NULL
 

Pigmeich

Новичок
cDLEON
Адреса с нулевым номером не существует (одна из аксиом при работе с памятью).

Значит while(1)?
 

cDLEON

Онанист РНРСlub
Pigmeich
Ну не знаю. У меня всё работает) Совпадение? )
 

fixxxer

К.О.
Партнер клуба
работает потому что условие всегда истинно, а выход у тебя по break ниже
 

cDLEON

Онанист РНРСlub
о_О. Внатури. Фсйо. Вопросов по указателям больше не имею)
Приступаю к выполнению домашнего задания =))

-~{}~ 11.01.08 15:14:

ваще вот тебе 2 классические задачки

везде использовать только указатели

сделаешь - считай разобрался

1.
#include <stdio.h>
int main(int argc, char **argv)
{
...
}

вывести первые буквы входных параметров (пример: ./a.out this is a test должно вывести tiat)

2.
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv)
{
assert(2==argc);
printf("%s\n",str_reverse(argv[1]));
return 0;
}


реализовать ф-ю str_reverse которая переворачивает строку на месте (не выделяя доп. память).
В опсчем нашёл время опять...
Взялся за СИ :D За пол часеГа решил все 2 :D
PHP:
#include <stdio.h>
#include <stdlib.h>

char *
substr(char *str,int start,int stop) {
	char tmp;
	if(stop-start<=0) {
		return NULL;
	}
	//malloc(stop-start+1);
	char *result;
	if(!(result=malloc(stop-start))) {
		return NULL;
	}
	int j=0;
	if(!(str=str+start)) {
		return NULL;
	}
	while(tmp=*str++) {
		printf("%i\n",start);
		result[j++]=tmp;
		if(start==stop) {
			break;
		}
		start++;
	}
	result[j]='\0';
	return result;
}

int 
strlen(char *str) {
	int len=0;
	while(*str++) {
		len++;
	}
	return len;
}

char *
str_reverse (char *str) {
	int i=0,len=strlen(str)-1,cur;
	char tmp;
	for(i=0;i<len;i++) {
		cur=len-i;
		//Дошли до середины
		if(i>=cur) {
			break;
		}
		tmp=str[i];
		str[i]=str[cur];
		str[cur]=tmp;
		//printf("%i\n",i);
	}
	return str;
}

int
main (int argc, char **argv) {
	char *str="Asdfghjkl";
	printf("Substr: %s \n",substr(str,3,10000));
	char *str2;
	str2=malloc(argc);
	int i;
	for(i=0;i<argc;i++) {
		str2[i]=*argv[i];
	}
	printf("Argv: %s\n",str2);
	printf("Str_reverse %s\n",str_reverse(argv[0]));
	getch();
	return 0;
};
ЗЫ. Если можно, скиньте свои более "профессиональные " варианты. Хочу немного с хитростями этого языка ознакомиться
 

Pigmeich

Новичок
cDLEON
более професиональные в string.h должны валяться.

От себя посоветую всегда инициализировать переменные при объявлении. И в str_reverse крутить цикл до len/2 :).
 
Сверху